Compare commits

..

28 Commits

Author SHA1 Message Date
klaus 772005910c 시리즈 콘텐츠 리스트
- 정렬(최신순, 등록순) 추가
2024-09-10 16:27:32 +09:00
klaus 1f36d8ef25 커뮤니티 댓글, 팬토크, 콘텐츠 댓글
- 프로필 이미지 터치시 차단, 신고가 가능한 유저 프로필 표시
2024-09-07 01:28:50 +09:00
klaus 1b8d65c3ea 라이브 방 - 유저 차단 팝업
- 리스너가 차단할 때 팝업 문구 수정
2024-09-05 20:01:16 +09:00
klaus 07df9ced75 PG 결제 - 카카오페이 결제
- 구매자 정보 추가
2024-09-05 16:07:27 +09:00
klaus 9dfd73b090 라이브 방
- 차단한 유저의 채팅이 보이지 않도록 수정
2024-09-04 22:29:55 +09:00
klaus 0ebb34a2df 차단 리스트 페이지 추가 2024-09-04 12:31:32 +09:00
klaus 6869cd62ea 팔로잉 리스트
- 팔로우 한 채널이 없는 경우 '팔로우 중인 채널이 없습니다.' 표시
2024-09-02 18:01:18 +09:00
klaus b7b73bb409 마이 페이지
- 팔로잉 리스트 버튼 추가
2024-09-02 17:47:28 +09:00
klaus 7bf3728cf9 커뮤니티 댓글
- 비밀 댓글 체크박스 보이지 않도록 수정
2024-09-02 14:32:12 +09:00
klaus cc01312ae5 콘텐츠 댓글
- 일반 댓글의 닉네임이 잘리는 버그 수정
2024-08-30 19:00:35 +09:00
klaus cf94615e71 라이브 방 비밀후원, 콘텐츠 비밀댓글
- 체크박스 네모로 변경
2024-08-30 18:17:06 +09:00
klaus 51cb36b2e6 라이브 방
- 후원현황과 후원하기 버튼 순서 변경
2024-08-30 15:07:35 +09:00
klaus 345df7a7b7 콘텐츠 댓글 리스트
- 비밀댓글은 닉네임 옆에 '비밀댓글' 마크 추가
2024-08-30 15:03:46 +09:00
klaus 4961727237 콘텐츠 댓글 리스트
- 댓글이 없을 때 유료 콘텐츠를 구매한 사람이 비밀댓글을 등록할 수 있는 기능 추가
2024-08-30 14:42:20 +09:00
klaus 6640130ef9 콘텐츠 상세
- 댓글이 없을 때 유료 콘텐츠를 구매한 사람이 비밀댓글을 등록할 수 있는 기능 추가
2024-08-30 13:11:56 +09:00
klaus e38778d9e7 캔 결제수단 추가
- 카카오페이
2024-08-27 19:33:58 +09:00
klaus 63e9b705a9 스플래시 2024/09 2024-08-27 00:06:41 +09:00
klaus 38864ca666 포그라운드 서비스 시작시 foregroundServiceTypes 추가 2024-08-26 15:24:45 +09:00
klaus adab4aee48 라이브 후원
- 비밀 후원 기능 추가
2024-08-24 00:37:53 +09:00
klaus 3bad5c5e55 콘텐츠 메인
- 우측 최상단에 콘텐츠 보관함, 알람 아이콘 추가
- 배너와 추천 시리즈 순서 변경
2024-08-21 21:49:42 +09:00
klaus 7607c10bdc @Keep 어노테이션을 추가하여 난독화에서 제외되도록 수정 2024-08-21 20:22:39 +09:00
klaus 4349f2bd3a targetSdk 34로 변경
커스텀 액션에서 패키지를 명시
2024-08-21 12:44:51 +09:00
klaus 62abd3c900 라이브
- 후원 메시지, 룰렛 결과 모든 유저에게 보이도록 수정
2024-08-14 18:34:39 +09:00
klaus 63193c82a1 versionCode 96, versionName 1.15.1 2024-08-12 17:22:45 +09:00
klaus 6431577bf1 알람
- 날짜 선택 추가
2024-08-12 16:58:23 +09:00
klaus b56a0d58bf 알람
- 볼륨 설정 추가
2024-08-09 15:22:17 +09:00
klaus 00774739ed 팬토크
- 응원글 등록/수정/삭제시 전체 데이터를 지우고 다시 조회하도록 수정
2024-08-08 02:19:26 +09:00
klaus b98cc8ed79 크리에이터 커뮤니티 오디오 녹음
- 파일명 수정
2024-08-08 02:02:21 +09:00
211 changed files with 2849 additions and 321 deletions

View File

@ -0,0 +1,123 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -4,6 +4,14 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-08-26T10:43:24.248064Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/klaus/.android/avd/Pixel_8_Pro_API_34.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

318
.idea/other.xml Normal file
View File

@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="direct_access_persist.xml">
<option name="deviceSelectionList">
<list>
<PersistentDeviceSelectionData>
<option name="api" value="27" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="F01L" />
<option name="id" value="F01L" />
<option name="manufacturer" value="FUJITSU" />
<option name="name" value="F-01L" />
<option name="screenDensity" value="360" />
<option name="screenX" value="720" />
<option name="screenY" value="1280" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="28" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="SH-01L" />
<option name="id" value="SH-01L" />
<option name="manufacturer" value="SHARP" />
<option name="name" value="AQUOS sense2 SH-01L" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />
<option name="codename" value="a51" />
<option name="id" value="a51" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy A51" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="akita" />
<option name="id" value="akita" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="b0q" />
<option name="id" value="b0q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S22 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="32" />
<option name="brand" value="google" />
<option name="codename" value="bluejay" />
<option name="id" value="bluejay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="caiman" />
<option name="id" value="caiman" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro" />
<option name="screenDensity" value="360" />
<option name="screenX" value="960" />
<option name="screenY" value="2142" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="comet" />
<option name="id" value="comet" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="29" />
<option name="brand" value="samsung" />
<option name="codename" value="crownqlteue" />
<option name="id" value="crownqlteue" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Note9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2220" />
<option name="screenY" value="1080" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="dm3q" />
<option name="id" value="dm3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S23 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="e1q" />
<option name="id" value="e1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S24" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix_camera" />
<option name="id" value="felix_camera" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold (Camera-enabled)" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="gts8uwifi" />
<option name="id" value="gts8uwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S8 Ultra" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1848" />
<option name="screenY" value="2960" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="husky" />
<option name="id" value="husky" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8 Pro" />
<option name="screenDensity" value="390" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="motorola" />
<option name="codename" value="java" />
<option name="id" value="java" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="G20" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="komodo" />
<option name="id" value="komodo" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro XL" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="lynx" />
<option name="id" value="lynx" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="google" />
<option name="codename" value="oriole" />
<option name="id" value="oriole" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="panther" />
<option name="id" value="panther" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q5q" />
<option name="id" value="q5q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold5" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1812" />
<option name="screenY" value="2176" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="r11" />
<option name="id" value="r11" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Watch" />
<option name="screenDensity" value="320" />
<option name="screenX" value="384" />
<option name="screenY" value="384" />
<option name="type" value="WEAR_OS" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="redfin" />
<option name="id" value="redfin" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 5" />
<option name="screenDensity" value="440" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="shiba" />
<option name="id" value="shiba" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="tangorpro" />
<option name="id" value="tangorpro" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Tablet" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="tokay" />
<option name="id" value="tokay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="29" />
<option name="brand" value="samsung" />
<option name="codename" value="x1q" />
<option name="id" value="x1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S20" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1440" />
<option name="screenY" value="3200" />
</PersistentDeviceSelectionData>
</list>
</option>
</component>
</project>

View File

@ -14,7 +14,7 @@ plugins {
android { android {
namespace 'kr.co.vividnext.sodalive' namespace 'kr.co.vividnext.sodalive'
compileSdk 33 compileSdk 34
viewBinding { viewBinding {
enabled true enabled true
@ -24,11 +24,6 @@ android {
dataBinding true dataBinding true
} }
lintOptions {
checkDependencies true
checkReleaseBuilds false
}
dependenciesInfo { dependenciesInfo {
// Disables dependency metadata when building APKs. // Disables dependency metadata when building APKs.
includeInApk = false includeInApk = false
@ -39,9 +34,9 @@ android {
defaultConfig { defaultConfig {
applicationId "kr.co.vividnext.sodalive" applicationId "kr.co.vividnext.sodalive"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 34
versionCode 92 versionCode 104
versionName "1.14.1" versionName "1.17.0"
} }
buildTypes { buildTypes {
@ -57,7 +52,8 @@ android {
} }
debug { debug {
minifyEnabled false minifyEnabled true
debuggable true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
applicationIdSuffix '.debug' applicationIdSuffix '.debug'
@ -75,6 +71,10 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString() jvmTarget = JavaVersion.VERSION_17.toString()
} }
lint {
checkDependencies true
checkReleaseBuilds false
}
} }
dependencies { dependencies {
@ -137,7 +137,7 @@ dependencies {
implementation 'com.google.firebase:firebase-config-ktx' implementation 'com.google.firebase:firebase-config-ktx'
// bootpay // bootpay
implementation "io.github.bootpay:android:4.3.4" implementation "io.github.bootpay:android:4.4.3"
// agora // agora
implementation "io.agora.rtc:voice-sdk:4.2.6" implementation "io.agora.rtc:voice-sdk:4.2.6"

View File

@ -222,9 +222,10 @@
-keep class kr.co.bootpay.core.** { *; } -keep class kr.co.bootpay.core.** { *; }
-keep class kr.co.pointclick.sdk.offerwall.core.consts.** {*;} -keep class retrofit2.** { *; }
-keep interface kr.co.pointclick.sdk.offerwall.core.consts.** {*;}
-keep class kr.co.pointclick.sdk.offerwall.core.models.** {*;} -keep class com.google.gson.** { *; }
-keep interface kr.co.pointclick.sdk.offerwall.core.models.** {*;} -keep class sun.misc.** { *; }
-keep class kr.co.pointclick.sdk.offerwall.core.PointClickAd {*;}
-keep class kr.co.pointclick.sdk.offerwall.core.events.PackageReceiver {*;} # @Keep 애노테이션이 붙은 클래스, 메서드, 필드를 보호
-keep @androidx.annotation.Keep class * { *; }

View File

@ -4,6 +4,8 @@
<uses-permission android:name="com.android.vending.BILLING" /> <uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission <uses-permission
@ -148,6 +150,7 @@
<activity android:name=".mypage.alarm.AlarmListActivity" /> <activity android:name=".mypage.alarm.AlarmListActivity" />
<activity android:name=".mypage.alarm.AddAlarmActivity" /> <activity android:name=".mypage.alarm.AddAlarmActivity" />
<activity android:name=".mypage.alarm.select_audio_content.AlarmSelectAudioContentActivity" /> <activity android:name=".mypage.alarm.select_audio_content.AlarmSelectAudioContentActivity" />
<activity android:name=".mypage.block.BlockMemberActivity" />
<activity <activity
android:name=".mypage.alarm.AlarmActivity" android:name=".mypage.alarm.AlarmActivity"
android:exported="true" android:exported="true"

View File

@ -172,13 +172,14 @@ class Agora(
fun sendRawMessageToPeer( fun sendRawMessageToPeer(
receiverUid: String, receiverUid: String,
requestType: LiveRoomRequestType, requestType: LiveRoomRequestType? = null,
rawMessage: ByteArray? = null,
onSuccess: () -> Unit onSuccess: () -> Unit
) { ) {
val option = SendMessageOptions() val option = SendMessageOptions()
val message = rtmClient!!.createMessage() val message = rtmClient!!.createMessage()
message.rawMessage = requestType.toString().toByteArray() message.rawMessage = rawMessage ?: requestType.toString().toByteArray()
rtmClient!!.sendMessageToPeer( rtmClient!!.sendMessageToPeer(
receiverUid, receiverUid,

View File

@ -1,13 +1,16 @@
package kr.co.vividnext.sodalive.audio_content package kr.co.vividnext.sodalive.audio_content
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import java.util.TimeZone import java.util.TimeZone
@Keep
data class AddAllPlaybackTrackingRequest( data class AddAllPlaybackTrackingRequest(
@SerializedName("timezone") val timezone: String = TimeZone.getDefault().id, @SerializedName("timezone") val timezone: String = TimeZone.getDefault().id,
@SerializedName("trackingDataList") val trackingDataList: List<PlaybackTrackingData> @SerializedName("trackingDataList") val trackingDataList: List<PlaybackTrackingData>
) )
@Keep
data class PlaybackTrackingData( data class PlaybackTrackingData(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("playDateTime") val playDateTime: String, @SerializedName("playDateTime") val playDateTime: String,

View File

@ -6,10 +6,10 @@ import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.AudioAttributes import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer import android.media.MediaPlayer
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
@ -52,6 +52,7 @@ class AudioContentPlayService :
putExtra(Constants.EXTRA_AUDIO_CONTENT_PROGRESS, mediaPlayer.currentPosition) putExtra(Constants.EXTRA_AUDIO_CONTENT_PROGRESS, mediaPlayer.currentPosition)
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId) putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
} }
intent.setPackage(packageName)
sendBroadcast(intent) sendBroadcast(intent)
handler.postDelayed(this, 1000) handler.postDelayed(this, 1000)
} }
@ -65,6 +66,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_CHANGE_UI, Constants.EXTRA_AUDIO_CONTENT_CHANGE_UI,
true true
@ -102,6 +104,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_SHOWING, Constants.EXTRA_AUDIO_CONTENT_SHOWING,
true true
@ -137,6 +140,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_SHOWING, Constants.EXTRA_AUDIO_CONTENT_SHOWING,
false false
@ -206,6 +210,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION, Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION,
MusicAction.PAUSE MusicAction.PAUSE
@ -221,6 +226,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION, Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION,
MusicAction.PLAY MusicAction.PLAY
@ -255,6 +261,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_LOADING, Constants.EXTRA_AUDIO_CONTENT_LOADING,
true true
@ -318,6 +325,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_CHANGE_UI, Constants.EXTRA_AUDIO_CONTENT_CHANGE_UI,
true true
@ -342,6 +350,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_PLAYING, Constants.EXTRA_AUDIO_CONTENT_PLAYING,
this@AudioContentPlayService.isPlaying this@AudioContentPlayService.isPlaying
@ -380,6 +389,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION, Constants.EXTRA_AUDIO_CONTENT_NEXT_ACTION,
MusicAction.PLAY MusicAction.PLAY
@ -405,6 +415,7 @@ class AudioContentPlayService :
sendBroadcast( sendBroadcast(
Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER) Intent(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
.apply { .apply {
setPackage(packageName)
putExtra( putExtra(
Constants.EXTRA_AUDIO_CONTENT_PLAYING, Constants.EXTRA_AUDIO_CONTENT_PLAYING,
false false
@ -500,7 +511,16 @@ class AudioContentPlayService :
.setShowActionsInCompactView(0, 1) .setShowActionsInCompactView(0, 1)
) )
startForeground(1, notificationBuilder.build()) val notification = notificationBuilder.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
1,
notification,
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
)
} else {
startForeground(1, notification)
}
} }
override fun onLoadCleared(placeholder: Drawable?) { override fun onLoadCleared(placeholder: Drawable?) {

View File

@ -1,5 +1,6 @@
package kr.co.vividnext.sodalive.audio_content package kr.co.vividnext.sodalive.audio_content
import androidx.annotation.Keep
import io.objectbox.annotation.Entity import io.objectbox.annotation.Entity
import io.objectbox.annotation.Id import io.objectbox.annotation.Id
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -7,6 +8,7 @@ import java.util.Date
import java.util.Locale import java.util.Locale
@Entity @Entity
@Keep
data class PlaybackTracking( data class PlaybackTracking(
@Id @Id
var id: Long = 0, var id: Long = 0,

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.audio_content.all package kr.co.vividnext.sodalive.audio_content.all
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
@Keep
data class GetNewContentAllResponse( data class GetNewContentAllResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentMainItem> @SerializedName("items") val items: List<GetAudioContentMainItem>

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.audio_content.all.by_theme package kr.co.vividnext.sodalive.audio_content.all.by_theme
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
@Keep
data class GetContentByThemeResponse( data class GetContentByThemeResponse(
@SerializedName("theme") val theme: String, @SerializedName("theme") val theme: String,
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.category package kr.co.vividnext.sodalive.audio_content.category
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetCategoryListResponse( data class GetCategoryListResponse(
@SerializedName("categoryId") val categoryId: Long, @SerializedName("categoryId") val categoryId: Long,
@SerializedName("category") val category: String @SerializedName("category") val category: String

View File

@ -9,6 +9,7 @@ import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load import coil.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import com.orhanobut.logger.Logger
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentBinding import kr.co.vividnext.sodalive.databinding.ItemAudioContentCommentBinding
@ -19,7 +20,8 @@ class AudioContentCommentAdapter(
private val creatorId: Long, private val creatorId: Long,
private val modifyComment: (Long, String) -> Unit, private val modifyComment: (Long, String) -> Unit,
private val onClickDelete: (Long) -> Unit, private val onClickDelete: (Long) -> Unit,
private val onItemClick: (GetAudioContentCommentListItem) -> Unit private val onItemClick: (GetAudioContentCommentListItem) -> Unit,
private val onClickProfile: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentCommentAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AudioContentCommentAdapter.ViewHolder>() {
var items = mutableSetOf<GetAudioContentCommentListItem>() var items = mutableSetOf<GetAudioContentCommentListItem>()
@ -30,12 +32,24 @@ class AudioContentCommentAdapter(
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetAudioContentCommentListItem) { fun bind(item: GetAudioContentCommentListItem) {
binding.tvSecret.visibility = if (item.isSecret) {
View.VISIBLE
} else {
View.GONE
}
binding.ivCommentProfile.load(item.profileUrl) { binding.ivCommentProfile.load(item.profileUrl) {
crossfade(true) crossfade(true)
placeholder(R.drawable.bg_placeholder) placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation()) transformations(CircleCropTransformation())
} }
binding.ivCommentProfile.setOnClickListener {
if (SharedPreferenceManager.userId != item.writerId) {
onClickProfile(item.writerId)
}
}
val tvCommentLayoutParams = binding.tvComment.layoutParams as LinearLayout.LayoutParams val tvCommentLayoutParams = binding.tvComment.layoutParams as LinearLayout.LayoutParams
val can = item.donationCan val can = item.donationCan
if (can > 0) { if (can > 0) {

View File

@ -14,7 +14,8 @@ import kr.co.vividnext.sodalive.databinding.DialogAudioContentCommentBinding
class AudioContentCommentFragment( class AudioContentCommentFragment(
private val creatorId: Long, private val creatorId: Long,
private val audioContentId: Long private val audioContentId: Long,
private val isShowSecret: Boolean
) : BottomSheetDialogFragment() { ) : BottomSheetDialogFragment() {
private lateinit var binding: DialogAudioContentCommentBinding private lateinit var binding: DialogAudioContentCommentBinding
@ -50,7 +51,8 @@ class AudioContentCommentFragment(
val commentListFragmentTag = "COMMENT_LIST_FRAGMENT" val commentListFragmentTag = "COMMENT_LIST_FRAGMENT"
val commentListFragment = AudioContentCommentListFragment.newInstance( val commentListFragment = AudioContentCommentListFragment.newInstance(
creatorId = creatorId, creatorId = creatorId,
audioContentId = audioContentId audioContentId = audioContentId,
isShowSecret = isShowSecret
) )
val fragmentTransaction = childFragmentManager.beginTransaction() val fragmentTransaction = childFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.fl_container, commentListFragment, commentListFragmentTag) fragmentTransaction.add(R.id.fl_container, commentListFragment, commentListFragmentTag)

View File

@ -20,6 +20,7 @@ import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -35,6 +36,7 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
private var creatorId: Long = 0 private var creatorId: Long = 0
private var audioContentId: Long = 0 private var audioContentId: Long = 0
private var isShowSecret: Boolean = false
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -43,6 +45,7 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
): View? { ): View? {
creatorId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID) ?: 0 creatorId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID) ?: 0
audioContentId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID) ?: 0 audioContentId = arguments?.getLong(Constants.EXTRA_AUDIO_CONTENT_ID) ?: 0
isShowSecret = arguments?.getBoolean(Constants.EXTRA_IS_SHOW_SECRET) ?: false
return super.onCreateView(inflater, container, savedInstanceState) return super.onCreateView(inflater, container, savedInstanceState)
} }
@ -73,8 +76,20 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
binding.ivCommentSend.setOnClickListener { binding.ivCommentSend.setOnClickListener {
hideKeyboard() hideKeyboard()
val comment = binding.etComment.text.toString() val comment = binding.etComment.text.toString()
val isSecret = binding.tvSecret.isSelected
viewModel.registerComment(audioContentId, comment, isSecret)
binding.etComment.setText("") binding.etComment.setText("")
viewModel.registerComment(audioContentId, comment) binding.tvSecret.isSelected = false
}
if (isShowSecret) {
binding.tvSecret.visibility = View.VISIBLE
binding.tvSecret.setOnClickListener {
binding.tvSecret.isSelected = !binding.tvSecret.isSelected
}
} else {
binding.tvSecret.visibility = View.GONE
} }
adapter = AudioContentCommentAdapter( adapter = AudioContentCommentAdapter(
@ -107,6 +122,14 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
}, },
onItemClick = { onItemClick = {
(parentFragment as AudioContentCommentFragment).onClickComment(it) (parentFragment as AudioContentCommentFragment).onClickComment(it)
},
onClickProfile = {
MemberProfileDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
memberId = it,
screenWidth = screenWidth
).show()
} }
) )
@ -202,10 +225,15 @@ class AudioContentCommentListFragment : BaseFragment<FragmentAudioContentComment
} }
companion object { companion object {
fun newInstance(creatorId: Long, audioContentId: Long): AudioContentCommentListFragment { fun newInstance(
creatorId: Long,
audioContentId: Long,
isShowSecret: Boolean
): AudioContentCommentListFragment {
val args = Bundle() val args = Bundle()
args.putLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID, creatorId) args.putLong(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID, creatorId)
args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId) args.putLong(Constants.EXTRA_AUDIO_CONTENT_ID, audioContentId)
args.putBoolean(Constants.EXTRA_IS_SHOW_SECRET, isShowSecret)
val fragment = AudioContentCommentListFragment() val fragment = AudioContentCommentListFragment()
fragment.arguments = args fragment.arguments = args

View File

@ -84,7 +84,7 @@ class AudioContentCommentListViewModel(
} }
} }
fun registerComment(contentId: Long, comment: String) { fun registerComment(contentId: Long, comment: String, isSecret: Boolean) {
if (!_isLoading.value!!) { if (!_isLoading.value!!) {
_isLoading.value = true _isLoading.value = true
} }
@ -93,6 +93,7 @@ class AudioContentCommentListViewModel(
repository.registerComment( repository.registerComment(
contentId = contentId, contentId = contentId,
comment = comment, comment = comment,
isSecret = isSecret,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View File

@ -8,12 +8,14 @@ class AudioContentCommentRepository(private val api: AudioContentApi) {
contentId: Long, contentId: Long,
comment: String, comment: String,
parentId: Long? = null, parentId: Long? = null,
isSecret: Boolean = false,
token: String token: String
) = api.registerComment( ) = api.registerComment(
request = RegisterAudioContentCommentRequest( request = RegisterAudioContentCommentRequest(
comment = comment, comment = comment,
contentId = contentId, contentId = contentId,
parentId = parentId parentId = parentId,
isSecret = isSecret
), ),
authHeader = token authHeader = token
) )

View File

@ -1,21 +1,25 @@
package kr.co.vividnext.sodalive.audio_content.comment package kr.co.vividnext.sodalive.audio_content.comment
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Keep
data class GetAudioContentCommentListResponse( data class GetAudioContentCommentListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentCommentListItem> @SerializedName("items") val items: List<GetAudioContentCommentListItem>
) )
@Parcelize @Parcelize
@Keep
data class GetAudioContentCommentListItem( data class GetAudioContentCommentListItem(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("writerId") val writerId: Long, @SerializedName("writerId") val writerId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@SerializedName("comment") val comment: String, @SerializedName("comment") val comment: String,
@SerializedName("isSecret") val isSecret: Boolean,
@SerializedName("donationCan") val donationCan: Int, @SerializedName("donationCan") val donationCan: Int,
@SerializedName("date") val date: String, @SerializedName("date") val date: String,
@SerializedName("replyCount") val replyCount: Int @SerializedName("replyCount") val replyCount: Int

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.comment package kr.co.vividnext.sodalive.audio_content.comment
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class ModifyCommentRequest( data class ModifyCommentRequest(
@SerializedName("commentId") val commentId: Long, @SerializedName("commentId") val commentId: Long,
@SerializedName("comment") var comment: String? = null, @SerializedName("comment") var comment: String? = null,

View File

@ -1,9 +1,12 @@
package kr.co.vividnext.sodalive.audio_content.comment package kr.co.vividnext.sodalive.audio_content.comment
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class RegisterAudioContentCommentRequest( data class RegisterAudioContentCommentRequest(
@SerializedName("comment") val comment: String, @SerializedName("comment") val comment: String,
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("parentId") val parentId: Long? @SerializedName("parentId") val parentId: Long?,
@SerializedName("isSecret") val isSecret: Boolean
) )

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.audio_content.curation package kr.co.vividnext.sodalive.audio_content.curation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
@Keep
data class GetCurationContentResponse( data class GetCurationContentResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentMainItem> @SerializedName("items") val items: List<GetAudioContentMainItem>

View File

@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.audio_content.detail
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.Service
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -9,8 +10,11 @@ import android.content.IntentFilter
import android.graphics.Rect import android.graphics.Rect
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast import android.widget.Toast
@ -65,6 +69,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
private val audioContentReceiver = AudioContentReceiver() private val audioContentReceiver = AudioContentReceiver()
private var creatorId: Long = 0 private var creatorId: Long = 0
private val handler = Handler(Looper.getMainLooper())
private var refresh = false private var refresh = false
private var title = "" private var title = ""
@ -72,6 +77,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent> private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
private lateinit var audioContent: GetAudioContentDetailResponse private lateinit var audioContent: GetAudioContentDetailResponse
private lateinit var orderType: OrderType private lateinit var orderType: OrderType
private lateinit var imm: InputMethodManager
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
@ -92,6 +98,8 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
audioContentId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0) audioContentId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
imm = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
if (audioContentId <= 0) { if (audioContentId <= 0) {
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show() Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
finish() finish()
@ -271,7 +279,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
val dialog = LiveRoomDonationDialog( val dialog = LiveRoomDonationDialog(
this, this,
LayoutInflater.from(this) LayoutInflater.from(this)
) { can, message -> ) { can, message, _ ->
if (can <= 0) { if (can <= 0) {
showToast("1캔 이상 후원하실 수 있습니다.") showToast("1캔 이상 후원하실 수 있습니다.")
} else if (message.isBlank()) { } else if (message.isBlank()) {
@ -469,8 +477,13 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
binding.tvCommentText.text = response.commentList[0].comment binding.tvCommentText.text = response.commentList[0].comment
binding.tvCommentText.visibility = View.VISIBLE binding.tvCommentText.visibility = View.VISIBLE
binding.rlInputComment.visibility = View.GONE binding.rlInputComment.visibility = View.GONE
binding.tvSecret.visibility = View.GONE
binding.llComment.setOnClickListener { showCommentBottomSheetDialog() } binding.llComment.setOnClickListener {
showCommentBottomSheetDialog(
isShowSecret = response.existOrdered
)
}
} else { } else {
binding.tvCommentText.visibility = View.GONE binding.tvCommentText.visibility = View.GONE
binding.rlInputComment.visibility = View.VISIBLE binding.rlInputComment.visibility = View.VISIBLE
@ -481,9 +494,22 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
binding.ivCommentSend.setOnClickListener { binding.ivCommentSend.setOnClickListener {
hideKeyboard()
val comment = binding.etComment.text.toString() val comment = binding.etComment.text.toString()
val isSecret = binding.tvSecret.isSelected
viewModel.registerComment(audioContentId, comment, isSecret)
binding.etComment.setText("") binding.etComment.setText("")
viewModel.registerComment(audioContentId, comment) binding.tvSecret.isSelected = false
}
if (response.existOrdered) {
binding.tvSecret.visibility = View.VISIBLE
binding.tvSecret.setOnClickListener {
binding.tvSecret.isSelected = !binding.tvSecret.isSelected
}
} else {
binding.tvSecret.visibility = View.GONE
} }
binding.llComment.setOnClickListener {} binding.llComment.setOnClickListener {}
@ -494,10 +520,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
} }
private fun showCommentBottomSheetDialog() { private fun showCommentBottomSheetDialog(isShowSecret: Boolean) {
val dialog = AudioContentCommentFragment( val dialog = AudioContentCommentFragment(
creatorId = creatorId, creatorId = creatorId,
audioContentId = audioContentId audioContentId = audioContentId,
isShowSecret = isShowSecret
) )
dialog.show( dialog.show(
supportFragmentManager, supportFragmentManager,
@ -919,6 +946,15 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
} }
private fun hideKeyboard() {
handler.postDelayed({
imm.hideSoftInputFromWindow(
window.decorView.applicationWindowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
}, 100)
}
inner class AudioContentReceiver : BroadcastReceiver() { inner class AudioContentReceiver : BroadcastReceiver() {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {

View File

@ -254,7 +254,7 @@ class AudioContentDetailViewModel(
) )
} }
fun registerComment(audioContentId: Long, comment: String) { fun registerComment(audioContentId: Long, comment: String, isSecret: Boolean) {
if (!isLoading.value!!) { if (!isLoading.value!!) {
isLoading.value = true isLoading.value = true
} }
@ -263,6 +263,7 @@ class AudioContentDetailViewModel(
commentRepository.registerComment( commentRepository.registerComment(
contentId = audioContentId, contentId = audioContentId,
comment = comment, comment = comment,
isSecret = isSecret,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View File

@ -1,9 +1,11 @@
package kr.co.vividnext.sodalive.audio_content.detail package kr.co.vividnext.sodalive.audio_content.detail
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListItem import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListItem
import kr.co.vividnext.sodalive.audio_content.order.OrderType import kr.co.vividnext.sodalive.audio_content.order.OrderType
@Keep
data class GetAudioContentDetailResponse( data class GetAudioContentDetailResponse(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -39,12 +41,14 @@ data class GetAudioContentDetailResponse(
@SerializedName("creator") val creator: AudioContentCreator @SerializedName("creator") val creator: AudioContentCreator
) )
@Keep
data class OtherContentResponse( data class OtherContentResponse(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("coverUrl") val coverUrl: String, @SerializedName("coverUrl") val coverUrl: String,
) )
@Keep
data class AudioContentCreator( data class AudioContentCreator(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,11 +1,14 @@
package kr.co.vividnext.sodalive.audio_content.detail package kr.co.vividnext.sodalive.audio_content.detail
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PutAudioContentLikeRequest( data class PutAudioContentLikeRequest(
@SerializedName("contentId") val contentId: Long @SerializedName("contentId") val contentId: Long
) )
@Keep
data class PutAudioContentLikeResponse( data class PutAudioContentLikeResponse(
@SerializedName("like") val like: Boolean @SerializedName("like") val like: Boolean
) )

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.donation package kr.co.vividnext.sodalive.audio_content.donation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class AudioContentDonationRequest( data class AudioContentDonationRequest(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("donationCan") val donationCan: Int, @SerializedName("donationCan") val donationCan: Int,

View File

@ -41,6 +41,7 @@ import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.explorer.profile.series.UserProfileSeriesListAdapter import kr.co.vividnext.sodalive.explorer.profile.series.UserProfileSeriesListAdapter
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListActivity
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
import kr.co.vividnext.sodalive.settings.notification.MemberRole import kr.co.vividnext.sodalive.settings.notification.MemberRole
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -121,6 +122,24 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
} }
) )
} }
binding.ivContentKeep.setOnClickListener {
startActivity(
Intent(
requireContext(),
AudioContentOrderListActivity::class.java
)
)
}
binding.ivAlarm.setOnClickListener {
startActivity(
Intent(
requireActivity(),
AlarmListActivity::class.java
)
)
}
} }
private fun setupRecommendSeries() { private fun setupRecommendSeries() {

View File

@ -1,14 +1,17 @@
package kr.co.vividnext.sodalive.audio_content.main package kr.co.vividnext.sodalive.audio_content.main
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.settings.event.EventItem import kr.co.vividnext.sodalive.settings.event.EventItem
@Keep
data class GetNewContentUploadCreator( data class GetNewContentUploadCreator(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("creatorNickname") val creatorNickname: String, @SerializedName("creatorNickname") val creatorNickname: String,
@SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String @SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String
) )
@Keep
data class GetAudioContentMainItem( data class GetAudioContentMainItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String, @SerializedName("coverImageUrl") val coverImageUrl: String,
@ -20,12 +23,14 @@ data class GetAudioContentMainItem(
@SerializedName("duration") val duration: String @SerializedName("duration") val duration: String
) )
@Keep
data class GetAudioContentRanking( data class GetAudioContentRanking(
@SerializedName("startDate") val startDate: String, @SerializedName("startDate") val startDate: String,
@SerializedName("endDate") val endDate: String, @SerializedName("endDate") val endDate: String,
@SerializedName("items") val items: List<GetAudioContentRankingItem> @SerializedName("items") val items: List<GetAudioContentRankingItem>
) )
@Keep
data class GetAudioContentRankingItem( data class GetAudioContentRankingItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -37,6 +42,7 @@ data class GetAudioContentRankingItem(
@SerializedName("creatorNickname") val creatorNickname: String @SerializedName("creatorNickname") val creatorNickname: String
) )
@Keep
data class GetAudioContentCurationResponse( data class GetAudioContentCurationResponse(
@SerializedName("curationId") val curationId: Long, @SerializedName("curationId") val curationId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -44,6 +50,7 @@ data class GetAudioContentCurationResponse(
@SerializedName("contents") val audioContents: List<GetAudioContentMainItem> @SerializedName("contents") val audioContents: List<GetAudioContentMainItem>
) )
@Keep
data class GetAudioContentBannerResponse( data class GetAudioContentBannerResponse(
@SerializedName("type") val type: AudioContentBannerType, @SerializedName("type") val type: AudioContentBannerType,
@SerializedName("thumbnailImageUrl") val thumbnailImageUrl: String, @SerializedName("thumbnailImageUrl") val thumbnailImageUrl: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.modify package kr.co.vividnext.sodalive.audio_content.modify
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class ModifyAudioContentRequest( data class ModifyAudioContentRequest(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String?, @SerializedName("title") val title: String?,

View File

@ -34,7 +34,7 @@ class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderList
override fun setupView() { override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater) loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "구매목록" binding.toolbar.tvBack.text = "콘텐츠 보관함"
binding.toolbar.tvBack.setOnClickListener { finish() } binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = AudioContentOrderListAdapter { adapter = AudioContentOrderListAdapter {

View File

@ -1,12 +1,15 @@
package kr.co.vividnext.sodalive.audio_content.order package kr.co.vividnext.sodalive.audio_content.order
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetAudioContentOrderListResponse( data class GetAudioContentOrderListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentOrderListItem> @SerializedName("items") val items: List<GetAudioContentOrderListItem>
) )
@Keep
data class GetAudioContentOrderListItem( data class GetAudioContentOrderListItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String, @SerializedName("coverImageUrl") val coverImageUrl: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.order package kr.co.vividnext.sodalive.audio_content.order
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class OrderRequest( data class OrderRequest(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("orderType") val orderType: OrderType, @SerializedName("orderType") val orderType: OrderType,

View File

@ -1,11 +1,14 @@
package kr.co.vividnext.sodalive.audio_content.series package kr.co.vividnext.sodalive.audio_content.series
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetSeriesListResponse( data class GetSeriesListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<SeriesListItem> @SerializedName("items") val items: List<SeriesListItem>
) { ) {
@Keep
data class SeriesListItem( data class SeriesListItem(
@SerializedName("seriesId") val seriesId: Long, @SerializedName("seriesId") val seriesId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -18,6 +21,7 @@ data class GetSeriesListResponse(
@SerializedName("isPopular") val isPopular: Boolean @SerializedName("isPopular") val isPopular: Boolean
) )
@Keep
data class SeriesListItemCreator( data class SeriesListItemCreator(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -30,6 +30,7 @@ interface SeriesApi {
@Path("id") seriesId: Long, @Path("id") seriesId: Long,
@Query("page") page: Int, @Query("page") page: Int,
@Query("size") size: Int, @Query("size") size: Int,
@Query("sortType") sortType: SeriesListAllViewModel.SeriesSortType,
@Header("Authorization") authHeader: String @Header("Authorization") authHeader: String
): Single<ApiResponse<GetSeriesContentListResponse>> ): Single<ApiResponse<GetSeriesContentListResponse>>

View File

@ -13,7 +13,7 @@ class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseVie
enum class SeriesSortType { enum class SeriesSortType {
@SerializedName("NEWEST") NEWEST, @SerializedName("NEWEST") NEWEST,
@SerializedName("POPULAR") POPULAR @SerializedName("OLDEST") OLDEST
} }
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<String?>()

View File

@ -24,11 +24,13 @@ class SeriesRepository(private val api: SeriesApi) {
seriesId: Long, seriesId: Long,
page: Int, page: Int,
size: Int, size: Int,
sortType: SeriesListAllViewModel.SeriesSortType,
token: String token: String
) = api.getSeriesContentList( ) = api.getSeriesContentList(
seriesId = seriesId, seriesId = seriesId,
page = page - 1, page = page - 1,
size = size, size = size,
sortType = sortType,
authHeader = token authHeader = token
) )

View File

@ -2,11 +2,15 @@ package kr.co.vividnext.sodalive.audio_content.series.content
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllViewModel
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
@ -86,6 +90,14 @@ class SeriesContentAllActivity : BaseActivity<ActivitySeriesContentAllBinding>(
}) })
binding.rvSeriesContentAll.adapter = adapter binding.rvSeriesContentAll.adapter = adapter
binding.tvSortNewest.setOnClickListener {
viewModel.changeSort(SeriesListAllViewModel.SeriesSortType.NEWEST)
}
binding.tvSortOldest.setOnClickListener {
viewModel.changeSort(SeriesListAllViewModel.SeriesSortType.OLDEST)
}
} }
fun bindData() { fun bindData() {
@ -104,5 +116,42 @@ class SeriesContentAllActivity : BaseActivity<ActivitySeriesContentAllBinding>(
viewModel.seriesContentListLiveData.observe(this) { viewModel.seriesContentListLiveData.observe(this) {
adapter.addItems(it) adapter.addItems(it)
} }
viewModel.sortLiveData.observe(this) {
deselectSort()
selectSort(
when (it) {
SeriesListAllViewModel.SeriesSortType.OLDEST -> {
binding.tvSortOldest
}
else -> {
binding.tvSortNewest
}
}
)
}
}
private fun deselectSort() {
val color = ContextCompat.getColor(
applicationContext,
R.color.color_88e2e2e2
)
binding.tvSortNewest.setTextColor(color)
binding.tvSortOldest.setTextColor(color)
}
private fun selectSort(view: TextView) {
view.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_e2e2e2
)
)
adapter.clear()
viewModel.getSeriesContentList()
} }
} }

View File

@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllViewModel
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListItem import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListItem
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
@ -23,6 +24,10 @@ class SeriesContentAllViewModel(private val repository: SeriesRepository) : Base
val seriesContentListLiveData: LiveData<List<GetSeriesContentListItem>> val seriesContentListLiveData: LiveData<List<GetSeriesContentListItem>>
get() = _seriesContentListLiveData get() = _seriesContentListLiveData
private var _sortLiveData = MutableLiveData(SeriesListAllViewModel.SeriesSortType.NEWEST)
val sortLiveData: LiveData<SeriesListAllViewModel.SeriesSortType>
get() = _sortLiveData
var seriesId = 0L var seriesId = 0L
var page = 1 var page = 1
@ -38,6 +43,7 @@ class SeriesContentAllViewModel(private val repository: SeriesRepository) : Base
seriesId = seriesId, seriesId = seriesId,
page = page, page = page,
size = pageSize, size = pageSize,
sortType = _sortLiveData.value!!,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
@ -70,4 +76,12 @@ class SeriesContentAllViewModel(private val repository: SeriesRepository) : Base
) )
} }
} }
fun changeSort(sortType: SeriesListAllViewModel.SeriesSortType) {
if (_sortLiveData.value != sortType) {
page = 1
isLast = false
_sortLiveData.value = sortType
}
}
} }

View File

@ -1,15 +1,18 @@
package kr.co.vividnext.sodalive.audio_content.series.detail package kr.co.vividnext.sodalive.audio_content.series.detail
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Keep
data class GetSeriesContentListResponse( data class GetSeriesContentListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetSeriesContentListItem> @SerializedName("items") val items: List<GetSeriesContentListItem>
) )
@Parcelize @Parcelize
@Keep
data class GetSeriesContentListItem( data class GetSeriesContentListItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,

View File

@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.audio_content.series.detail package kr.co.vividnext.sodalive.audio_content.series.detail
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
@Keep
data class GetSeriesDetailResponse( data class GetSeriesDetailResponse(
@SerializedName("seriesId") val seriesId: Long, @SerializedName("seriesId") val seriesId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -27,6 +29,7 @@ data class GetSeriesDetailResponse(
@SerializedName("contentCount") val contentCount: Int @SerializedName("contentCount") val contentCount: Int
) : Parcelable { ) : Parcelable {
@Parcelize @Parcelize
@Keep
data class GetSeriesDetailCreator( data class GetSeriesDetailCreator(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.upload package kr.co.vividnext.sodalive.audio_content.upload
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CreateAudioContentRequest( data class CreateAudioContentRequest(
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("detail") val detail: String, @SerializedName("detail") val detail: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.upload.theme package kr.co.vividnext.sodalive.audio_content.upload.theme
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetAudioContentThemeResponse( data class GetAudioContentThemeResponse(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("theme") val theme: String, @SerializedName("theme") val theme: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.common package kr.co.vividnext.sodalive.common
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class ApiResponse<T>( data class ApiResponse<T>(
@SerializedName("success") val success: Boolean, @SerializedName("success") val success: Boolean,
@SerializedName("data") val data: T? = null, @SerializedName("data") val data: T? = null,

View File

@ -59,6 +59,7 @@ object Constants {
const val EXTRA_AUDIO_CONTENT_NEXT_ACTION = "audio_content_next_action" const val EXTRA_AUDIO_CONTENT_NEXT_ACTION = "audio_content_next_action"
const val EXTRA_AUDIO_CONTENT_ALERT_PREVIEW = "audio_content_alert_preview" const val EXTRA_AUDIO_CONTENT_ALERT_PREVIEW = "audio_content_alert_preview"
const val EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL = "audio_content_cover_image_url" const val EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL = "audio_content_cover_image_url"
const val EXTRA_IS_SHOW_SECRET = "extra_is_show_secret"
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2 const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver" const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"

View File

@ -7,6 +7,8 @@ import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -33,7 +35,19 @@ class SodaLiveService : Service() {
} }
private fun updateNotification(content: String) { private fun updateNotification(content: String) {
startForeground(Constants.LIVE_SERVICE_NOTIFICATION_ID, createNotification(content)) val notification = createNotification(content)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val foregroundServiceTypes = FOREGROUND_SERVICE_TYPE_MICROPHONE or
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
startForeground(
Constants.LIVE_SERVICE_NOTIFICATION_ID,
notification,
foregroundServiceTypes
)
} else {
startForeground(Constants.LIVE_SERVICE_NOTIFICATION_ID, notification)
}
} }
private fun createNotification(content: String): Notification { private fun createNotification(content: String): Notification {

View File

@ -80,6 +80,7 @@ import kr.co.vividnext.sodalive.mypage.alarm.AlarmListRepository
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListViewModel import kr.co.vividnext.sodalive.mypage.alarm.AlarmListViewModel
import kr.co.vividnext.sodalive.mypage.auth.AuthApi import kr.co.vividnext.sodalive.mypage.auth.AuthApi
import kr.co.vividnext.sodalive.mypage.auth.AuthRepository import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
import kr.co.vividnext.sodalive.mypage.block.BlockMemberViewModel
import kr.co.vividnext.sodalive.mypage.can.CanApi import kr.co.vividnext.sodalive.mypage.can.CanApi
import kr.co.vividnext.sodalive.mypage.can.CanRepository import kr.co.vividnext.sodalive.mypage.can.CanRepository
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel
@ -115,6 +116,7 @@ import kr.co.vividnext.sodalive.settings.terms.TermsRepository
import kr.co.vividnext.sodalive.settings.terms.TermsViewModel import kr.co.vividnext.sodalive.settings.terms.TermsViewModel
import kr.co.vividnext.sodalive.user.UserApi import kr.co.vividnext.sodalive.user.UserApi
import kr.co.vividnext.sodalive.user.UserRepository import kr.co.vividnext.sodalive.user.UserRepository
import kr.co.vividnext.sodalive.user.UserViewModel
import kr.co.vividnext.sodalive.user.find_password.FindPasswordViewModel import kr.co.vividnext.sodalive.user.find_password.FindPasswordViewModel
import kr.co.vividnext.sodalive.user.login.LoginViewModel import kr.co.vividnext.sodalive.user.login.LoginViewModel
import kr.co.vividnext.sodalive.user.signup.SignUpViewModel import kr.co.vividnext.sodalive.user.signup.SignUpViewModel
@ -256,6 +258,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { CanCouponViewModel(get()) } viewModel { CanCouponViewModel(get()) }
viewModel { CanChargeIapViewModel(get()) } viewModel { CanChargeIapViewModel(get()) }
viewModel { AlarmListViewModel(get()) } viewModel { AlarmListViewModel(get()) }
viewModel { BlockMemberViewModel(get()) }
viewModel { UserViewModel(get(), get()) }
} }
private val repositoryModule = module { private val repositoryModule = module {

View File

@ -0,0 +1,174 @@
package kr.co.vividnext.sodalive.dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.Window
import android.view.WindowManager
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentActivity
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.DialogMemberProfileBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.report.ProfileReportDialog
import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.report.UserReportDialog
import kr.co.vividnext.sodalive.settings.notification.MemberRole
import kr.co.vividnext.sodalive.user.UserViewModel
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
class MemberProfileDialog(
private val activity: FragmentActivity,
private val layoutInflater: LayoutInflater,
private val memberId: Long,
private val screenWidth: Int
) : KoinComponent {
private val viewModel: UserViewModel by inject()
private val alertDialog: AlertDialog
val dialogView = DialogMemberProfileBinding.inflate(layoutInflater)
private lateinit var loadingDialog: LoadingDialog
init {
val dialogBuilder = AlertDialog.Builder(activity)
dialogBuilder.setView(dialogView.root)
alertDialog = dialogBuilder.create()
alertDialog.setCancelable(false)
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setupView()
bindData()
}
fun dismiss() {
alertDialog.dismiss()
}
fun show() {
viewModel.getMemberProfile(memberId) {
alertDialog.show()
val lp = WindowManager.LayoutParams()
lp.copyFrom(alertDialog.window?.attributes)
lp.width = screenWidth - (40.dpToPx()).toInt()
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
alertDialog.window?.attributes = lp
}
}
private fun setupView() {
loadingDialog = LoadingDialog(activity, layoutInflater)
val profileLP = dialogView.ivProfile.layoutParams
profileLP.width = activity.resources.displayMetrics.widthPixels - (66.7f.dpToPx()).toInt()
profileLP.height = activity.resources.displayMetrics.widthPixels - (66.7f.dpToPx()).toInt()
dialogView.ivProfile.layoutParams = profileLP
dialogView.ivClose.setOnClickListener { dismiss() }
}
private fun bindData() {
viewModel.isLoading.observe(activity) {
if (it) {
loadingDialog.show(screenWidth)
} else {
loadingDialog.dismiss()
}
}
viewModel.toastLiveData.observe(activity) {
Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
}
viewModel.memberProfile.observe(activity) {
dialogView.ivProfile.load(it.profileImageUrl) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(RoundedCornersTransformation(8.dpToPx()))
}
dialogView.tvNickname.text = it.nickname
dialogView.tvBlockMember.text = if (it.isBlocked) {
"차단 해제"
} else {
"차단"
}
dialogView.tvBlockMember.setOnClickListener { _ ->
if (it.isBlocked) {
viewModel.memberUnBlock(it.memberId) { dismiss() }
} else {
showMemberBlockDialog(it.memberId, it.nickname)
}
}
dialogView.tvReportMember.setOnClickListener { _ ->
showMemberReportDialog(it.memberId)
}
dialogView.tvReportMemberProfile.setOnClickListener { _ ->
showProfileReportDialog(it.memberId)
}
}
}
private fun showMemberBlockDialog(memberId: Long, nickname: String) {
val message = if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
"""
${nickname}님을 차단하시겠습니까?
사용자를 차단하면 사용자는 아래 기능이 제한됩니다.
- 내가 개설한 라이브 입장 불가
- 나에게 메시지 보내기 불가
- 채널의 팬Talk 작성불가
""".trimIndent()
} else {
"""
${nickname}님을 차단하시겠습니까?
- 사용자를 차단하면 '차단한 사용자의 라이브 채팅' 보이지 않습니다.
""".trimIndent()
}
val dialog = android.app.AlertDialog.Builder(activity)
dialog.setTitle("사용자 차단")
dialog.setMessage(message)
dialog.setPositiveButton("차단") { _, _ ->
viewModel.memberBlock(memberId) { dismiss() }
}
dialog.setNegativeButton("취소") { _, _ -> }
dialog.show()
}
private fun showMemberReportDialog(memberId: Long) {
val dialog = UserReportDialog(activity, layoutInflater) {
viewModel.report(
type = ReportType.USER,
userId = memberId,
reason = it
) { dismiss() }
}
dialog.show(screenWidth)
}
private fun showProfileReportDialog(memberId: Long) {
val dialog = ProfileReportDialog(activity, layoutInflater) {
viewModel.report(
type = ReportType.PROFILE,
userId = memberId
) { dismiss() }
}
dialog.show(screenWidth)
}
}

View File

@ -1,11 +1,14 @@
package kr.co.vividnext.sodalive.explorer package kr.co.vividnext.sodalive.explorer
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetExplorerResponse( data class GetExplorerResponse(
@SerializedName("sections") val sections: List<GetExplorerSectionResponse> @SerializedName("sections") val sections: List<GetExplorerSectionResponse>
) )
@Keep
data class GetExplorerSectionResponse( data class GetExplorerSectionResponse(
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("coloredTitle") val coloredTitle: String?, @SerializedName("coloredTitle") val coloredTitle: String?,
@ -14,6 +17,7 @@ data class GetExplorerSectionResponse(
@SerializedName("creators") val creators: List<GetExplorerSectionCreatorResponse> @SerializedName("creators") val creators: List<GetExplorerSectionCreatorResponse>
) )
@Keep
data class GetExplorerSectionCreatorResponse( data class GetExplorerSectionCreatorResponse(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,12 +1,15 @@
package kr.co.vividnext.sodalive.explorer.profile package kr.co.vividnext.sodalive.explorer.profile
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetCheersResponse( data class GetCheersResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("cheers") val cheers: List<GetCheersResponseItem> @SerializedName("cheers") val cheers: List<GetCheersResponseItem>
) )
@Keep
data class GetCheersResponseItem( data class GetCheersResponseItem(
@SerializedName("cheersId") val cheersId: Long, @SerializedName("cheersId") val cheersId: Long,
@SerializedName("memberId") val memberId: Long, @SerializedName("memberId") val memberId: Long,

View File

@ -1,9 +1,11 @@
package kr.co.vividnext.sodalive.explorer.profile package kr.co.vividnext.sodalive.explorer.profile
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
@Keep
data class GetCreatorProfileResponse( data class GetCreatorProfileResponse(
@SerializedName("creator") @SerializedName("creator")
val creator: CreatorResponse, val creator: CreatorResponse,
@ -27,6 +29,7 @@ data class GetCreatorProfileResponse(
val isBlock: Boolean val isBlock: Boolean
) )
@Keep
data class CreatorResponse( data class CreatorResponse(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@ -42,6 +45,7 @@ data class CreatorResponse(
@SerializedName("notificationRecipientCount") val notificationRecipientCount: Int @SerializedName("notificationRecipientCount") val notificationRecipientCount: Int
) )
@Keep
data class UserDonationRankingResponse( data class UserDonationRankingResponse(
@SerializedName("userId") val userId: Long, @SerializedName("userId") val userId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@ -49,6 +53,7 @@ data class UserDonationRankingResponse(
@SerializedName("donationCan") val donationCan: Int @SerializedName("donationCan") val donationCan: Int
) )
@Keep
data class LiveRoomResponse( data class LiveRoomResponse(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@ -65,11 +70,13 @@ data class LiveRoomResponse(
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean @SerializedName("isPrivateRoom") val isPrivateRoom: Boolean
) )
@Keep
data class GetAudioContentListResponse( data class GetAudioContentListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentListItem> @SerializedName("items") val items: List<GetAudioContentListItem>
) )
@Keep
data class GetAudioContentListItem( data class GetAudioContentListItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String, @SerializedName("coverImageUrl") val coverImageUrl: String,
@ -87,6 +94,7 @@ data class GetAudioContentListItem(
@SerializedName("isSoldOut") val isSoldOut: Boolean @SerializedName("isSoldOut") val isSoldOut: Boolean
) )
@Keep
data class GetCreatorActivitySummary( data class GetCreatorActivitySummary(
@SerializedName("liveCount") val liveCount: Int, @SerializedName("liveCount") val liveCount: Int,
@SerializedName("liveTime") val liveTime: Int, @SerializedName("liveTime") val liveTime: Int,

View File

@ -1,5 +1,7 @@
package kr.co.vividnext.sodalive.explorer.profile package kr.co.vividnext.sodalive.explorer.profile
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class MemberBlockRequest(@SerializedName("blockMemberId") val blockMemberId: Long) data class MemberBlockRequest(@SerializedName("blockMemberId") val blockMemberId: Long)

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile package kr.co.vividnext.sodalive.explorer.profile
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PostCreatorNoticeRequest( data class PostCreatorNoticeRequest(
@SerializedName("notice") @SerializedName("notice")
val notice: String val notice: String

View File

@ -38,6 +38,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
@ -382,6 +383,14 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
cancelButtonTitle = "취소", cancelButtonTitle = "취소",
cancelButtonClick = {} cancelButtonClick = {}
).show(screenWidth) ).show(screenWidth)
},
onClickProfile = {
MemberProfileDialog(
activity = this@UserProfileActivity,
layoutInflater = layoutInflater,
memberId = it,
screenWidth = screenWidth
).show()
} }
) )

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.cheers package kr.co.vividnext.sodalive.explorer.profile.cheers
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PostWriteCheersRequest( data class PostWriteCheersRequest(
@SerializedName("parentId") val parentId: Long? = null, @SerializedName("parentId") val parentId: Long? = null,
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.cheers package kr.co.vividnext.sodalive.explorer.profile.cheers
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PutModifyCheersRequest( data class PutModifyCheersRequest(
@SerializedName("cheersId") val cheersId: Long, @SerializedName("cheersId") val cheersId: Long,
@SerializedName("content") var content: String? = null, @SerializedName("content") var content: String? = null,

View File

@ -20,7 +20,8 @@ class UserProfileCheersAdapter(
private val modifyReply: (Long, String?) -> Unit, private val modifyReply: (Long, String?) -> Unit,
private val modifyCheers: (Long, String) -> Unit, private val modifyCheers: (Long, String) -> Unit,
private val onClickReport: (Long) -> Unit, private val onClickReport: (Long) -> Unit,
private val onClickDelete: (Long) -> Unit private val onClickDelete: (Long) -> Unit,
private val onClickProfile: (Long) -> Unit
) : RecyclerView.Adapter<UserProfileCheersAdapter.ViewHolder>() { ) : RecyclerView.Adapter<UserProfileCheersAdapter.ViewHolder>() {
val items = mutableListOf<GetCheersResponseItem>() val items = mutableListOf<GetCheersResponseItem>()
@ -35,6 +36,12 @@ class UserProfileCheersAdapter(
binding.llCheerReply.visibility = View.GONE binding.llCheerReply.visibility = View.GONE
binding.rlCheerReply.visibility = View.GONE binding.rlCheerReply.visibility = View.GONE
binding.ivProfile.setOnClickListener {
if (SharedPreferenceManager.userId != cheers.memberId) {
onClickProfile(cheers.memberId)
}
}
binding.ivProfile.load(cheers.profileUrl) { binding.ivProfile.load(cheers.profileUrl) {
crossfade(true) crossfade(true)
placeholder(R.drawable.ic_place_holder) placeholder(R.drawable.ic_place_holder)

View File

@ -1,15 +1,18 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community package kr.co.vividnext.sodalive.explorer.profile.creator_community
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Keep
data class GetCommunityPostCommentListResponse( data class GetCommunityPostCommentListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetCommunityPostCommentListItem> @SerializedName("items") val items: List<GetCommunityPostCommentListItem>
) )
@Parcelize @Parcelize
@Keep
data class GetCommunityPostCommentListItem( data class GetCommunityPostCommentListItem(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("writerId") val writerId: Long, @SerializedName("writerId") val writerId: Long,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community package kr.co.vividnext.sodalive.explorer.profile.creator_community
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetCommunityPostListResponse( data class GetCommunityPostListResponse(
@SerializedName("postId") val postId: Long, @SerializedName("postId") val postId: Long,
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PostCommunityPostLikeRequest( data class PostCommunityPostLikeRequest(
@SerializedName("postId") val postId: Long @SerializedName("postId") val postId: Long
) )

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class PurchasePostRequest( data class PurchasePostRequest(
@SerializedName("postId") val postId: Long, @SerializedName("postId") val postId: Long,
@SerializedName("timezone") val timezone: String, @SerializedName("timezone") val timezone: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CreateCommunityPostCommentRequest( data class CreateCommunityPostCommentRequest(
@SerializedName("comment") val comment: String, @SerializedName("comment") val comment: String,
@SerializedName("postId") val postId: Long, @SerializedName("postId") val postId: Long,

View File

@ -17,7 +17,8 @@ class CreatorCommunityCommentAdapter(
private val creatorId: Long, private val creatorId: Long,
private val modifyComment: (Long, String) -> Unit, private val modifyComment: (Long, String) -> Unit,
private val onClickDelete: (Long) -> Unit, private val onClickDelete: (Long) -> Unit,
private val onItemClick: (GetCommunityPostCommentListItem) -> Unit private val onItemClick: (GetCommunityPostCommentListItem) -> Unit,
private val onClickProfile: (Long) -> Unit
) : RecyclerView.Adapter<CreatorCommunityCommentAdapter.ViewHolder>() { ) : RecyclerView.Adapter<CreatorCommunityCommentAdapter.ViewHolder>() {
var items = mutableSetOf<GetCommunityPostCommentListItem>() var items = mutableSetOf<GetCommunityPostCommentListItem>()
@ -33,6 +34,12 @@ class CreatorCommunityCommentAdapter(
transformations(CircleCropTransformation()) transformations(CircleCropTransformation())
} }
binding.ivCommentProfile.setOnClickListener {
if (SharedPreferenceManager.userId != item.writerId) {
onClickProfile(item.writerId)
}
}
binding.tvComment.text = item.comment binding.tvComment.text = item.comment
binding.tvCommentDate.text = item.date binding.tvCommentDate.text = item.date
binding.tvCommentNickname.text = item.nickname binding.tvCommentNickname.text = item.nickname

View File

@ -20,6 +20,7 @@ import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -106,6 +107,14 @@ class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCom
}, },
onItemClick = { onItemClick = {
(parentFragment as CreatorCommunityCommentFragment).onClickComment(it) (parentFragment as CreatorCommunityCommentFragment).onClickComment(it)
},
onClickProfile = {
MemberProfileDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
memberId = it,
screenWidth = screenWidth
).show()
} }
) )

View File

@ -19,7 +19,8 @@ import kr.co.vividnext.sodalive.extensions.loadUrl
class CreatorCommunityCommentReplyAdapter( class CreatorCommunityCommentReplyAdapter(
private val creatorId: Long, private val creatorId: Long,
private val modifyComment: (Long, String) -> Unit, private val modifyComment: (Long, String) -> Unit,
private val onClickDelete: (Long) -> Unit private val onClickDelete: (Long) -> Unit,
private val onClickProfile: (Long) -> Unit
) : RecyclerView.Adapter<CreatorCommunityCommentReplyViewHolder>() { ) : RecyclerView.Adapter<CreatorCommunityCommentReplyViewHolder>() {
var items = mutableSetOf<GetCommunityPostCommentListItem>() var items = mutableSetOf<GetCommunityPostCommentListItem>()
override fun onCreateViewHolder( override fun onCreateViewHolder(
@ -46,7 +47,8 @@ class CreatorCommunityCommentReplyAdapter(
showOptionMenu = { context, view, commentId, writerId, creatorId, onClickModify -> showOptionMenu = { context, view, commentId, writerId, creatorId, onClickModify ->
showOptionMenu(context, view, commentId, writerId, creatorId, onClickModify) showOptionMenu(context, view, commentId, writerId, creatorId, onClickModify)
}, },
modifyComment = modifyComment modifyComment = modifyComment,
onClickProfile = onClickProfile
) )
} }
} }
@ -128,9 +130,16 @@ class CreatorCommunityCommentReplyItemViewHolder(
private val showOptionMenu: ( private val showOptionMenu: (
Context, View, Long, Long, Long, onClickModify: () -> Unit Context, View, Long, Long, Long, onClickModify: () -> Unit
) -> Unit, ) -> Unit,
private val modifyComment: (Long, String) -> Unit private val modifyComment: (Long, String) -> Unit,
private val onClickProfile: (Long) -> Unit
) : CreatorCommunityCommentReplyViewHolder(binding) { ) : CreatorCommunityCommentReplyViewHolder(binding) {
override fun bind(item: GetCommunityPostCommentListItem) { override fun bind(item: GetCommunityPostCommentListItem) {
binding.ivCommentProfile.setOnClickListener {
if (SharedPreferenceManager.userId != item.writerId) {
onClickProfile(item.writerId)
}
}
binding.ivCommentProfile.load(item.profileUrl) { binding.ivCommentProfile.load(item.profileUrl) {
crossfade(true) crossfade(true)
placeholder(R.drawable.ic_place_holder) placeholder(R.drawable.ic_place_holder)

View File

@ -21,6 +21,7 @@ import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentReplyBinding import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentReplyBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -127,6 +128,14 @@ class CreatorCommunityCommentReplyFragment : BaseFragment<FragmentAudioContentCo
cancelButtonClick = {} cancelButtonClick = {}
).show(screenWidth) ).show(screenWidth)
}, },
onClickProfile = {
MemberProfileDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
memberId = it,
screenWidth = screenWidth
).show()
}
).apply { ).apply {
items.add(originalComment!!) items.add(originalComment!!)
} }

View File

@ -6,10 +6,16 @@ import android.media.AudioAttributes
import android.media.MediaPlayer import android.media.MediaPlayer
import android.net.Uri import android.net.Uri
import android.widget.Toast import android.widget.Toast
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
import java.io.IOException import java.io.IOException
data class CreatorCommunityContentItem(val contentId: Long, val url: String) @Keep
data class CreatorCommunityContentItem(
@SerializedName("contentId") val contentId: Long,
@SerializedName("url") val url: String
)
class CreatorCommunityMediaPlayerManager( class CreatorCommunityMediaPlayerManager(
private val context: Context, private val context: Context,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class ModifyCommunityPostRequest( data class ModifyCommunityPostRequest(
@SerializedName("creatorCommunityId") val creatorCommunityId: Long, @SerializedName("creatorCommunityId") val creatorCommunityId: Long,
@SerializedName("content") val content: String? = null, @SerializedName("content") val content: String? = null,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.write package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CreateCommunityPostRequest( data class CreateCommunityPostRequest(
@SerializedName("content") val content: String, @SerializedName("content") val content: String,
@SerializedName("price") val price: Int, @SerializedName("price") val price: Int,

View File

@ -85,7 +85,7 @@ class RecordingVoiceFragment : BottomSheetDialogFragment() {
} }
binding.ivRecordStart.setOnClickListener { binding.ivRecordStart.setOnClickListener {
fileNameMedia = requireActivity().filesDir.path + fileNameMedia = requireActivity().filesDir.path +
"/record_community_voice_${System.currentTimeMillis()}.m4a" "/now_voice_${System.currentTimeMillis()}.m4a"
val fileMedia = File(fileNameMedia) val fileMedia = File(fileNameMedia)
if (!fileMedia.exists()) { if (!fileMedia.exists()) {

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.explorer.profile.donation package kr.co.vividnext.sodalive.explorer.profile.donation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.explorer.profile.UserDonationRankingResponse import kr.co.vividnext.sodalive.explorer.profile.UserDonationRankingResponse
@Keep
data class GetDonationAllResponse( data class GetDonationAllResponse(
@SerializedName("accumulatedCansToday") @SerializedName("accumulatedCansToday")
val accumulatedCansToday: Int, val accumulatedCansToday: Int,

View File

@ -16,6 +16,7 @@ import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileFantalkAllBinding import kr.co.vividnext.sodalive.databinding.ActivityUserProfileFantalkAllBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.report.CheersReportDialog import kr.co.vividnext.sodalive.report.CheersReportDialog
@ -61,6 +62,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
private fun setupCheersView() { private fun setupCheersView() {
binding.ivSend.setOnClickListener { binding.ivSend.setOnClickListener {
hideKeyboard { hideKeyboard {
cheersAdapter.items.clear()
viewModel.writeCheers( viewModel.writeCheers(
creatorId = userId, creatorId = userId,
cheersContent = binding.etCheer.text.toString() cheersContent = binding.etCheer.text.toString()
@ -73,6 +75,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
userId = userId, userId = userId,
enterReply = { cheersId, content -> enterReply = { cheersId, content ->
hideKeyboard { hideKeyboard {
cheersAdapter.items.clear()
viewModel.writeCheers( viewModel.writeCheers(
parentCheersId = cheersId, parentCheersId = cheersId,
creatorId = userId, creatorId = userId,
@ -82,6 +85,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
}, },
modifyReply = { cheersId, content -> modifyReply = { cheersId, content ->
hideKeyboard { hideKeyboard {
cheersAdapter.items.clear()
viewModel.modifyCheers( viewModel.modifyCheers(
cheersId = cheersId, cheersId = cheersId,
creatorId = userId, creatorId = userId,
@ -91,6 +95,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
}, },
modifyCheers = { cheersId, content -> modifyCheers = { cheersId, content ->
hideKeyboard { hideKeyboard {
cheersAdapter.items.clear()
viewModel.modifyCheers( viewModel.modifyCheers(
cheersId = cheersId, cheersId = cheersId,
creatorId = userId, creatorId = userId,
@ -107,6 +112,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
desc = "삭제하시겠습니까?", desc = "삭제하시겠습니까?",
confirmButtonTitle = "삭제", confirmButtonTitle = "삭제",
confirmButtonClick = { confirmButtonClick = {
cheersAdapter.items.clear()
viewModel.modifyCheers( viewModel.modifyCheers(
cheersId = it, cheersId = it,
creatorId = userId, creatorId = userId,
@ -116,6 +122,14 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
cancelButtonTitle = "취소", cancelButtonTitle = "취소",
cancelButtonClick = {} cancelButtonClick = {}
).show(screenWidth) ).show(screenWidth)
},
onClickProfile = {
MemberProfileDialog(
activity = this@UserProfileFantalkAllViewActivity,
layoutInflater = layoutInflater,
memberId = it,
screenWidth = screenWidth
).show()
} }
) )

View File

@ -1,12 +1,15 @@
package kr.co.vividnext.sodalive.explorer.profile.follow package kr.co.vividnext.sodalive.explorer.profile.follow
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetFollowerListResponse( data class GetFollowerListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetFollowerListResponseItem> @SerializedName("items") val items: List<GetFollowerListResponseItem>
) )
@Keep
data class GetFollowerListResponseItem( data class GetFollowerListResponseItem(
@SerializedName("userId") val userId: Long, @SerializedName("userId") val userId: Long,
@SerializedName("profileImage") val profileImage: String, @SerializedName("profileImage") val profileImage: String,

View File

@ -32,7 +32,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
override fun setupView() { override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater) loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "팔로잉 채널 리스트" binding.toolbar.tvBack.text = "팔로잉 리스트"
binding.toolbar.tvBack.setOnClickListener { finish() } binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = FollowingCreatorAdapter( adapter = FollowingCreatorAdapter(
@ -104,6 +104,14 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
viewModel.creatorListTotalCountLiveData.observe(this) { viewModel.creatorListTotalCountLiveData.observe(this) {
binding.tvTotalCount.text = " $it " binding.tvTotalCount.text = " $it "
if (it > 0) {
binding.tvNone.visibility = View.GONE
binding.rvFollowingCreator.visibility = View.VISIBLE
} else {
binding.tvNone.visibility = View.VISIBLE
binding.rvFollowingCreator.visibility = View.GONE
}
} }
} }
} }

View File

@ -16,7 +16,7 @@ class FollowingCreatorViewModel(
val creatorListLiveData: LiveData<List<GetCreatorFollowingAllListItem>> val creatorListLiveData: LiveData<List<GetCreatorFollowingAllListItem>>
get() = _creatorListLiveData get() = _creatorListLiveData
private val _creatorListTotalCountLiveData = MutableLiveData<Int>() private val _creatorListTotalCountLiveData = MutableLiveData(0)
val creatorListTotalCountLiveData: LiveData<Int> val creatorListTotalCountLiveData: LiveData<Int>
get() = _creatorListTotalCountLiveData get() = _creatorListTotalCountLiveData

View File

@ -1,12 +1,15 @@
package kr.co.vividnext.sodalive.following package kr.co.vividnext.sodalive.following
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetCreatorFollowingAllListResponse( data class GetCreatorFollowingAllListResponse(
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetCreatorFollowingAllListItem> @SerializedName("items") val items: List<GetCreatorFollowingAllListItem>
) )
@Keep
data class GetCreatorFollowingAllListItem( data class GetCreatorFollowingAllListItem(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live package kr.co.vividnext.sodalive.live
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetRoomListResponse( data class GetRoomListResponse(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,

View File

@ -163,12 +163,14 @@ class LiveRepository(
roomId: Long, roomId: Long,
can: Int, can: Int,
message: String, message: String,
isSecret: Boolean,
token: String token: String
): Single<ApiResponse<LiveRoomDonationResponse>> { ): Single<ApiResponse<LiveRoomDonationResponse>> {
return api.donation( return api.donation(
request = LiveRoomDonationRequest( request = LiveRoomDonationRequest(
roomId = roomId, roomId = roomId,
can = can, can = can,
isSecret = isSecret,
message = message, message = message,
container = "aos" container = "aos"
), ),

View File

@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.live package kr.co.vividnext.sodalive.live
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.common.ApiResponse import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
import kr.co.vividnext.sodalive.settings.event.GetEventResponse import kr.co.vividnext.sodalive.settings.event.GetEventResponse
@Keep
data class LiveSummary( data class LiveSummary(
@SerializedName("liveNow") val liveNow: ApiResponse<List<GetRoomListResponse>>, @SerializedName("liveNow") val liveNow: ApiResponse<List<GetRoomListResponse>>,
@SerializedName("liveReservation") val liveReservation: ApiResponse<List<GetRoomListResponse>>, @SerializedName("liveReservation") val liveReservation: ApiResponse<List<GetRoomListResponse>>,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.recommend package kr.co.vividnext.sodalive.live.recommend
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetRecommendLiveResponse( data class GetRecommendLiveResponse(
@SerializedName("imageUrl") @SerializedName("imageUrl")
val imageUrl: String, val imageUrl: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.recommend_channel package kr.co.vividnext.sodalive.live.recommend_channel
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetRecommendChannelResponse( data class GetRecommendChannelResponse(
@SerializedName("creatorId") @SerializedName("creatorId")
val creatorId: Long, val creatorId: Long,

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.live.reservation package kr.co.vividnext.sodalive.live.reservation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import java.util.TimeZone import java.util.TimeZone
@Keep
data class MakeLiveReservationRequest( data class MakeLiveReservationRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("container") val container: String = "aos", @SerializedName("container") val container: String = "aos",

View File

@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.live.reservation package kr.co.vividnext.sodalive.live.reservation
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
@Keep
data class MakeLiveReservationResponse( data class MakeLiveReservationResponse(
@SerializedName("reservationId") val reservationId: Long, @SerializedName("reservationId") val reservationId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.reservation_status package kr.co.vividnext.sodalive.live.reservation_status
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CancelLiveReservationRequest( data class CancelLiveReservationRequest(
@SerializedName("reservationId") @SerializedName("reservationId")
val reservationId: Long, val reservationId: Long,

View File

@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.live.reservation_status package kr.co.vividnext.sodalive.live.reservation_status
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
@Keep
data class GetLiveReservationResponse( data class GetLiveReservationResponse(
@SerializedName("reservationId") val reservationId: Long, @SerializedName("reservationId") val reservationId: Long,
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room package kr.co.vividnext.sodalive.live.room
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CancelLiveRequest( data class CancelLiveRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("reason") val reason: String @SerializedName("reason") val reason: String

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room package kr.co.vividnext.sodalive.live.room
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class EnterOrQuitLiveRoomRequest( data class EnterOrQuitLiveRoomRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("container") val container: String = "aos", @SerializedName("container") val container: String = "aos",

View File

@ -249,6 +249,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
viewModel.getMemberCan() viewModel.getMemberCan()
viewModel.getRoomInfo(roomId) viewModel.getRoomInfo(roomId)
viewModel.getBlockedMemberIdList()
binding.etChat.setOnFocusChangeListener { view, hasFocus -> binding.etChat.setOnFocusChangeListener { view, hasFocus ->
if (isNoChatting && hasFocus) { if (isNoChatting && hasFocus) {
@ -464,10 +465,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
binding.flDonation.setOnClickListener { binding.flDonation.setOnClickListener {
val dialog = LiveRoomDonationDialog( val dialog = LiveRoomDonationDialog(
this, this,
LayoutInflater.from(this) LayoutInflater.from(this),
) { can, message -> isLiveDonation = true
) { can, message, isSecret ->
if (can > 0) { if (can > 0) {
donation(can, message) donation(can, message, isSecret)
} else { } else {
showToast("1캔 이상 후원하실 수 있습니다.") showToast("1캔 이상 후원하실 수 있습니다.")
} }
@ -521,6 +523,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
when (it.itemId) { when (it.itemId) {
R.id.menu_user_block -> { R.id.menu_user_block -> {
viewModel.memberUnBlock(userId) viewModel.memberUnBlock(userId)
viewModel.removeBlockedMember(memberId = userId)
} }
R.id.menu_user_report -> { R.id.menu_user_report -> {
@ -560,18 +563,29 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
private fun showMemberBlockDialog(userId: Long, nickname: String) { private fun showMemberBlockDialog(userId: Long, nickname: String) {
val message = if (SharedPreferenceManager.role == MemberRole.CREATOR.name) {
"""
${nickname}님을 차단하시겠습니까?
사용자를 차단하면 사용자는 아래 기능이 제한됩니다.
- 내가 개설한 라이브 입장 불가
- 나에게 메시지 보내기 불가
- 채널의 팬Talk 작성불가
""".trimIndent()
} else {
"""
${nickname}님을 차단하시겠습니까?
- 사용자를 차단하면 '차단한 사용자의 라이브 채팅' 보이지 않습니다.
""".trimIndent()
}
val dialog = AlertDialog.Builder(this) val dialog = AlertDialog.Builder(this)
dialog.setTitle("사용자 차단") dialog.setTitle("사용자 차단")
dialog.setMessage( dialog.setMessage(message)
"${nickname}님을 차단하시겠습니까?\n\n" +
"사용자를 차단하면 사용자는 아래 기능이 제한됩니다.\n" +
"- 내가 개설한 라이브 입장 불가\n" +
"- 나에게 메시지 보내기 불가\n" +
"- 내 채널의 팬Talk 작성불가"
)
dialog.setPositiveButton("차단") { _, _ -> dialog.setPositiveButton("차단") { _, _ ->
roomUserProfileDialog.dismiss() roomUserProfileDialog.dismiss()
viewModel.memberBlock(userId) { viewModel.memberBlock(userId) {
viewModel.addBlockedMember(memberId = userId)
if (viewModel.roomInfoResponse.creatorId == SharedPreferenceManager.userId) { if (viewModel.roomInfoResponse.creatorId == SharedPreferenceManager.userId) {
kickOut(userId) kickOut(userId)
} }
@ -703,37 +717,35 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
View.GONE View.GONE
} }
if ( binding.flDonationMessageList.setOnClickListener {
response.creatorId == SharedPreferenceManager.userId && LiveRoomDonationMessageDialog(
SharedPreferenceManager.role == MemberRole.CREATOR.name layoutInflater = LayoutInflater.from(this),
) { creatorId = response.creatorId,
binding.flDonationMessageList.visibility = View.VISIBLE activity = this,
binding.flDonationMessageList.setOnClickListener { donationMessageListLiveData = donationMessageViewModel
LiveRoomDonationMessageDialog( .donationMessageListLiveData,
layoutInflater = LayoutInflater.from(this), donationMessageCountLiveData = donationMessageViewModel
activity = this, .donationMessageCountLiveData,
donationMessageListLiveData = donationMessageViewModel getDonationMessageList = {
.donationMessageListLiveData, donationMessageViewModel.getDonationMessageList(roomId = roomId)
donationMessageCountLiveData = donationMessageViewModel },
.donationMessageCountLiveData, deleteDonationMessage = {
getDonationMessageList = { if (
donationMessageViewModel.getDonationMessageList(roomId = roomId) response.creatorId == SharedPreferenceManager.userId &&
}, SharedPreferenceManager.role == MemberRole.CREATOR.name
deleteDonationMessage = { ) {
donationMessageViewModel.deleteDonationMessage( donationMessageViewModel.deleteDonationMessage(
roomId = roomId, roomId = roomId,
uuid = it uuid = it
) )
},
copyMessage = {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
clipboard.setPrimaryClip(ClipData.newPlainText(it, it))
showToast("후원 히스토리가 복사되었습니다.")
} }
).show() },
} copyMessage = {
} else { val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
binding.flDonationMessageList.visibility = View.GONE clipboard.setPrimaryClip(ClipData.newPlainText(it, it))
showToast("후원 히스토리가 복사되었습니다.")
}
).show()
} }
speakerListAdapter.managerId = response.creatorId speakerListAdapter.managerId = response.creatorId
@ -1258,6 +1270,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
agora.muteAllRemoteAudioStreams(isSpeakerMute) agora.muteAllRemoteAudioStreams(isSpeakerMute)
} }
@SuppressLint("SetTextI18n")
private fun inputChat() { private fun inputChat() {
val nickname = viewModel.getUserNickname(SharedPreferenceManager.userId.toInt()) val nickname = viewModel.getUserNickname(SharedPreferenceManager.userId.toInt())
val profileUrl = viewModel.getUserProfileUrl(SharedPreferenceManager.userId.toInt()) val profileUrl = viewModel.getUserProfileUrl(SharedPreferenceManager.userId.toInt())
@ -1306,13 +1319,21 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
} }
private fun donation(can: Int, message: String) { private fun donation(can: Int, message: String, isSecret: Boolean) {
val rawMessage = "${can}캔을 후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99" val rawMessage = if (isSecret) {
"${can}캔을 비밀후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99"
} else {
"${can}캔을 후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99"
}
viewModel.donation(roomId, can, message) { signature -> viewModel.donation(roomId, can, message, isSecret) { signature ->
val donationRawMessage = Gson().toJson( val donationRawMessage = Gson().toJson(
LiveRoomChatRawMessage( LiveRoomChatRawMessage(
type = LiveRoomChatRawMessageType.DONATION, type = if (isSecret) {
LiveRoomChatRawMessageType.SECRET_DONATION
} else {
LiveRoomChatRawMessageType.DONATION
},
message = rawMessage, message = rawMessage,
can = can, can = can,
signature = signature, signature = signature,
@ -1321,9 +1342,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
) )
agora.sendRawMessageToGroup( if (isSecret) {
rawMessage = donationRawMessage.toByteArray(), agora.sendRawMessageToPeer(
onSuccess = { receiverUid = viewModel.roomInfoResponse.creatorId.toString(),
rawMessage = donationRawMessage.toByteArray()
) {
handler.post { handler.post {
val nickname = val nickname =
viewModel.getUserNickname(SharedPreferenceManager.userId.toInt()) viewModel.getUserNickname(SharedPreferenceManager.userId.toInt())
@ -1339,14 +1362,37 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
) )
invalidateChat() invalidateChat()
viewModel.addDonationCan(can)
addSignature(signature) addSignature(signature)
} }
},
onFailure = {
viewModel.refundDonation(roomId)
} }
) } else {
agora.sendRawMessageToGroup(
rawMessage = donationRawMessage.toByteArray(),
onSuccess = {
handler.post {
val nickname =
viewModel.getUserNickname(SharedPreferenceManager.userId.toInt())
val profileUrl =
viewModel.getUserProfileUrl(SharedPreferenceManager.userId.toInt())
chatAdapter.items.add(
LiveRoomDonationChat(
profileUrl,
nickname,
rawMessage,
can,
donationMessage = message
)
)
invalidateChat()
viewModel.addDonationCan(can)
addSignature(signature)
}
},
onFailure = {
viewModel.refundDonation(roomId)
}
)
}
} }
} }
@ -1492,22 +1538,27 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
viewModel.addDonationCan(rawMessage.can) viewModel.addDonationCan(rawMessage.can)
} }
} }
else -> {}
} }
} else { } else {
val chat = message.text val memberId = fromMember.userId.toLong()
if (viewModel.isNotBlockedMember(memberId)) {
val chat = message.text
if (chat.isNotBlank()) { if (chat.isNotBlank()) {
handler.post { handler.post {
chatAdapter.items.add( chatAdapter.items.add(
LiveRoomNormalChat( LiveRoomNormalChat(
userId = fromMember.userId.toLong(), userId = memberId,
profileUrl = profileUrl, profileUrl = profileUrl,
nickname = nickname, nickname = nickname,
rank = rank, rank = rank,
chat = chat chat = chat
)
) )
) invalidateChat()
invalidateChat() }
} }
} }
} }
@ -1790,6 +1841,35 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
return return
} }
val message = Gson().fromJson(
rawMessage,
LiveRoomChatRawMessage::class.java
)
if (message.type == LiveRoomChatRawMessageType.SECRET_DONATION) {
val nickname = viewModel.getUserNickname(peerId.toInt())
val profileUrl = viewModel.getUserProfileUrl(peerId.toInt())
handler.post {
chatAdapter.items.add(
LiveRoomDonationChat(
profileUrl,
nickname,
message.message,
message.can,
message.donationMessage ?: ""
)
)
invalidateChat()
if (message.signature != null) {
addSignature(message.signature)
} else if (message.signatureImageUrl != null) {
addSignatureImage(message.signatureImageUrl)
}
}
}
} }
} }
} }

View File

@ -90,6 +90,8 @@ class LiveRoomViewModel(
lateinit var getRealPathFromURI: (Uri) -> String? lateinit var getRealPathFromURI: (Uri) -> String?
private val blockedMemberIdList: MutableList<Long> = mutableListOf()
fun getUserNickname(memberId: Int): String { fun getUserNickname(memberId: Int): String {
for (manager in roomInfoResponse.managerList) { for (manager in roomInfoResponse.managerList) {
if (manager.id.toInt() == memberId) { if (manager.id.toInt() == memberId) {
@ -236,6 +238,35 @@ class LiveRoomViewModel(
return memberId == roomInfoResponse.creatorId.toInt() return memberId == roomInfoResponse.creatorId.toInt()
} }
fun isNotBlockedMember(memberId: Long): Boolean {
return !blockedMemberIdList.contains(memberId)
}
fun addBlockedMember(memberId: Long) {
blockedMemberIdList.add(memberId)
}
fun removeBlockedMember(memberId: Long) {
blockedMemberIdList.remove(memberId)
}
fun getBlockedMemberIdList() {
compositeDisposable.add(
userRepository.getBlockedMemberIdList(token = "Bearer ${SharedPreferenceManager.token}")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
this.blockedMemberIdList.clear()
this.blockedMemberIdList.addAll(it.data)
}
},
{}
)
)
}
fun getMemberCan() { fun getMemberCan() {
compositeDisposable.add( compositeDisposable.add(
userRepository.getMemberInfo(token = "Bearer ${SharedPreferenceManager.token}") userRepository.getMemberInfo(token = "Bearer ${SharedPreferenceManager.token}")
@ -247,8 +278,7 @@ class LiveRoomViewModel(
SharedPreferenceManager.can = it.data.can SharedPreferenceManager.can = it.data.can
} }
}, },
{ {}
}
) )
) )
} }
@ -521,11 +551,18 @@ class LiveRoomViewModel(
roomId: Long, roomId: Long,
can: Int, can: Int,
message: String, message: String,
isSecret: Boolean,
onSuccess: (LiveRoomDonationResponse?) -> Unit onSuccess: (LiveRoomDonationResponse?) -> Unit
) { ) {
_isLoading.postValue(true) _isLoading.postValue(true)
compositeDisposable.add( compositeDisposable.add(
repository.donation(roomId, can, message, "Bearer ${SharedPreferenceManager.token}") repository.donation(
roomId,
can,
message,
isSecret,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room package kr.co.vividnext.sodalive.live.room
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class SetManagerOrSpeakerOrAudienceRequest( data class SetManagerOrSpeakerOrAudienceRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("memberId") val memberId: Long @SerializedName("memberId") val memberId: Long

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.live.room package kr.co.vividnext.sodalive.live.room
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import java.util.TimeZone import java.util.TimeZone
@Keep
data class StartLiveRequest( data class StartLiveRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("timezone") val timezone: String = TimeZone.getDefault().id, @SerializedName("timezone") val timezone: String = TimeZone.getDefault().id,

View File

@ -9,6 +9,7 @@ import android.text.TextUtils
import android.text.style.ForegroundColorSpan import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan import android.text.style.StyleSpan
import android.view.View import android.view.View
import androidx.annotation.Keep
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.setPadding import androidx.core.view.setPadding
@ -46,6 +47,7 @@ abstract class LiveRoomChat {
) )
} }
@Keep
data class LiveRoomJoinChat( data class LiveRoomJoinChat(
val nickname: String val nickname: String
) : LiveRoomChat() { ) : LiveRoomChat() {
@ -77,6 +79,7 @@ data class LiveRoomJoinChat(
} }
} }
@Keep
data class LiveRoomDonationStatusChat( data class LiveRoomDonationStatusChat(
val response: GetLiveRoomDonationStatusResponse? = null, val response: GetLiveRoomDonationStatusResponse? = null,
val donationStatusString: String? = null val donationStatusString: String? = null
@ -146,6 +149,7 @@ data class LiveRoomDonationStatusChat(
} }
} }
@Keep
data class LiveRoomNormalChat( data class LiveRoomNormalChat(
@SerializedName("userId") val userId: Long, @SerializedName("userId") val userId: Long,
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@ -238,6 +242,7 @@ data class LiveRoomNormalChat(
} }
} }
@Keep
data class LiveRoomDonationChat( data class LiveRoomDonationChat(
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@ -299,41 +304,48 @@ data class LiveRoomDonationChat(
itemBinding.llMessageBg.setPadding(0) itemBinding.llMessageBg.setPadding(0)
itemBinding.llMessageBg.background = null itemBinding.llMessageBg.background = null
itemBinding.root.setBackgroundResource( if (spChat.contains("비밀")) {
when { itemBinding.root.setBackgroundResource(
can >= 10000 -> { R.drawable.bg_round_corner_6_7_cc333333
R.drawable.bg_round_corner_6_7_ccc25264 )
} } else {
itemBinding.root.setBackgroundResource(
when {
can >= 10000 -> {
R.drawable.bg_round_corner_6_7_ccc25264
}
can >= 5000 -> { can >= 5000 -> {
R.drawable.bg_round_corner_6_7_ccd85e37 R.drawable.bg_round_corner_6_7_ccd85e37
} }
can >= 1000 -> { can >= 1000 -> {
R.drawable.bg_round_corner_6_7_ccd38c38 R.drawable.bg_round_corner_6_7_ccd38c38
} }
can >= 500 -> { can >= 500 -> {
R.drawable.bg_round_corner_6_7_cc59548f R.drawable.bg_round_corner_6_7_cc59548f
} }
can >= 100 -> { can >= 100 -> {
R.drawable.bg_round_corner_6_7_cc4d6aa4 R.drawable.bg_round_corner_6_7_cc4d6aa4
} }
can >= 50 -> { can >= 50 -> {
R.drawable.bg_round_corner_6_7_cc2d7390 R.drawable.bg_round_corner_6_7_cc2d7390
} }
else -> { else -> {
R.drawable.bg_round_corner_6_7_cc548f7d R.drawable.bg_round_corner_6_7_cc548f7d
}
} }
} )
) }
itemBinding.root.setPadding(33) itemBinding.root.setPadding(33)
} }
} }
@Keep
data class LiveRoomRouletteDonationChat( data class LiveRoomRouletteDonationChat(
@SerializedName("profileUrl") val profileUrl: String, @SerializedName("profileUrl") val profileUrl: String,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.live.room.chat package kr.co.vividnext.sodalive.live.room.chat
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
@Keep
data class LiveRoomChatRawMessage( data class LiveRoomChatRawMessage(
@SerializedName("type") val type: LiveRoomChatRawMessageType, @SerializedName("type") val type: LiveRoomChatRawMessageType,
@SerializedName("message") val message: String, @SerializedName("message") val message: String,
@ -16,14 +18,22 @@ data class LiveRoomChatRawMessage(
enum class LiveRoomChatRawMessageType { enum class LiveRoomChatRawMessageType {
@SerializedName("DONATION") @SerializedName("DONATION")
DONATION, DONATION,
@SerializedName("SECRET_DONATION")
SECRET_DONATION,
@SerializedName("SET_MANAGER") @SerializedName("SET_MANAGER")
SET_MANAGER, SET_MANAGER,
@SerializedName("EDIT_ROOM_INFO") @SerializedName("EDIT_ROOM_INFO")
EDIT_ROOM_INFO, EDIT_ROOM_INFO,
@SerializedName("DONATION_STATUS") @SerializedName("DONATION_STATUS")
DONATION_STATUS, DONATION_STATUS,
@SerializedName("TOGGLE_ROULETTE") @SerializedName("TOGGLE_ROULETTE")
TOGGLE_ROULETTE, TOGGLE_ROULETTE,
@SerializedName("ROULETTE_DONATION") @SerializedName("ROULETTE_DONATION")
ROULETTE_DONATION ROULETTE_DONATION
} }

View File

@ -1,8 +1,10 @@
package kr.co.vividnext.sodalive.live.room.create package kr.co.vividnext.sodalive.live.room.create
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.live.room.LiveRoomType import kr.co.vividnext.sodalive.live.room.LiveRoomType
@Keep
data class CreateLiveRoomRequest( data class CreateLiveRoomRequest(
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("price") val price: Int = 0, @SerializedName("price") val price: Int = 0,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room.create package kr.co.vividnext.sodalive.live.room.create
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class CreateLiveRoomResponse( data class CreateLiveRoomResponse(
@SerializedName("id") val id: Long?, @SerializedName("id") val id: Long?,
@SerializedName("channelName") val channelName: String? @SerializedName("channelName") val channelName: String?

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room.create package kr.co.vividnext.sodalive.live.room.create
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetRecentRoomInfoResponse( data class GetRecentRoomInfoResponse(
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("notice") val notice: String, @SerializedName("notice") val notice: String,

View File

@ -1,10 +1,12 @@
package kr.co.vividnext.sodalive.live.room.detail package kr.co.vividnext.sodalive.live.room.detail
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@Parcelize @Parcelize
@Keep
data class GetRoomDetailResponse( data class GetRoomDetailResponse(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("price") val price: Int, @SerializedName("price") val price: Int,
@ -22,9 +24,10 @@ data class GetRoomDetailResponse(
@SerializedName("numberOfParticipantsTotal") val numberOfParticipantsTotal: Int, @SerializedName("numberOfParticipantsTotal") val numberOfParticipantsTotal: Int,
@SerializedName("manager") val manager: GetRoomDetailManager, @SerializedName("manager") val manager: GetRoomDetailManager,
@SerializedName("participatingUsers") val participatingUsers: List<GetRoomDetailUser> @SerializedName("participatingUsers") val participatingUsers: List<GetRoomDetailUser>
): Parcelable ) : Parcelable
@Parcelize @Parcelize
@Keep
data class GetRoomDetailManager( data class GetRoomDetailManager(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@ -38,6 +41,7 @@ data class GetRoomDetailManager(
) : Parcelable ) : Parcelable
@Parcelize @Parcelize
@Keep
data class GetRoomDetailUser( data class GetRoomDetailUser(
@SerializedName("id") val id: Long, @SerializedName("id") val id: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.live.room.donation package kr.co.vividnext.sodalive.live.room.donation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class DeleteLiveRoomDonationMessage( data class DeleteLiveRoomDonationMessage(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("messageUUID") val messageUUID: String @SerializedName("messageUUID") val messageUUID: String

View File

@ -1,13 +1,16 @@
package kr.co.vividnext.sodalive.live.room.donation package kr.co.vividnext.sodalive.live.room.donation
import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep
data class GetLiveRoomDonationStatusResponse( data class GetLiveRoomDonationStatusResponse(
@SerializedName("donationList") val donationList: List<GetLiveRoomDonationItem>, @SerializedName("donationList") val donationList: List<GetLiveRoomDonationItem>,
@SerializedName("totalCount") val totalCount: Int, @SerializedName("totalCount") val totalCount: Int,
@SerializedName("totalCan") val totalCan: Int @SerializedName("totalCan") val totalCan: Int
) )
@Keep
data class GetLiveRoomDonationItem( data class GetLiveRoomDonationItem(
@SerializedName("profileImage") val profileImage: String, @SerializedName("profileImage") val profileImage: String,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,

Some files were not shown because too many files have changed in this diff Show More