Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fb727d0ee | ||
|
|
48f2a0e543 | ||
|
|
c261b32148 | ||
|
|
cc8f271f44 | ||
|
|
086af8a366 | ||
|
|
5e114e18a0 | ||
|
|
330148821c | ||
|
|
1d38912474 | ||
|
|
2e67e092a5 | ||
|
|
8749ae9ae7 | ||
|
|
81b5a1dafc | ||
|
|
582b4fe703 | ||
|
|
287ba0b01b | ||
|
|
7b11185db4 | ||
|
|
5029332023 | ||
|
|
f891c15eb9 | ||
|
|
9bb0a6512e | ||
|
|
4bc725bdf2 | ||
|
|
5e1a7e9ace | ||
|
|
e57998654b | ||
|
|
7c2ea3a02b | ||
|
|
a6c63b71b9 | ||
|
|
4f6b235d60 | ||
|
|
127e5fc147 | ||
|
|
be847b4600 | ||
|
|
c6bee79f8e | ||
|
|
e9bb2c6dd8 | ||
|
|
9de82916dd | ||
|
|
f454596df5 | ||
|
|
22a24cb1c1 | ||
|
|
1f8d0beb2f | ||
|
|
10886153b2 | ||
|
|
1f88d721d7 | ||
|
|
9939910c71 | ||
|
|
4f4ae62026 | ||
|
|
3560d7bf89 | ||
|
|
5cfc42774c | ||
|
|
4130ab296e | ||
|
|
87d9a1d377 | ||
|
|
70f4266ed8 | ||
|
|
7a9c2512cf | ||
|
|
a04704db40 | ||
|
|
ec808cfd0c | ||
|
|
817234a80b | ||
|
|
88cb581231 |
@@ -86,8 +86,8 @@ android {
|
|||||||
applicationId "kr.co.vividnext.sodalive"
|
applicationId "kr.co.vividnext.sodalive"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 35
|
targetSdk 35
|
||||||
versionCode 246
|
versionCode 254
|
||||||
versionName "1.56.1"
|
versionName "1.56.3"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">VoiceOn-Test</string>
|
<string name="app_name">SodaLive-Test</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">ボイスオン-テスト</string>
|
<string name="app_name">ソーダライブ-テスト</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">보이스온-테스트</string>
|
<string name="app_name">소다라이브-테스트</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -68,6 +68,9 @@
|
|||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:replace="android:allowBackup"
|
tools:replace="android:allowBackup"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name="kr.co.vividnext.sodalive.v2.main.chat.recipient.DmRecipientPickerActivity"
|
||||||
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".main.DeepLinkActivity"
|
android:name=".main.DeepLinkActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
@@ -174,8 +177,8 @@
|
|||||||
<activity android:name=".settings.notification.NotificationSettingsActivity" />
|
<activity android:name=".settings.notification.NotificationSettingsActivity" />
|
||||||
<activity android:name=".settings.notification.NotificationReceiveSettingsActivity" />
|
<activity android:name=".settings.notification.NotificationReceiveSettingsActivity" />
|
||||||
<activity android:name=".settings.ContentSettingsActivity" />
|
<activity android:name=".settings.ContentSettingsActivity" />
|
||||||
<activity android:name=".live.reservation_status.LiveReservationStatusActivity" />
|
<activity android:name=".live.reservation.status.LiveReservationStatusActivity" />
|
||||||
<activity android:name=".live.reservation_status.LiveReservationCancelActivity" />
|
<activity android:name=".live.reservation.status.LiveReservationCancelActivity" />
|
||||||
<activity android:name=".audio_content.AudioContentActivity" />
|
<activity android:name=".audio_content.AudioContentActivity" />
|
||||||
<activity android:name=".audio_content.detail.AudioContentDetailActivity" />
|
<activity android:name=".audio_content.detail.AudioContentDetailActivity" />
|
||||||
<activity android:name=".audio_content.modify.AudioContentModifyActivity" />
|
<activity android:name=".audio_content.modify.AudioContentModifyActivity" />
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class SeriesListAllActivity : BaseActivity<ActivitySeriesListAllBinding>(
|
|||||||
if (intent.getBooleanExtra(Constants.EXTRA_IS_COMPLETED, false)) {
|
if (intent.getBooleanExtra(Constants.EXTRA_IS_COMPLETED, false)) {
|
||||||
getString(R.string.screen_series_main_completed_title)
|
getString(R.string.screen_series_main_completed_title)
|
||||||
} else if (intent.getBooleanExtra(Constants.EXTRA_IS_ORIGINAL, false)) {
|
} else if (intent.getBooleanExtra(Constants.EXTRA_IS_ORIGINAL, false)) {
|
||||||
getString(R.string.voiceon_original_only)
|
getString(R.string.sodalive_original_only)
|
||||||
} else {
|
} else {
|
||||||
getString(R.string.screen_series_main_title)
|
getString(R.string.screen_series_main_title)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 캐릭터 정보 모델
|
* 소다라이브 - 채팅방 캐릭터 정보 모델
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 모델 (서버 응답 기반)
|
* 소다라이브 - 채팅 메시지 모델 (서버 응답 기반)
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 메시지 어댑터 (4.2 ViewHolder 구현)
|
* 소다라이브 - 채팅방 메시지 어댑터 (4.2 ViewHolder 구현)
|
||||||
* - 4가지 ViewType 지원
|
* - 4가지 ViewType 지원
|
||||||
* - ViewHolder 바인딩 로직 구현: 시간 포맷팅, 상태 표시, 이미지 로딩, 그룹화 처리, 타이핑 애니메이션
|
* - ViewHolder 바인딩 로직 구현: 시간 포맷팅, 상태 표시, 이미지 로딩, 그룹화 처리, 타이핑 애니메이션
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 Entity/도메인 매퍼
|
* 소다라이브 - 채팅 메시지 Entity/도메인 매퍼
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 매핑 유틸리티
|
* 소다라이브 - 채팅 메시지 매핑 유틸리티
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 점진적 메시지 로딩 응답 DTO
|
* 소다라이브 - 점진적 메시지 로딩 응답 DTO
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 ChatRepository (Repository 패턴)
|
* 소다라이브 - 채팅방 ChatRepository (Repository 패턴)
|
||||||
* - 로컬 DB(Room) + 네트워크(TalkApi) 통합 관리
|
* - 로컬 DB(Room) + 네트워크(TalkApi) 통합 관리
|
||||||
* - 통합 채팅방 입장 API 호출 및 로컬 동기화
|
* - 통합 채팅방 입장 API 호출 및 로컬 동기화
|
||||||
* - 점진적 메시지 로딩
|
* - 점진적 메시지 로딩
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 통합 채팅방 입장 응답 DTO
|
* 소다라이브 - 통합 채팅방 입장 응답 DTO
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 메시지 전송 상태 Enum
|
* 소다라이브 - 채팅방 메시지 전송 상태 Enum
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 메시지 타입 Enum
|
* 소다라이브 - 채팅방 메시지 타입 Enum
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 모델 (서버 응답 전용 DTO)
|
* 소다라이브 - 채팅 메시지 모델 (서버 응답 전용 DTO)
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room
|
package kr.co.vividnext.sodalive.chat.talk.room
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 Room TypeConverters
|
* 소다라이브 - 채팅 메시지 Room TypeConverters
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room.db
|
package kr.co.vividnext.sodalive.chat.talk.room.db
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 DAO
|
* 소다라이브 - 채팅 메시지 DAO
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room.db
|
package kr.co.vividnext.sodalive.chat.talk.room.db
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅방 Room Database (ChatMessage 테이블 포함)
|
* 소다라이브 - 채팅방 Room Database (ChatMessage 테이블 포함)
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room.db
|
package kr.co.vividnext.sodalive.chat.talk.room.db
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* 보이스온 - 채팅 메시지 Room Entity
|
* 소다라이브 - 채팅 메시지 Room Entity
|
||||||
*/
|
*/
|
||||||
package kr.co.vividnext.sodalive.chat.talk.room.db
|
package kr.co.vividnext.sodalive.chat.talk.room.db
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,28 @@ object SharedPreferenceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||||
|
fun resetCanForTest() {
|
||||||
|
ensureInitialized()
|
||||||
|
runBlocking {
|
||||||
|
dataStore.edit { preferences ->
|
||||||
|
removeByName(preferences, Constants.PREF_CAN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferenceState.update { state -> state - Constants.PREF_CAN }
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||||
|
fun setCanForTest(value: Int) {
|
||||||
|
ensureInitialized()
|
||||||
|
runBlocking {
|
||||||
|
dataStore.edit { preferences ->
|
||||||
|
preferences[intPreferencesKey(Constants.PREF_CAN)] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferenceState.update { state -> state + (Constants.PREF_CAN to value) }
|
||||||
|
}
|
||||||
|
|
||||||
fun clear() {
|
fun clear() {
|
||||||
ensureInitialized()
|
ensureInitialized()
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ import kr.co.vividnext.sodalive.live.LiveRepository
|
|||||||
import kr.co.vividnext.sodalive.live.LiveViewModel
|
import kr.co.vividnext.sodalive.live.LiveViewModel
|
||||||
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
|
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
|
||||||
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
|
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
|
||||||
import kr.co.vividnext.sodalive.live.reservation_status.LiveReservationStatusViewModel
|
import kr.co.vividnext.sodalive.live.reservation.status.LiveReservationStatusViewModel
|
||||||
import kr.co.vividnext.sodalive.live.room.LiveRoomViewModel
|
import kr.co.vividnext.sodalive.live.room.LiveRoomViewModel
|
||||||
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
|
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
|
||||||
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailViewModel
|
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailViewModel
|
||||||
@@ -463,13 +463,13 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
viewModel { CreatorChannelLiveViewModel(get()) }
|
viewModel { CreatorChannelLiveViewModel(get()) }
|
||||||
viewModel { CreatorChannelAudioViewModel(get()) }
|
viewModel { CreatorChannelAudioViewModel(get()) }
|
||||||
viewModel { CreatorChannelSeriesViewModel(get()) }
|
viewModel { CreatorChannelSeriesViewModel(get()) }
|
||||||
viewModel { CreatorChannelCommunityViewModel(get(), get()) }
|
viewModel { CreatorChannelCommunityViewModel(get()) }
|
||||||
viewModel { CreatorChannelCommunityDetailViewModel(get(), get(), get()) }
|
viewModel { CreatorChannelCommunityDetailViewModel(get(), get()) }
|
||||||
viewModel { CreatorChannelCommunityReplyViewModel(get(), get(), get()) }
|
viewModel { CreatorChannelCommunityReplyViewModel(get(), get()) }
|
||||||
viewModel { CreatorChannelFanTalkViewModel(get(), get()) }
|
viewModel { CreatorChannelFanTalkViewModel(get()) }
|
||||||
viewModel { CreatorChannelFanTalkDetailViewModel(get(), get()) }
|
viewModel { CreatorChannelFanTalkDetailViewModel(get()) }
|
||||||
viewModel { CreatorChannelFanTalkWriteViewModel(get()) }
|
viewModel { CreatorChannelFanTalkWriteViewModel(get()) }
|
||||||
viewModel { CreatorChannelDonationViewModel(get(), get()) }
|
viewModel { CreatorChannelDonationViewModel(get()) }
|
||||||
viewModel { PushNotificationListViewModel(get()) }
|
viewModel { PushNotificationListViewModel(get()) }
|
||||||
viewModel { CharacterTabViewModel(get()) }
|
viewModel { CharacterTabViewModel(get()) }
|
||||||
viewModel { CharacterDetailViewModel(get()) }
|
viewModel { CharacterDetailViewModel(get()) }
|
||||||
|
|||||||
@@ -359,7 +359,7 @@ class UserProfileViewModel(
|
|||||||
"deep_link_sub5" to "$userId"
|
"deep_link_sub5" to "$userId"
|
||||||
)
|
)
|
||||||
val shareUrl = Utils.createOneLinkUrl(params = params)
|
val shareUrl = Utils.createOneLinkUrl(params = params)
|
||||||
onSuccess("보이스온 ${nickname}님의 채널입니다.\n$shareUrl")
|
onSuccess("소다라이브 ${nickname}님의 채널입니다.\n$shareUrl")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getChannelDonationList(creatorId: Long) {
|
fun getChannelDonationList(creatorId: Long) {
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(FragmentHomeBinding::infl
|
|||||||
recyclerView.adapter = originalSeriesAdapter
|
recyclerView.adapter = originalSeriesAdapter
|
||||||
|
|
||||||
binding.tvSeriesOriginalAll.setOnClickListener {
|
binding.tvSeriesOriginalAll.setOnClickListener {
|
||||||
// ‘오직 보이스온에서만’ 전체보기: isOriginal=true로 시리즈 전체보기 화면 진입
|
// ‘오직 소다라이브에서만’ 전체보기: isOriginal=true로 시리즈 전체보기 화면 진입
|
||||||
if (SharedPreferenceManager.token.isNotBlank()) {
|
if (SharedPreferenceManager.token.isNotBlank()) {
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(
|
Intent(
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import io.reactivex.rxjava3.core.Single
|
|||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
|
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
|
||||||
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationResponse
|
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationResponse
|
||||||
import kr.co.vividnext.sodalive.live.reservation_status.CancelLiveReservationRequest
|
import kr.co.vividnext.sodalive.live.reservation.status.CancelLiveReservationRequest
|
||||||
import kr.co.vividnext.sodalive.live.reservation_status.GetLiveReservationResponse
|
import kr.co.vividnext.sodalive.live.reservation.status.GetLiveReservationResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
|
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.EnterOrQuitLiveRoomRequest
|
import kr.co.vividnext.sodalive.live.room.EnterOrQuitLiveRoomRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import io.reactivex.rxjava3.core.Flowable
|
|||||||
import io.reactivex.rxjava3.core.Single
|
import io.reactivex.rxjava3.core.Single
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
|
import kr.co.vividnext.sodalive.live.reservation.MakeLiveReservationRequest
|
||||||
import kr.co.vividnext.sodalive.live.reservation_status.CancelLiveReservationRequest
|
import kr.co.vividnext.sodalive.live.reservation.status.CancelLiveReservationRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
|
import kr.co.vividnext.sodalive.live.room.CancelLiveRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.EnterOrQuitLiveRoomRequest
|
import kr.co.vividnext.sodalive.live.room.EnterOrQuitLiveRoomRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.vividnext.sodalive.live.reservation_status
|
package kr.co.vividnext.sodalive.live.reservation.status
|
||||||
|
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
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 androidx.annotation.Keep
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.vividnext.sodalive.live.reservation_status
|
package kr.co.vividnext.sodalive.live.reservation.status
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
@@ -18,10 +18,10 @@ import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
|||||||
import kr.co.vividnext.sodalive.databinding.ActivityLiveReservationCancelBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityLiveReservationCancelBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.main.MainActivity
|
|
||||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
|
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusActivity
|
||||||
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
||||||
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
|
import kr.co.vividnext.sodalive.settings.language.LocaleHelper
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
@@ -117,7 +117,7 @@ class LiveReservationCancelActivity : BaseActivity<ActivityLiveReservationCancel
|
|||||||
|
|
||||||
binding.tvOtherSudaReservation.setOnClickListener {
|
binding.tvOtherSudaReservation.setOnClickListener {
|
||||||
finishAffinity()
|
finishAffinity()
|
||||||
startActivity(Intent(applicationContext, MainActivity::class.java))
|
startActivity(Intent(applicationContext, MainV2Activity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvCheckCanStatus.setOnClickListener {
|
binding.tvCheckCanStatus.setOnClickListener {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.vividnext.sodalive.live.reservation_status
|
package kr.co.vividnext.sodalive.live.reservation.status
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.vividnext.sodalive.live.reservation_status
|
package kr.co.vividnext.sodalive.live.reservation.status
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package kr.co.vividnext.sodalive.live.reservation_status
|
package kr.co.vividnext.sodalive.live.reservation.status
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
@@ -120,13 +120,13 @@ import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
|||||||
import kr.co.vividnext.sodalive.live.roulette.RouletteSpinDialog
|
import kr.co.vividnext.sodalive.live.roulette.RouletteSpinDialog
|
||||||
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
||||||
import kr.co.vividnext.sodalive.main.DeepLinkActivity
|
import kr.co.vividnext.sodalive.main.DeepLinkActivity
|
||||||
import kr.co.vividnext.sodalive.main.MainActivity
|
|
||||||
import kr.co.vividnext.sodalive.report.ProfileReportDialog
|
import kr.co.vividnext.sodalive.report.ProfileReportDialog
|
||||||
import kr.co.vividnext.sodalive.report.ReportType
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
import kr.co.vividnext.sodalive.report.UserReportDialog
|
import kr.co.vividnext.sodalive.report.UserReportDialog
|
||||||
import kr.co.vividnext.sodalive.settings.ContentSettingsActivity
|
import kr.co.vividnext.sodalive.settings.ContentSettingsActivity
|
||||||
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
import kr.co.vividnext.sodalive.settings.language.LanguageManager
|
||||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.MainV2Activity
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -379,7 +379,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||||||
val bundle = intent?.getBundleExtra(Constants.EXTRA_DATA) ?: return
|
val bundle = intent?.getBundleExtra(Constants.EXTRA_DATA) ?: return
|
||||||
|
|
||||||
showDeepLinkNavigationDialog {
|
showDeepLinkNavigationDialog {
|
||||||
val nextIntent = Intent(applicationContext, MainActivity::class.java).apply {
|
val nextIntent = Intent(applicationContext, MainV2Activity::class.java).apply {
|
||||||
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
putExtra(Constants.EXTRA_DATA, bundle)
|
putExtra(Constants.EXTRA_DATA, bundle)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,12 +436,12 @@ class LiveRoomViewModel(
|
|||||||
|
|
||||||
val message = if (isPrivateRoom) {
|
val message = if (isPrivateRoom) {
|
||||||
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
||||||
"보이스온의 비공개라이브에 초대하였습니다.\n" +
|
"소다라이브의 비공개라이브에 초대하였습니다.\n" +
|
||||||
"※ 라이브 참여: $shareUrl\n" +
|
"※ 라이브 참여: $shareUrl\n" +
|
||||||
"(입장 비밀번호 : $password)"
|
"(입장 비밀번호 : $password)"
|
||||||
} else {
|
} else {
|
||||||
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
||||||
"보이스온의 공개라이브에 초대하였습니다.\n" +
|
"소다라이브의 공개라이브에 초대하였습니다.\n" +
|
||||||
"※ 라이브 참여: $shareUrl"
|
"※ 라이브 참여: $shareUrl"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ class MyPageFragment : BaseFragment<FragmentMyBinding>(FragmentMyBinding::inflat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ivIntroduceVoiceon.setOnClickListener {
|
binding.ivIntroduceSodalive.setOnClickListener {
|
||||||
val url = "https://blog.naver.com/sodalive_official"
|
val url = "https://blog.naver.com/sodalive_official"
|
||||||
if (URLUtil.isValidUrl(url)) {
|
if (URLUtil.isValidUrl(url)) {
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
|
startActivity(Intent(Intent.ACTION_VIEW, url.toUri()))
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ 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
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.common.Utils
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityPostMenuBottomSheetDialog
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityPostMenuBottomSheetDialog
|
||||||
@@ -230,6 +231,7 @@ class CreatorChannelActivity :
|
|||||||
private fun setupClickListeners() {
|
private fun setupClickListeners() {
|
||||||
binding.ivBack.setOnClickListener { finish() }
|
binding.ivBack.setOnClickListener { finish() }
|
||||||
binding.ivMore.setOnClickListener { onMoreClicked() }
|
binding.ivMore.setOnClickListener { onMoreClicked() }
|
||||||
|
binding.ivShare.setOnClickListener { shareCurrentCreatorChannel() }
|
||||||
binding.tvFollowerCount.setOnClickListener { onFollowerCountClicked() }
|
binding.tvFollowerCount.setOnClickListener { onFollowerCountClicked() }
|
||||||
binding.layoutFollowCapsule.setOnClickListener { onFollowCapsuleClicked() }
|
binding.layoutFollowCapsule.setOnClickListener { onFollowCapsuleClicked() }
|
||||||
binding.ivBell.setOnClickListener { onBellClicked() }
|
binding.ivBell.setOnClickListener { onBellClicked() }
|
||||||
@@ -291,9 +293,11 @@ class CreatorChannelActivity :
|
|||||||
binding.layoutFollowCapsule.visibility = View.GONE
|
binding.layoutFollowCapsule.visibility = View.GONE
|
||||||
binding.ivBell.visibility = View.GONE
|
binding.ivBell.visibility = View.GONE
|
||||||
binding.ivMore.visibility = View.GONE
|
binding.ivMore.visibility = View.GONE
|
||||||
|
binding.ivShare.visibility = View.VISIBLE
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.ivShare.visibility = View.GONE
|
||||||
binding.layoutFollowCapsule.visibility = View.VISIBLE
|
binding.layoutFollowCapsule.visibility = View.VISIBLE
|
||||||
binding.ivMore.visibility = View.VISIBLE
|
binding.ivMore.visibility = View.VISIBLE
|
||||||
val titleBarState = CreatorChannelTitleBarState.from(
|
val titleBarState = CreatorChannelTitleBarState.from(
|
||||||
@@ -435,12 +439,35 @@ class CreatorChannelActivity :
|
|||||||
if (header.isOwner) return
|
if (header.isOwner) return
|
||||||
|
|
||||||
CreatorChannelMoreBottomSheet.newInstance().apply {
|
CreatorChannelMoreBottomSheet.newInstance().apply {
|
||||||
|
onClickChannelShare = { shareCurrentCreatorChannel() }
|
||||||
onClickBlock = { showUserBlockDialog() }
|
onClickBlock = { showUserBlockDialog() }
|
||||||
onClickUserReport = { showUserReportDialog() }
|
onClickUserReport = { showUserReportDialog() }
|
||||||
onClickProfileReport = { showProfileReportDialog() }
|
onClickProfileReport = { showProfileReportDialog() }
|
||||||
}.show(supportFragmentManager, CreatorChannelMoreBottomSheet::class.java.simpleName)
|
}.show(supportFragmentManager, CreatorChannelMoreBottomSheet::class.java.simpleName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun shareCurrentCreatorChannel() {
|
||||||
|
val header = currentHeader ?: return
|
||||||
|
if (creatorId <= 0L) return
|
||||||
|
|
||||||
|
val nickname = header.nickname
|
||||||
|
val params = mapOf(
|
||||||
|
"af_dp" to "voiceon://",
|
||||||
|
"deep_link_value" to "channel",
|
||||||
|
"deep_link_sub5" to "$creatorId"
|
||||||
|
)
|
||||||
|
val shareUrl = Utils.createOneLinkUrl(params = params)
|
||||||
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
|
intent.type = "text/plain"
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, "소다라이브 ${nickname}님의 채널입니다.\n$shareUrl")
|
||||||
|
|
||||||
|
val shareIntent = Intent.createChooser(
|
||||||
|
intent,
|
||||||
|
getString(R.string.screen_user_profile_share_channel)
|
||||||
|
)
|
||||||
|
startActivity(shareIntent)
|
||||||
|
}
|
||||||
|
|
||||||
private fun showUserBlockDialog() {
|
private fun showUserBlockDialog() {
|
||||||
val nickname = currentHeader?.nickname.orEmpty()
|
val nickname = currentHeader?.nickname.orEmpty()
|
||||||
V2ModalDialog(
|
V2ModalDialog(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.databinding.DialogCreatorChannelMoreBinding
|
|||||||
|
|
||||||
class CreatorChannelMoreBottomSheet : BottomSheetDialogFragment() {
|
class CreatorChannelMoreBottomSheet : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
var onClickChannelShare: (() -> Unit)? = null
|
||||||
var onClickBlock: (() -> Unit)? = null
|
var onClickBlock: (() -> Unit)? = null
|
||||||
var onClickUserReport: (() -> Unit)? = null
|
var onClickUserReport: (() -> Unit)? = null
|
||||||
var onClickProfileReport: (() -> Unit)? = null
|
var onClickProfileReport: (() -> Unit)? = null
|
||||||
@@ -29,6 +30,10 @@ class CreatorChannelMoreBottomSheet : BottomSheetDialogFragment() {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val viewBinding = binding ?: return
|
val viewBinding = binding ?: return
|
||||||
|
|
||||||
|
viewBinding.tvChannelShare.setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
onClickChannelShare?.invoke()
|
||||||
|
}
|
||||||
viewBinding.tvUserBlock.setOnClickListener {
|
viewBinding.tvUserBlock.setOnClickListener {
|
||||||
dismiss()
|
dismiss()
|
||||||
onClickBlock?.invoke()
|
onClickBlock?.invoke()
|
||||||
|
|||||||
@@ -7,15 +7,13 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
|||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityTabResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.CreatorChannelCommunityPostUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.CreatorChannelCommunityPostUiModel
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.toCommunityPostUiModels
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.model.toCommunityPostUiModels
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
||||||
|
|
||||||
class CreatorChannelCommunityViewModel(
|
class CreatorChannelCommunityViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _communityStateLiveData = MutableLiveData<CreatorChannelCommunityUiState>()
|
private val _communityStateLiveData = MutableLiveData<CreatorChannelCommunityUiState>()
|
||||||
@@ -158,7 +156,6 @@ class CreatorChannelCommunityViewModel(
|
|||||||
|
|
||||||
private fun CreatorChannelCommunityTabResponse.toCommunityPostUiModels(): List<CreatorChannelCommunityPostUiModel> =
|
private fun CreatorChannelCommunityTabResponse.toCommunityPostUiModels(): List<CreatorChannelCommunityPostUiModel> =
|
||||||
communityPosts.toCommunityPostUiModels(
|
communityPosts.toCommunityPostUiModels(
|
||||||
relativeTimeTextFormatter = relativeTimeTextFormatter,
|
|
||||||
isOwner = isOwner,
|
isOwner = isOwner,
|
||||||
currentUserId = SharedPreferenceManager.userId
|
currentUserId = SharedPreferenceManager.userId
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.bumptech.glide.request.target.Target
|
|||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
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.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelCommunityDetailBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelCommunityDetailBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityPostMenuBottomSheetDialog
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityPostMenuBottomSheetDialog
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityReportDialog
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityReportDialog
|
||||||
@@ -34,6 +35,7 @@ import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.Creato
|
|||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.reply.CreatorChannelCommunityReplyActivity
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.reply.CreatorChannelCommunityReplyActivity
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.ui.CreatorChannelCommunityCommentAdapter
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.ui.CreatorChannelCommunityCommentAdapter
|
||||||
import kr.co.vividnext.sodalive.v2.widget.feed.calculateFeedCommunityImageHeight
|
import kr.co.vividnext.sodalive.v2.widget.feed.calculateFeedCommunityImageHeight
|
||||||
@@ -171,7 +173,13 @@ class CreatorChannelCommunityDetailActivity : BaseActivity<ActivityCreatorChanne
|
|||||||
transformations(CircleCropTransformation())
|
transformations(CircleCropTransformation())
|
||||||
}
|
}
|
||||||
tvCreatorChannelCommunityDetailNickname.text = post.creatorNickname
|
tvCreatorChannelCommunityDetailNickname.text = post.creatorNickname
|
||||||
tvCreatorChannelCommunityDetailTime.text = post.createdAtText
|
tvCreatorChannelCommunityDetailTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelCommunityDetailTime.context, post.createdAtUtc)
|
||||||
|
layoutCreatorChannelCommunityDetailCreator.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
CreatorChannelActivity.newIntent(this@CreatorChannelCommunityDetailActivity, post.creatorId)
|
||||||
|
)
|
||||||
|
}
|
||||||
btnCreatorChannelCommunityDetailMore.isVisible = post.showMore
|
btnCreatorChannelCommunityDetailMore.isVisible = post.showMore
|
||||||
tvCreatorChannelCommunityDetailBody.text = post.content
|
tvCreatorChannelCommunityDetailBody.text = post.content
|
||||||
layoutCreatorChannelCommunityDetailReaction.isVisible = post.showReaction || content.isCommentAvailable
|
layoutCreatorChannelCommunityDetailReaction.isVisible = post.showReaction || content.isCommentAvailable
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
|||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.ModifyCommunityPostRequest
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.ModifyCommunityPostRequest
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
||||||
@@ -25,8 +24,7 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
|||||||
|
|
||||||
class CreatorChannelCommunityDetailViewModel(
|
class CreatorChannelCommunityDetailViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository,
|
||||||
private val legacyRepository: CreatorCommunityRepository,
|
private val legacyRepository: CreatorCommunityRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _detailStateLiveData = MutableLiveData<CreatorChannelCommunityDetailUiState>()
|
private val _detailStateLiveData = MutableLiveData<CreatorChannelCommunityDetailUiState>()
|
||||||
@@ -536,7 +534,7 @@ class CreatorChannelCommunityDetailViewModel(
|
|||||||
creatorId = creatorId,
|
creatorId = creatorId,
|
||||||
creatorNickname = creatorNickname,
|
creatorNickname = creatorNickname,
|
||||||
creatorProfileUrl = creatorProfileUrl,
|
creatorProfileUrl = creatorProfileUrl,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
createdAtUtc = createdAtUtc,
|
||||||
content = content,
|
content = content,
|
||||||
imageUrl = imageUrl.takeUnless { isLocked() },
|
imageUrl = imageUrl.takeUnless { isLocked() },
|
||||||
audioUrl = audioUrl.takeUnless { isLocked() },
|
audioUrl = audioUrl.takeUnless { isLocked() },
|
||||||
@@ -566,7 +564,6 @@ class CreatorChannelCommunityDetailViewModel(
|
|||||||
memberNickname = writerNickname,
|
memberNickname = writerNickname,
|
||||||
memberProfileUrl = writerProfileImageUrl,
|
memberProfileUrl = writerProfileImageUrl,
|
||||||
createdAtUtc = createdAtUtc,
|
createdAtUtc = createdAtUtc,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
|
||||||
comment = content,
|
comment = content,
|
||||||
likeCount = 0,
|
likeCount = 0,
|
||||||
replyCount = if (latestReply != null) 1 else 0,
|
replyCount = if (latestReply != null) 1 else 0,
|
||||||
@@ -586,7 +583,6 @@ class CreatorChannelCommunityDetailViewModel(
|
|||||||
memberNickname = writerNickname,
|
memberNickname = writerNickname,
|
||||||
memberProfileUrl = writerProfileImageUrl,
|
memberProfileUrl = writerProfileImageUrl,
|
||||||
createdAtUtc = createdAtUtc,
|
createdAtUtc = createdAtUtc,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
|
||||||
comment = content,
|
comment = content,
|
||||||
likeCount = 0,
|
likeCount = 0,
|
||||||
isLiked = false,
|
isLiked = false,
|
||||||
@@ -625,7 +621,7 @@ data class CreatorChannelCommunityPostDetailUiModel(
|
|||||||
val creatorId: Long,
|
val creatorId: Long,
|
||||||
val creatorNickname: String,
|
val creatorNickname: String,
|
||||||
val creatorProfileUrl: String?,
|
val creatorProfileUrl: String?,
|
||||||
val createdAtText: String,
|
val createdAtUtc: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val imageUrl: String?,
|
val imageUrl: String?,
|
||||||
val audioUrl: String?,
|
val audioUrl: String?,
|
||||||
@@ -648,7 +644,6 @@ data class CreatorChannelCommunityCommentUiModel(
|
|||||||
val memberNickname: String,
|
val memberNickname: String,
|
||||||
val memberProfileUrl: String?,
|
val memberProfileUrl: String?,
|
||||||
val createdAtUtc: String,
|
val createdAtUtc: String,
|
||||||
val createdAtText: String,
|
|
||||||
val comment: String,
|
val comment: String,
|
||||||
val likeCount: Int,
|
val likeCount: Int,
|
||||||
val replyCount: Int,
|
val replyCount: Int,
|
||||||
@@ -665,7 +660,6 @@ data class CreatorChannelCommunityReplyUiModel(
|
|||||||
val memberNickname: String,
|
val memberNickname: String,
|
||||||
val memberProfileUrl: String?,
|
val memberProfileUrl: String?,
|
||||||
val createdAtUtc: String,
|
val createdAtUtc: String,
|
||||||
val createdAtText: String,
|
|
||||||
val comment: String,
|
val comment: String,
|
||||||
val likeCount: Int,
|
val likeCount: Int,
|
||||||
val isLiked: Boolean,
|
val isLiked: Boolean,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ 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.R
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelCommunityReplyBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelCommunityReplyBinding
|
||||||
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
||||||
@@ -110,6 +111,11 @@ class CreatorChannelCommunityReplyActivity : BaseActivity<ActivityCreatorChannel
|
|||||||
onModifyClick = { comment -> viewModel.startParentCommentEdit(comment.comment) },
|
onModifyClick = { comment -> viewModel.startParentCommentEdit(comment.comment) },
|
||||||
onDeleteClick = { showDeleteParentCommentDialog() }
|
onDeleteClick = { showDeleteParentCommentDialog() }
|
||||||
)
|
)
|
||||||
|
layoutCreatorChannelCommunityReplyParent.tvCreatorChannelCommunityCommentTime.text =
|
||||||
|
formatUtcRelativeTimeText(
|
||||||
|
layoutCreatorChannelCommunityReplyParent.tvCreatorChannelCommunityCommentTime.context,
|
||||||
|
content.parentComment.createdAtUtc
|
||||||
|
)
|
||||||
layoutCreatorChannelCommunityReplyParent.layoutCreatorChannelCommunityCommentLatestReply.isVisible = false
|
layoutCreatorChannelCommunityReplyParent.layoutCreatorChannelCommunityCommentLatestReply.isVisible = false
|
||||||
replyAdapter.submitItems(content.replies)
|
replyAdapter.submitItems(content.replies)
|
||||||
if (etCreatorChannelCommunityReply.text.toString() != content.replyInput) {
|
if (etCreatorChannelCommunityReply.text.toString() != content.replyInput) {
|
||||||
@@ -183,7 +189,6 @@ class CreatorChannelCommunityReplyActivity : BaseActivity<ActivityCreatorChannel
|
|||||||
memberNickname = intent.getStringExtra(EXTRA_MEMBER_NICKNAME).orEmpty(),
|
memberNickname = intent.getStringExtra(EXTRA_MEMBER_NICKNAME).orEmpty(),
|
||||||
memberProfileUrl = intent.getStringExtra(EXTRA_MEMBER_PROFILE_URL),
|
memberProfileUrl = intent.getStringExtra(EXTRA_MEMBER_PROFILE_URL),
|
||||||
createdAtUtc = intent.getStringExtra(EXTRA_CREATED_AT_UTC).orEmpty(),
|
createdAtUtc = intent.getStringExtra(EXTRA_CREATED_AT_UTC).orEmpty(),
|
||||||
createdAtText = intent.getStringExtra(EXTRA_CREATED_AT_TEXT).orEmpty(),
|
|
||||||
comment = intent.getStringExtra(EXTRA_COMMENT).orEmpty(),
|
comment = intent.getStringExtra(EXTRA_COMMENT).orEmpty(),
|
||||||
likeCount = intent.getIntExtra(EXTRA_LIKE_COUNT, 0),
|
likeCount = intent.getIntExtra(EXTRA_LIKE_COUNT, 0),
|
||||||
replyCount = intent.getIntExtra(EXTRA_REPLY_COUNT, 0),
|
replyCount = intent.getIntExtra(EXTRA_REPLY_COUNT, 0),
|
||||||
@@ -201,7 +206,6 @@ class CreatorChannelCommunityReplyActivity : BaseActivity<ActivityCreatorChannel
|
|||||||
private const val EXTRA_MEMBER_NICKNAME = "extra_member_nickname"
|
private const val EXTRA_MEMBER_NICKNAME = "extra_member_nickname"
|
||||||
private const val EXTRA_MEMBER_PROFILE_URL = "extra_member_profile_url"
|
private const val EXTRA_MEMBER_PROFILE_URL = "extra_member_profile_url"
|
||||||
private const val EXTRA_CREATED_AT_UTC = "extra_created_at_utc"
|
private const val EXTRA_CREATED_AT_UTC = "extra_created_at_utc"
|
||||||
private const val EXTRA_CREATED_AT_TEXT = "extra_created_at_text"
|
|
||||||
private const val EXTRA_COMMENT = "extra_comment"
|
private const val EXTRA_COMMENT = "extra_comment"
|
||||||
private const val EXTRA_LIKE_COUNT = "extra_like_count"
|
private const val EXTRA_LIKE_COUNT = "extra_like_count"
|
||||||
private const val EXTRA_REPLY_COUNT = "extra_reply_count"
|
private const val EXTRA_REPLY_COUNT = "extra_reply_count"
|
||||||
@@ -217,7 +221,6 @@ class CreatorChannelCommunityReplyActivity : BaseActivity<ActivityCreatorChannel
|
|||||||
.putExtra(EXTRA_MEMBER_NICKNAME, parentComment.memberNickname)
|
.putExtra(EXTRA_MEMBER_NICKNAME, parentComment.memberNickname)
|
||||||
.putExtra(EXTRA_MEMBER_PROFILE_URL, parentComment.memberProfileUrl)
|
.putExtra(EXTRA_MEMBER_PROFILE_URL, parentComment.memberProfileUrl)
|
||||||
.putExtra(EXTRA_CREATED_AT_UTC, parentComment.createdAtUtc)
|
.putExtra(EXTRA_CREATED_AT_UTC, parentComment.createdAtUtc)
|
||||||
.putExtra(EXTRA_CREATED_AT_TEXT, parentComment.createdAtText)
|
|
||||||
.putExtra(EXTRA_COMMENT, parentComment.comment)
|
.putExtra(EXTRA_COMMENT, parentComment.comment)
|
||||||
.putExtra(EXTRA_LIKE_COUNT, parentComment.likeCount)
|
.putExtra(EXTRA_LIKE_COUNT, parentComment.likeCount)
|
||||||
.putExtra(EXTRA_REPLY_COUNT, parentComment.replyCount)
|
.putExtra(EXTRA_REPLY_COUNT, parentComment.replyCount)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
|||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
||||||
@@ -21,8 +20,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
|||||||
|
|
||||||
class CreatorChannelCommunityReplyViewModel(
|
class CreatorChannelCommunityReplyViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository,
|
||||||
private val legacyRepository: CreatorCommunityRepository,
|
private val legacyRepository: CreatorCommunityRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _replyStateLiveData = MutableLiveData<CreatorChannelCommunityReplyUiState>()
|
private val _replyStateLiveData = MutableLiveData<CreatorChannelCommunityReplyUiState>()
|
||||||
@@ -57,20 +55,17 @@ class CreatorChannelCommunityReplyViewModel(
|
|||||||
private var isModifyingReply = false
|
private var isModifyingReply = false
|
||||||
|
|
||||||
fun loadReplies(postId: Long, parentComment: CreatorChannelCommunityCommentUiModel) {
|
fun loadReplies(postId: Long, parentComment: CreatorChannelCommunityCommentUiModel) {
|
||||||
val formattedParentComment = parentComment.copy(
|
|
||||||
createdAtText = relativeTimeTextFormatter.format(parentComment.createdAtUtc)
|
|
||||||
)
|
|
||||||
this.postId = postId
|
this.postId = postId
|
||||||
this.parentComment = formattedParentComment
|
this.parentComment = parentComment
|
||||||
replyRequestGeneration++
|
replyRequestGeneration++
|
||||||
isLoadingReplies = false
|
isLoadingReplies = false
|
||||||
_replyStateLiveData.value = CreatorChannelCommunityReplyUiState.Content(
|
_replyStateLiveData.value = CreatorChannelCommunityReplyUiState.Content(
|
||||||
parentComment = formattedParentComment,
|
parentComment = parentComment,
|
||||||
replies = emptyList(),
|
replies = emptyList(),
|
||||||
replyPage = FIRST_PAGE,
|
replyPage = FIRST_PAGE,
|
||||||
hasNextReply = false
|
hasNextReply = false
|
||||||
)
|
)
|
||||||
if (formattedParentComment.commentId > 0) {
|
if (parentComment.commentId > 0) {
|
||||||
loadReplyPage(page = FIRST_PAGE, append = false)
|
loadReplyPage(page = FIRST_PAGE, append = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -486,7 +481,6 @@ class CreatorChannelCommunityReplyViewModel(
|
|||||||
memberNickname = writerNickname,
|
memberNickname = writerNickname,
|
||||||
memberProfileUrl = writerProfileImageUrl,
|
memberProfileUrl = writerProfileImageUrl,
|
||||||
createdAtUtc = createdAtUtc,
|
createdAtUtc = createdAtUtc,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
|
||||||
comment = content,
|
comment = content,
|
||||||
likeCount = 0,
|
likeCount = 0,
|
||||||
isLiked = false,
|
isLiked = false,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityReplyBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityReplyBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityReplyUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityReplyUiModel
|
||||||
@@ -51,7 +52,8 @@ class CreatorChannelCommunityReplyAdapter(
|
|||||||
transformations(CircleCropTransformation())
|
transformations(CircleCropTransformation())
|
||||||
}
|
}
|
||||||
tvCreatorChannelCommunityReplyItemNickname.text = item.memberNickname
|
tvCreatorChannelCommunityReplyItemNickname.text = item.memberNickname
|
||||||
tvCreatorChannelCommunityReplyItemTime.text = item.createdAtText
|
tvCreatorChannelCommunityReplyItemTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelCommunityReplyItemTime.context, item.createdAtUtc)
|
||||||
tvCreatorChannelCommunityReplyItemBody.text = item.comment
|
tvCreatorChannelCommunityReplyItemBody.text = item.comment
|
||||||
ivCreatorChannelCommunityReplyItemMore.isVisible = item.canShowMore
|
ivCreatorChannelCommunityReplyItemMore.isVisible = item.canShowMore
|
||||||
ivCreatorChannelCommunityReplyItemMore.setOnClickListener { anchor ->
|
ivCreatorChannelCommunityReplyItemMore.setOnClickListener { anchor ->
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityCommentBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityCommentBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.detail.CreatorChannelCommunityCommentUiModel
|
||||||
@@ -70,7 +71,8 @@ class CreatorChannelCommunityCommentAdapter(
|
|||||||
transformations(CircleCropTransformation())
|
transformations(CircleCropTransformation())
|
||||||
}
|
}
|
||||||
tvCreatorChannelCommunityCommentNickname.text = item.memberNickname
|
tvCreatorChannelCommunityCommentNickname.text = item.memberNickname
|
||||||
tvCreatorChannelCommunityCommentTime.text = item.createdAtText
|
tvCreatorChannelCommunityCommentTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelCommunityCommentTime.context, item.createdAtUtc)
|
||||||
tvCreatorChannelCommunityCommentBody.text = item.comment
|
tvCreatorChannelCommunityCommentBody.text = item.comment
|
||||||
ivCreatorChannelCommunityCommentMore.isVisible = item.canShowMore && onDeleteClick != null
|
ivCreatorChannelCommunityCommentMore.isVisible = item.canShowMore && onDeleteClick != null
|
||||||
ivCreatorChannelCommunityCommentMore.setOnClickListener { anchor ->
|
ivCreatorChannelCommunityCommentMore.setOnClickListener { anchor ->
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.creator.channel.community.model
|
package kr.co.vividnext.sodalive.v2.creator.channel.community.model
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.community.data.CreatorChannelCommunityPostResponse
|
||||||
|
|
||||||
private const val GRID_PREVIEW_MAX_LENGTH = 24
|
private const val GRID_PREVIEW_MAX_LENGTH = 24
|
||||||
|
|
||||||
fun List<CreatorChannelCommunityPostResponse>.toCommunityPostUiModels(
|
fun List<CreatorChannelCommunityPostResponse>.toCommunityPostUiModels(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
|
||||||
isOwner: Boolean,
|
isOwner: Boolean,
|
||||||
currentUserId: Long
|
currentUserId: Long
|
||||||
): List<CreatorChannelCommunityPostUiModel> = map {
|
): List<CreatorChannelCommunityPostUiModel> = map {
|
||||||
it.toCommunityPostUiModel(relativeTimeTextFormatter, isOwner, currentUserId)
|
it.toCommunityPostUiModel(isOwner, currentUserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CreatorChannelCommunityPostResponse.toCommunityPostUiModel(
|
private fun CreatorChannelCommunityPostResponse.toCommunityPostUiModel(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
|
||||||
isOwner: Boolean,
|
isOwner: Boolean,
|
||||||
currentUserId: Long
|
currentUserId: Long
|
||||||
): CreatorChannelCommunityPostUiModel {
|
): CreatorChannelCommunityPostUiModel {
|
||||||
@@ -26,7 +23,7 @@ private fun CreatorChannelCommunityPostResponse.toCommunityPostUiModel(
|
|||||||
creatorId = creatorId,
|
creatorId = creatorId,
|
||||||
creatorNickname = creatorNickname,
|
creatorNickname = creatorNickname,
|
||||||
creatorProfileUrl = creatorProfileUrl,
|
creatorProfileUrl = creatorProfileUrl,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
createdAtUtc = createdAtUtc,
|
||||||
content = content,
|
content = content,
|
||||||
imageUrl = visibleImageUrl,
|
imageUrl = visibleImageUrl,
|
||||||
price = price,
|
price = price,
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ data class CreatorChannelCommunityPostUiModel(
|
|||||||
val creatorId: Long,
|
val creatorId: Long,
|
||||||
val creatorNickname: String,
|
val creatorNickname: String,
|
||||||
val creatorProfileUrl: String,
|
val creatorProfileUrl: String,
|
||||||
val createdAtText: String,
|
val createdAtUtc: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val imageUrl: String?,
|
val imageUrl: String?,
|
||||||
val price: Int,
|
val price: Int,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import com.bumptech.glide.load.engine.GlideException
|
|||||||
import com.bumptech.glide.request.RequestListener
|
import com.bumptech.glide.request.RequestListener
|
||||||
import com.bumptech.glide.request.target.Target
|
import com.bumptech.glide.request.target.Target
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityListBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelCommunityListBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
@@ -68,7 +69,8 @@ class CreatorChannelCommunityListAdapter(
|
|||||||
transformations(CircleCropTransformation())
|
transformations(CircleCropTransformation())
|
||||||
}
|
}
|
||||||
tvCreatorChannelCommunityListNickname.text = item.creatorNickname
|
tvCreatorChannelCommunityListNickname.text = item.creatorNickname
|
||||||
tvCreatorChannelCommunityListTime.text = item.createdAtText
|
tvCreatorChannelCommunityListTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelCommunityListTime.context, item.createdAtUtc)
|
||||||
layoutCreatorChannelCommunityListNotice.isVisible = item.showNotice
|
layoutCreatorChannelCommunityListNotice.isVisible = item.showNotice
|
||||||
tvCreatorChannelCommunityListBody.text = item.content
|
tvCreatorChannelCommunityListBody.text = item.content
|
||||||
layoutCreatorChannelCommunityListReaction.isVisible = item.showReaction || item.showComment
|
layoutCreatorChannelCommunityListReaction.isVisible = item.showReaction || item.showComment
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ private data class CreatorChannelDonationItemLayoutKey(
|
|||||||
val nickname: String,
|
val nickname: String,
|
||||||
val can: Int,
|
val can: Int,
|
||||||
val message: String,
|
val message: String,
|
||||||
val createdAtText: String
|
val createdAtUtc: String
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun CreatorChannelDonationUiState.Content.toContentLayoutKey(): CreatorChannelDonationContentLayoutKey {
|
private fun CreatorChannelDonationUiState.Content.toContentLayoutKey(): CreatorChannelDonationContentLayoutKey {
|
||||||
@@ -206,7 +206,7 @@ private fun CreatorChannelDonationUiState.Content.toContentLayoutKey(): CreatorC
|
|||||||
nickname = donation.nickname,
|
nickname = donation.nickname,
|
||||||
can = donation.can,
|
can = donation.can,
|
||||||
message = donation.message,
|
message = donation.message,
|
||||||
createdAtText = donation.createdAtText
|
createdAtUtc = donation.createdAtUtc
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
|||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationTabResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationTabResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.CreatorChannelDonationRankingUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.CreatorChannelDonationRankingUiModel
|
||||||
@@ -17,15 +15,13 @@ import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.toDonationRank
|
|||||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.toDonationUiModels
|
import kr.co.vividnext.sodalive.v2.creator.channel.donation.model.toDonationUiModels
|
||||||
|
|
||||||
class CreatorChannelDonationViewModel(
|
class CreatorChannelDonationViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _donationStateLiveData = MutableLiveData<CreatorChannelDonationUiState>()
|
private val _donationStateLiveData = MutableLiveData<CreatorChannelDonationUiState>()
|
||||||
val donationStateLiveData: LiveData<CreatorChannelDonationUiState>
|
val donationStateLiveData: LiveData<CreatorChannelDonationUiState>
|
||||||
get() = _donationStateLiveData
|
get() = _donationStateLiveData
|
||||||
|
|
||||||
private val context = SodaLiveApplicationHolder.get()
|
|
||||||
private var creatorId: Long = 0L
|
private var creatorId: Long = 0L
|
||||||
private var isOwner: Boolean = false
|
private var isOwner: Boolean = false
|
||||||
private var requestGeneration: Int = 0
|
private var requestGeneration: Int = 0
|
||||||
@@ -222,7 +218,7 @@ class CreatorChannelDonationViewModel(
|
|||||||
rankings.toDonationRankingUiModels()
|
rankings.toDonationRankingUiModels()
|
||||||
|
|
||||||
private fun CreatorChannelDonationTabResponse.toDonationUiModels(): List<CreatorChannelDonationUiModel> =
|
private fun CreatorChannelDonationTabResponse.toDonationUiModels(): List<CreatorChannelDonationUiModel> =
|
||||||
donations.toDonationUiModels(context, relativeTimeTextFormatter)
|
donations.toDonationUiModels()
|
||||||
|
|
||||||
private fun authToken(): String = "Bearer ${SharedPreferenceManager.token}"
|
private fun authToken(): String = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.creator.channel.donation.model
|
package kr.co.vividnext.sodalive.v2.creator.channel.donation.model
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.CreatorChannelDonationResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.MemberDonationRankingResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.donation.data.MemberDonationRankingResponse
|
||||||
|
|
||||||
fun List<MemberDonationRankingResponse>.toDonationRankingUiModels(): List<CreatorChannelDonationRankingUiModel> =
|
fun List<MemberDonationRankingResponse>.toDonationRankingUiModels(): List<CreatorChannelDonationRankingUiModel> =
|
||||||
mapIndexed { index, response -> response.toDonationRankingUiModel(rank = index + 1) }
|
mapIndexed { index, response -> response.toDonationRankingUiModel(rank = index + 1) }
|
||||||
|
|
||||||
fun List<CreatorChannelDonationResponse>.toDonationUiModels(
|
fun List<CreatorChannelDonationResponse>.toDonationUiModels(): List<CreatorChannelDonationUiModel> =
|
||||||
context: Context,
|
map { it.toDonationUiModel() }
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
): List<CreatorChannelDonationUiModel> = map { it.toDonationUiModel(context, relativeTimeTextFormatter) }
|
|
||||||
|
|
||||||
private fun MemberDonationRankingResponse.toDonationRankingUiModel(rank: Int) = CreatorChannelDonationRankingUiModel(
|
private fun MemberDonationRankingResponse.toDonationRankingUiModel(rank: Int) = CreatorChannelDonationRankingUiModel(
|
||||||
rank = rank,
|
rank = rank,
|
||||||
@@ -23,15 +19,12 @@ private fun MemberDonationRankingResponse.toDonationRankingUiModel(rank: Int) =
|
|||||||
donationCan = donationCan
|
donationCan = donationCan
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun CreatorChannelDonationResponse.toDonationUiModel(
|
private fun CreatorChannelDonationResponse.toDonationUiModel() = CreatorChannelDonationUiModel(
|
||||||
context: Context,
|
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) = CreatorChannelDonationUiModel(
|
|
||||||
nickname = nickname,
|
nickname = nickname,
|
||||||
profileImageUrl = profileImageUrl,
|
profileImageUrl = profileImageUrl,
|
||||||
can = can,
|
can = can,
|
||||||
message = message.takeUnless { it.isBlank() } ?: context.getString(R.string.creator_channel_donation_fallback_message, can),
|
message = message,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
createdAtUtc = createdAtUtc,
|
||||||
headerColorResId = calculateDonationHeaderColorRes(can)
|
headerColorResId = calculateDonationHeaderColorRes(can)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ data class CreatorChannelDonationUiModel(
|
|||||||
val profileImageUrl: String,
|
val profileImageUrl: String,
|
||||||
val can: Int,
|
val can: Int,
|
||||||
val message: String,
|
val message: String,
|
||||||
val createdAtText: String,
|
val createdAtUtc: String,
|
||||||
@param:ColorRes val headerColorResId: Int
|
@param:ColorRes val headerColorResId: Int
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import android.view.ViewGroup
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationBinding
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationEmptyBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationEmptyBinding
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationRankingBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelDonationRankingBinding
|
||||||
@@ -115,6 +117,7 @@ class CreatorChannelDonationAdapter(
|
|||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(item: CreatorChannelDonationUiModel) = with(binding) {
|
fun bind(item: CreatorChannelDonationUiModel) = with(binding) {
|
||||||
|
val context = root.context
|
||||||
bindCreatorChannelDonationCard(
|
bindCreatorChannelDonationCard(
|
||||||
headerView = layoutCreatorChannelDonationHeader,
|
headerView = layoutCreatorChannelDonationHeader,
|
||||||
profileView = ivCreatorChannelDonationProfile,
|
profileView = ivCreatorChannelDonationProfile,
|
||||||
@@ -125,9 +128,10 @@ class CreatorChannelDonationAdapter(
|
|||||||
headerColorResId = item.headerColorResId,
|
headerColorResId = item.headerColorResId,
|
||||||
profileImageUrl = item.profileImageUrl,
|
profileImageUrl = item.profileImageUrl,
|
||||||
nickname = item.nickname,
|
nickname = item.nickname,
|
||||||
createdAtText = item.createdAtText,
|
createdAtText = formatUtcRelativeTimeText(context, item.createdAtUtc),
|
||||||
can = item.can,
|
can = item.can,
|
||||||
message = item.message
|
message = item.message.takeUnless { it.isBlank() }
|
||||||
|
?: context.getString(R.string.creator_channel_donation_fallback_message, item.can)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,13 @@ import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
|||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkTabResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkTabResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.CreatorChannelFanTalkUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.CreatorChannelFanTalkUiModel
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.toFanTalkUiModels
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.toFanTalkUiModels
|
||||||
|
|
||||||
class CreatorChannelFanTalkViewModel(
|
class CreatorChannelFanTalkViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _fanTalkStateLiveData = MutableLiveData<CreatorChannelFanTalkUiState>()
|
private val _fanTalkStateLiveData = MutableLiveData<CreatorChannelFanTalkUiState>()
|
||||||
@@ -198,7 +196,6 @@ class CreatorChannelFanTalkViewModel(
|
|||||||
|
|
||||||
private fun CreatorChannelFanTalkTabResponse.toFanTalkUiModels(): List<CreatorChannelFanTalkUiModel> =
|
private fun CreatorChannelFanTalkTabResponse.toFanTalkUiModels(): List<CreatorChannelFanTalkUiModel> =
|
||||||
fanTalks.toFanTalkUiModels(
|
fanTalks.toFanTalkUiModels(
|
||||||
relativeTimeTextFormatter = relativeTimeTextFormatter,
|
|
||||||
isOwner = isOwner,
|
isOwner = isOwner,
|
||||||
currentUserId = SharedPreferenceManager.userId
|
currentUserId = SharedPreferenceManager.userId
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import androidx.core.widget.doAfterTextChanged
|
|||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelFantalkDetailBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorChannelFantalkDetailBinding
|
||||||
import kr.co.vividnext.sodalive.databinding.ViewCreatorChannelFantalkMorePopupBinding
|
import kr.co.vividnext.sodalive.databinding.ViewCreatorChannelFantalkMorePopupBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
@@ -107,7 +108,8 @@ class CreatorChannelFanTalkDetailActivity : BaseActivity<ActivityCreatorChannelF
|
|||||||
private fun bindParentFanTalk(item: CreatorChannelFanTalkUiModel) = with(binding) {
|
private fun bindParentFanTalk(item: CreatorChannelFanTalkUiModel) = with(binding) {
|
||||||
ivCreatorChannelFantalkDetailProfile.loadProfile(item.writerProfileImageUrl)
|
ivCreatorChannelFantalkDetailProfile.loadProfile(item.writerProfileImageUrl)
|
||||||
tvCreatorChannelFantalkDetailNickname.text = item.writerNickname
|
tvCreatorChannelFantalkDetailNickname.text = item.writerNickname
|
||||||
tvCreatorChannelFantalkDetailTime.text = item.createdAtText
|
tvCreatorChannelFantalkDetailTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelFantalkDetailTime.context, item.createdAtUtc)
|
||||||
tvCreatorChannelFantalkDetailContent.text = item.content
|
tvCreatorChannelFantalkDetailContent.text = item.content
|
||||||
ivCreatorChannelFantalkDetailMore.isVisible = false
|
ivCreatorChannelFantalkDetailMore.isVisible = false
|
||||||
ivCreatorChannelFantalkDetailMore.setOnClickListener(null)
|
ivCreatorChannelFantalkDetailMore.setOnClickListener(null)
|
||||||
@@ -123,7 +125,8 @@ class CreatorChannelFanTalkDetailActivity : BaseActivity<ActivityCreatorChannelF
|
|||||||
|
|
||||||
ivCreatorChannelFantalkDetailReplyProfile.loadProfile(reply.writerProfileImageUrl)
|
ivCreatorChannelFantalkDetailReplyProfile.loadProfile(reply.writerProfileImageUrl)
|
||||||
tvCreatorChannelFantalkDetailReplyNickname.text = reply.writerNickname
|
tvCreatorChannelFantalkDetailReplyNickname.text = reply.writerNickname
|
||||||
tvCreatorChannelFantalkDetailReplyTime.text = reply.createdAtText
|
tvCreatorChannelFantalkDetailReplyTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelFantalkDetailReplyTime.context, reply.createdAtUtc)
|
||||||
tvCreatorChannelFantalkDetailReplyContent.text = reply.content
|
tvCreatorChannelFantalkDetailReplyContent.text = reply.content
|
||||||
ivCreatorChannelFantalkDetailReplyMore.isVisible = reply.fanTalkId > 0L
|
ivCreatorChannelFantalkDetailReplyMore.isVisible = reply.fanTalkId > 0L
|
||||||
ivCreatorChannelFantalkDetailReplyMore.setOnClickListener(
|
ivCreatorChannelFantalkDetailReplyMore.setOnClickListener(
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ data class CreatorChannelFanTalkDetailPayload(
|
|||||||
val writerNickname: String,
|
val writerNickname: String,
|
||||||
val writerProfileImageUrl: String,
|
val writerProfileImageUrl: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val createdAtText: String,
|
val createdAtUtc: String,
|
||||||
val reply: CreatorChannelFanTalkDetailReplyPayload?,
|
val reply: CreatorChannelFanTalkDetailReplyPayload?,
|
||||||
val showEdit: Boolean,
|
val showEdit: Boolean,
|
||||||
val showDelete: Boolean
|
val showDelete: Boolean
|
||||||
@@ -26,7 +26,7 @@ data class CreatorChannelFanTalkDetailPayload(
|
|||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = createdAtText,
|
createdAtUtc = createdAtUtc,
|
||||||
reply = reply?.toUiModel(),
|
reply = reply?.toUiModel(),
|
||||||
rightAction = CreatorChannelFanTalkRightAction.OwnerMore(showEdit = showEdit, showDelete = showDelete)
|
rightAction = CreatorChannelFanTalkRightAction.OwnerMore(showEdit = showEdit, showDelete = showDelete)
|
||||||
)
|
)
|
||||||
@@ -39,7 +39,7 @@ data class CreatorChannelFanTalkDetailReplyPayload(
|
|||||||
val writerNickname: String,
|
val writerNickname: String,
|
||||||
val writerProfileImageUrl: String,
|
val writerProfileImageUrl: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val createdAtText: String
|
val createdAtUtc: String
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
fun toUiModel(): CreatorChannelFanTalkReplyUiModel = CreatorChannelFanTalkReplyUiModel(
|
fun toUiModel(): CreatorChannelFanTalkReplyUiModel = CreatorChannelFanTalkReplyUiModel(
|
||||||
fanTalkId = fanTalkId,
|
fanTalkId = fanTalkId,
|
||||||
@@ -47,7 +47,7 @@ data class CreatorChannelFanTalkDetailReplyPayload(
|
|||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = createdAtText
|
createdAtUtc = createdAtUtc
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ fun CreatorChannelFanTalkUiModel.toFanTalkDetailPayload(): CreatorChannelFanTalk
|
|||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = createdAtText,
|
createdAtUtc = createdAtUtc,
|
||||||
reply = reply?.toFanTalkDetailReplyPayload(),
|
reply = reply?.toFanTalkDetailReplyPayload(),
|
||||||
showEdit = ownerMore?.showEdit == true,
|
showEdit = ownerMore?.showEdit == true,
|
||||||
showDelete = ownerMore?.showDelete == true
|
showDelete = ownerMore?.showDelete == true
|
||||||
@@ -73,7 +73,7 @@ fun CreatorChannelFanTalkReplyUiModel.toFanTalkDetailReplyPayload(): CreatorChan
|
|||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = createdAtText
|
createdAtUtc = createdAtUtc
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,13 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
|||||||
import kr.co.vividnext.sodalive.common.ApiResponse
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.common.ToastMessage
|
import kr.co.vividnext.sodalive.common.ToastMessage
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelEvent
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelRepository
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkReplyResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkReplyResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.toFanTalkReplyUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.toFanTalkReplyUiModel
|
||||||
|
|
||||||
class CreatorChannelFanTalkDetailViewModel(
|
class CreatorChannelFanTalkDetailViewModel(
|
||||||
private val repository: CreatorChannelRepository,
|
private val repository: CreatorChannelRepository
|
||||||
private val relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val _detailStateLiveData = MutableLiveData<CreatorChannelFanTalkDetailUiState>()
|
private val _detailStateLiveData = MutableLiveData<CreatorChannelFanTalkDetailUiState>()
|
||||||
@@ -191,7 +189,7 @@ class CreatorChannelFanTalkDetailViewModel(
|
|||||||
val current = currentContent() ?: return
|
val current = currentContent() ?: return
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
_detailStateLiveData.value = current.copy(
|
_detailStateLiveData.value = current.copy(
|
||||||
reply = response.data?.toFanTalkReplyUiModel(relativeTimeTextFormatter) ?: current.reply,
|
reply = response.data?.toFanTalkReplyUiModel() ?: current.reply,
|
||||||
replyInput = "",
|
replyInput = "",
|
||||||
isSubmitting = false,
|
isSubmitting = false,
|
||||||
editingTarget = null
|
editingTarget = null
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model
|
package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.UtcRelativeTimeTextFormatter
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkReplyResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkReplyResponse
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkResponse
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.data.CreatorChannelFanTalkResponse
|
||||||
|
|
||||||
fun List<CreatorChannelFanTalkResponse>.toFanTalkUiModels(
|
fun List<CreatorChannelFanTalkResponse>.toFanTalkUiModels(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
|
||||||
isOwner: Boolean,
|
isOwner: Boolean,
|
||||||
currentUserId: Long
|
currentUserId: Long
|
||||||
): List<CreatorChannelFanTalkUiModel> = map {
|
): List<CreatorChannelFanTalkUiModel> = map {
|
||||||
it.toFanTalkUiModel(relativeTimeTextFormatter, isOwner, currentUserId)
|
it.toFanTalkUiModel(isOwner, currentUserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CreatorChannelFanTalkResponse.toFanTalkUiModel(
|
private fun CreatorChannelFanTalkResponse.toFanTalkUiModel(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter,
|
|
||||||
isOwner: Boolean,
|
isOwner: Boolean,
|
||||||
currentUserId: Long
|
currentUserId: Long
|
||||||
) = CreatorChannelFanTalkUiModel(
|
) = CreatorChannelFanTalkUiModel(
|
||||||
@@ -22,31 +19,27 @@ private fun CreatorChannelFanTalkResponse.toFanTalkUiModel(
|
|||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc),
|
createdAtUtc = createdAtUtc,
|
||||||
reply = creatorReplies.orEmpty().firstOrNull()?.toFanTalkReplyUiModel(relativeTimeTextFormatter),
|
reply = creatorReplies.orEmpty().firstOrNull()?.toFanTalkReplyUiModel(),
|
||||||
rightAction = toRightAction(isOwner = isOwner, currentUserId = currentUserId)
|
rightAction = toRightAction(isOwner = isOwner, currentUserId = currentUserId)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun CreatorChannelFanTalkReplyResponse.toFanTalkReplyUiModel(
|
fun CreatorChannelFanTalkReplyResponse.toFanTalkReplyUiModel() = CreatorChannelFanTalkReplyUiModel(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) = CreatorChannelFanTalkReplyUiModel(
|
|
||||||
fanTalkId = fanTalkId,
|
fanTalkId = fanTalkId,
|
||||||
writerId = writerId,
|
writerId = writerId,
|
||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc)
|
createdAtUtc = createdAtUtc
|
||||||
)
|
)
|
||||||
|
|
||||||
fun CreatorChannelFanTalkResponse.toFanTalkReplyUiModel(
|
fun CreatorChannelFanTalkResponse.toFanTalkReplyUiModel() = CreatorChannelFanTalkReplyUiModel(
|
||||||
relativeTimeTextFormatter: UtcRelativeTimeTextFormatter
|
|
||||||
) = CreatorChannelFanTalkReplyUiModel(
|
|
||||||
fanTalkId = fanTalkId,
|
fanTalkId = fanTalkId,
|
||||||
writerId = writerId,
|
writerId = writerId,
|
||||||
writerNickname = writerNickname,
|
writerNickname = writerNickname,
|
||||||
writerProfileImageUrl = writerProfileImageUrl,
|
writerProfileImageUrl = writerProfileImageUrl,
|
||||||
content = content,
|
content = content,
|
||||||
createdAtText = relativeTimeTextFormatter.format(createdAtUtc)
|
createdAtUtc = createdAtUtc
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun CreatorChannelFanTalkResponse.toRightAction(
|
private fun CreatorChannelFanTalkResponse.toRightAction(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ data class CreatorChannelFanTalkUiModel(
|
|||||||
val writerNickname: String,
|
val writerNickname: String,
|
||||||
val writerProfileImageUrl: String,
|
val writerProfileImageUrl: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val createdAtText: String,
|
val createdAtUtc: String,
|
||||||
val reply: CreatorChannelFanTalkReplyUiModel?,
|
val reply: CreatorChannelFanTalkReplyUiModel?,
|
||||||
val rightAction: CreatorChannelFanTalkRightAction
|
val rightAction: CreatorChannelFanTalkRightAction
|
||||||
)
|
)
|
||||||
@@ -17,7 +17,7 @@ data class CreatorChannelFanTalkReplyUiModel(
|
|||||||
val writerNickname: String,
|
val writerNickname: String,
|
||||||
val writerProfileImageUrl: String,
|
val writerProfileImageUrl: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val createdAtText: String
|
val createdAtUtc: String
|
||||||
)
|
)
|
||||||
|
|
||||||
sealed interface CreatorChannelFanTalkRightAction {
|
sealed interface CreatorChannelFanTalkRightAction {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.formatUtcRelativeTimeText
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelFantalkBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorChannelFantalkBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.CreatorChannelFanTalkReplyUiModel
|
import kr.co.vividnext.sodalive.v2.creator.channel.fantalk.model.CreatorChannelFanTalkReplyUiModel
|
||||||
@@ -51,7 +52,8 @@ class CreatorChannelFanTalkAdapter(
|
|||||||
fun bind(item: CreatorChannelFanTalkUiModel) = with(binding) {
|
fun bind(item: CreatorChannelFanTalkUiModel) = with(binding) {
|
||||||
ivCreatorChannelFantalkProfile.loadProfile(item.writerProfileImageUrl)
|
ivCreatorChannelFantalkProfile.loadProfile(item.writerProfileImageUrl)
|
||||||
tvCreatorChannelFantalkNickname.text = item.writerNickname
|
tvCreatorChannelFantalkNickname.text = item.writerNickname
|
||||||
tvCreatorChannelFantalkTime.text = item.createdAtText
|
tvCreatorChannelFantalkTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelFantalkTime.context, item.createdAtUtc)
|
||||||
tvCreatorChannelFantalkContent.text = item.content
|
tvCreatorChannelFantalkContent.text = item.content
|
||||||
root.setOnClickListener { onItemClick(item) }
|
root.setOnClickListener { onItemClick(item) }
|
||||||
tvCreatorChannelFantalkContent.setOnClickListener { onItemClick(item) }
|
tvCreatorChannelFantalkContent.setOnClickListener { onItemClick(item) }
|
||||||
@@ -63,6 +65,7 @@ class CreatorChannelFanTalkAdapter(
|
|||||||
when (item.rightAction) {
|
when (item.rightAction) {
|
||||||
CreatorChannelFanTalkRightAction.Report -> {
|
CreatorChannelFanTalkRightAction.Report -> {
|
||||||
tvCreatorChannelFantalkReport.isVisible = true
|
tvCreatorChannelFantalkReport.isVisible = true
|
||||||
|
tvCreatorChannelFantalkReport.text = root.context.getString(R.string.creator_channel_fantalk_report)
|
||||||
tvCreatorChannelFantalkReport.setOnClickListener { onReportClick(item) }
|
tvCreatorChannelFantalkReport.setOnClickListener { onReportClick(item) }
|
||||||
ivCreatorChannelFantalkMore.isVisible = false
|
ivCreatorChannelFantalkMore.isVisible = false
|
||||||
ivCreatorChannelFantalkMore.setOnClickListener(null)
|
ivCreatorChannelFantalkMore.setOnClickListener(null)
|
||||||
@@ -84,7 +87,8 @@ class CreatorChannelFanTalkAdapter(
|
|||||||
|
|
||||||
ivCreatorChannelFantalkReplyProfile.loadProfile(reply.writerProfileImageUrl)
|
ivCreatorChannelFantalkReplyProfile.loadProfile(reply.writerProfileImageUrl)
|
||||||
tvCreatorChannelFantalkReplyNickname.text = reply.writerNickname
|
tvCreatorChannelFantalkReplyNickname.text = reply.writerNickname
|
||||||
tvCreatorChannelFantalkReplyTime.text = reply.createdAtText
|
tvCreatorChannelFantalkReplyTime.text =
|
||||||
|
formatUtcRelativeTimeText(tvCreatorChannelFantalkReplyTime.context, reply.createdAtUtc)
|
||||||
tvCreatorChannelFantalkReplyContent.text = reply.content
|
tvCreatorChannelFantalkReplyContent.text = reply.content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ internal fun bindCreatorChannelDonationCard(
|
|||||||
}
|
}
|
||||||
nicknameView.text = nickname
|
nicknameView.text = nickname
|
||||||
createdAtView.text = createdAtText
|
createdAtView.text = createdAtText
|
||||||
canView.text = context.getString(R.string.creator_channel_donation_can_format, can.moneyFormat())
|
canView.text = can.moneyFormat()
|
||||||
messageView.text = message
|
messageView.text = message
|
||||||
if (headerColorResId == R.color.red_400) {
|
if (headerColorResId == R.color.red_400) {
|
||||||
nicknameView.setTextColor(context.getColor(R.color.white))
|
nicknameView.setTextColor(context.getColor(R.color.white))
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.main
|
package kr.co.vividnext.sodalive.v2.main
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.Manifest
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -38,6 +38,8 @@ import com.google.firebase.messaging.FirebaseMessaging
|
|||||||
import com.gun0912.tedpermission.PermissionListener
|
import com.gun0912.tedpermission.PermissionListener
|
||||||
import com.gun0912.tedpermission.normal.TedPermission
|
import com.gun0912.tedpermission.normal.TedPermission
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
@@ -53,6 +55,7 @@ import kr.co.vividnext.sodalive.databinding.ActivityMainV2Binding
|
|||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.live.LiveViewModel
|
import kr.co.vividnext.sodalive.live.LiveViewModel
|
||||||
|
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
||||||
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateActivity
|
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateActivity
|
||||||
import kr.co.vividnext.sodalive.main.EventPopupDialogFragment
|
import kr.co.vividnext.sodalive.main.EventPopupDialogFragment
|
||||||
import kr.co.vividnext.sodalive.message.MessageActivity
|
import kr.co.vividnext.sodalive.message.MessageActivity
|
||||||
@@ -79,9 +82,6 @@ import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomFilter
|
|||||||
import kr.co.vividnext.sodalive.v2.main.content.ContentMainFragment
|
import kr.co.vividnext.sodalive.v2.main.content.ContentMainFragment
|
||||||
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType
|
import kr.co.vividnext.sodalive.v2.main.content.data.MainContentAllType
|
||||||
import kr.co.vividnext.sodalive.v2.main.home.HomeMainFragment
|
import kr.co.vividnext.sodalive.v2.main.home.HomeMainFragment
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@@ -108,6 +108,18 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
private var mediaControllerFuture: ListenableFuture<MediaController>? = null
|
private var mediaControllerFuture: ListenableFuture<MediaController>? = null
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private val showMiniPlayerRunnable = Runnable { initAndVisibleMiniPlayer() }
|
private val showMiniPlayerRunnable = Runnable { initAndVisibleMiniPlayer() }
|
||||||
|
private val deferredRouteRunnable = Runnable {
|
||||||
|
if (isFinishing || isDestroyed) return@Runnable
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!handleAudioNotificationRoute(intent) && isV2AccessAllowed(AccessRequirement.Login)) {
|
||||||
|
executeDeeplink(intent)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
isDeferredRouteLoading = false
|
||||||
|
updateRouteLoadingDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
private val audioContentReceiver = AudioContentReceiver()
|
private val audioContentReceiver = AudioContentReceiver()
|
||||||
private var playerStateJob: Job? = null
|
private var playerStateJob: Job? = null
|
||||||
private var isDeferredRouteLoading = false
|
private var isDeferredRouteLoading = false
|
||||||
@@ -145,13 +157,7 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
trackAppLaunchIfNeeded()
|
trackAppLaunchIfNeeded()
|
||||||
pushTokenUpdate()
|
pushTokenUpdate()
|
||||||
|
|
||||||
handler.postDelayed({
|
handler.postDelayed(deferredRouteRunnable, 1000)
|
||||||
if (!handleAudioNotificationRoute(intent) && isV2AccessAllowed(AccessRequirement.Login)) {
|
|
||||||
executeDeeplink(intent)
|
|
||||||
}
|
|
||||||
isDeferredRouteLoading = false
|
|
||||||
updateRouteLoadingDialog()
|
|
||||||
}, 1000)
|
|
||||||
|
|
||||||
if (isV2AccessAllowed(AccessRequirement.Login)) {
|
if (isV2AccessAllowed(AccessRequirement.Login)) {
|
||||||
updatePidAndGaid()
|
updatePidAndGaid()
|
||||||
@@ -178,15 +184,27 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
setIntent(intent)
|
setIntent(intent)
|
||||||
|
handler.removeCallbacks(deferredRouteRunnable)
|
||||||
|
isDeferredRouteLoading = false
|
||||||
|
updateRouteLoadingDialog()
|
||||||
|
|
||||||
if (intent.hasExtra(EXTRA_CHAT_FILTER)) {
|
if (intent.hasExtra(EXTRA_CHAT_FILTER)) {
|
||||||
openChatWithInitialFilter()
|
openChatWithInitialFilter()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!handleAudioNotificationRoute(intent) && isV2AccessAllowed(AccessRequirement.Login)) {
|
if (handleAudioNotificationRoute(intent) || !isV2AccessAllowed(AccessRequirement.Login)) {
|
||||||
executeDeeplink(intent)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (LiveRoomActivity.isForeground && isLiveRoomDeepLink(intent)) {
|
||||||
|
isDeferredRouteLoading = true
|
||||||
|
updateRouteLoadingDialog()
|
||||||
|
handler.postDelayed(deferredRouteRunnable, 1000)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
executeDeeplink(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||||
@@ -213,6 +231,9 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
handler.removeCallbacks(deferredRouteRunnable)
|
||||||
|
isDeferredRouteLoading = false
|
||||||
|
routeLoadingDialog.dismiss()
|
||||||
deInitMiniPlayer()
|
deInitMiniPlayer()
|
||||||
playerStateJob?.cancel()
|
playerStateJob?.cancel()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
@@ -315,15 +336,18 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
viewModel.clickTab(MainV2Tab.HOME)
|
viewModel.clickTab(MainV2Tab.HOME)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_main_v2_content -> {
|
R.id.menu_main_v2_content -> {
|
||||||
viewModel.clickTab(MainV2Tab.CONTENT)
|
viewModel.clickTab(MainV2Tab.CONTENT)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_main_v2_chat -> selectChatTabWithLoginGuard()
|
R.id.menu_main_v2_chat -> selectChatTabWithLoginGuard()
|
||||||
R.id.menu_main_v2_my -> {
|
R.id.menu_main_v2_my -> {
|
||||||
viewModel.clickTab(MainV2Tab.MY)
|
viewModel.clickTab(MainV2Tab.MY)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -757,19 +781,53 @@ class MainV2Activity : BaseActivity<ActivityMainV2Binding>(ActivityMainV2Binding
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun executeDeeplink(intent: Intent) {
|
private fun executeDeeplink(intent: Intent) {
|
||||||
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA) ?: return
|
val routeBundle = resolveDeepLinkBundle(intent) ?: return
|
||||||
|
|
||||||
|
if (executeBundleRoute(routeBundle)) {
|
||||||
|
clearDeferredDeepLink()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveDeepLinkBundle(intent: Intent): Bundle? {
|
||||||
|
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA) ?: return null
|
||||||
val deepLinkUrl = bundle.getString("deep_link")
|
val deepLinkUrl = bundle.getString("deep_link")
|
||||||
val routeBundle = if (!deepLinkUrl.isNullOrBlank()) {
|
return if (!deepLinkUrl.isNullOrBlank()) {
|
||||||
Bundle(bundle).apply {
|
Bundle(bundle).apply {
|
||||||
buildBundleFromDeepLinkUrl(deepLinkUrl)?.let { putAll(it) }
|
buildBundleFromDeepLinkUrl(deepLinkUrl)?.let { putAll(it) }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bundle
|
bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
if (executeBundleRoute(routeBundle)) {
|
|
||||||
clearDeferredDeepLink()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isLiveRoomDeepLink(intent: Intent): Boolean {
|
||||||
|
val bundle = resolveDeepLinkBundle(intent) ?: return false
|
||||||
|
if (isDmChatDeepLink(bundle)) return false
|
||||||
|
|
||||||
|
val roomId = bundle.getString("room_id")?.toLongOrNull()
|
||||||
|
?: bundle.getLong(Constants.EXTRA_ROOM_ID).takeIf { it > 0 }
|
||||||
|
if (roomId != null && roomId > 0) return true
|
||||||
|
if (hasDirectNonLiveRoute(bundle)) return false
|
||||||
|
|
||||||
|
val deepLinkValueId = bundle.getString("deep_link_sub5")?.toLongOrNull()
|
||||||
|
return bundle.getString("deep_link_value")?.lowercase(Locale.ROOT) == "live" &&
|
||||||
|
deepLinkValueId != null && deepLinkValueId > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasDirectNonLiveRoute(bundle: Bundle): Boolean {
|
||||||
|
fun hasPositiveId(stringKey: String, longKey: String): Boolean {
|
||||||
|
return (
|
||||||
|
bundle.getString(stringKey)?.toLongOrNull()
|
||||||
|
?: bundle.getLong(longKey).takeIf { it > 0 }
|
||||||
|
)?.let { it > 0 } == true
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasPositiveId(Constants.EXTRA_COMMUNITY_POST_ID, Constants.EXTRA_COMMUNITY_POST_ID) ||
|
||||||
|
hasPositiveId("channel_id", Constants.EXTRA_USER_ID) ||
|
||||||
|
hasPositiveId("content_id", Constants.EXTRA_AUDIO_CONTENT_ID) ||
|
||||||
|
hasPositiveId("message_id", Constants.EXTRA_MESSAGE_ID) ||
|
||||||
|
hasPositiveId(Constants.EXTRA_COMMUNITY_CREATOR_ID, Constants.EXTRA_COMMUNITY_CREATOR_ID) ||
|
||||||
|
hasPositiveId("audition_id", Constants.EXTRA_AUDITION_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildBundleFromDeepLinkUrl(deepLinkUrl: String): Bundle? {
|
private fun buildBundleFromDeepLinkUrl(deepLinkUrl: String): Bundle? {
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ package kr.co.vividnext.sodalive.v2.main.chat
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
@@ -12,9 +10,10 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
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.databinding.FragmentV2MainChatBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentV2MainChatBinding
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||||
import kr.co.vividnext.sodalive.search.SearchActivity
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
import kr.co.vividnext.sodalive.v2.access.AccessRequirement
|
import kr.co.vividnext.sodalive.v2.access.AccessRequirement
|
||||||
import kr.co.vividnext.sodalive.v2.access.ensureV2Access
|
import kr.co.vividnext.sodalive.v2.access.ensureV2Access
|
||||||
import kr.co.vividnext.sodalive.v2.chat.action.ChatActionCommand
|
import kr.co.vividnext.sodalive.v2.chat.action.ChatActionCommand
|
||||||
@@ -24,6 +23,7 @@ import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiItem
|
|||||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiState
|
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomListUiState
|
||||||
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomType
|
import kr.co.vividnext.sodalive.v2.main.chat.model.ChatRoomType
|
||||||
import kr.co.vividnext.sodalive.v2.main.chat.model.emptyMessageResId
|
import kr.co.vividnext.sodalive.v2.main.chat.model.emptyMessageResId
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.chat.recipient.DmRecipientPickerActivity
|
||||||
import kr.co.vividnext.sodalive.v2.main.chat.ui.ChatRoomListAdapter
|
import kr.co.vividnext.sodalive.v2.main.chat.ui.ChatRoomListAdapter
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
|
||||||
@@ -51,12 +51,19 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
private var isChatPullRefreshing = false
|
private var isChatPullRefreshing = false
|
||||||
private var refreshingChatFilter: ChatRoomFilter? = null
|
private var refreshingChatFilter: ChatRoomFilter? = null
|
||||||
private var lastRenderedChatContentState: ChatRoomListUiState.Content? = null
|
private var lastRenderedChatContentState: ChatRoomListUiState.Content? = null
|
||||||
|
private var shouldRefreshChatRoomsOnResume = false
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
shouldRefreshChatRoomsOnResume = false
|
||||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||||
|
|
||||||
setupTitleBar()
|
setupTitleBar()
|
||||||
|
val isCreator = SharedPreferenceManager.role == MemberRole.CREATOR.name
|
||||||
|
binding.btnNewDm.isVisible = isCreator
|
||||||
|
binding.btnNewDm.setOnClickListener {
|
||||||
|
if (isCreator) openWithLoginGuard(DmRecipientPickerActivity::class.java)
|
||||||
|
}
|
||||||
val initialFilter = getInitialFilter() ?: ChatRoomFilter.ALL
|
val initialFilter = getInitialFilter() ?: ChatRoomFilter.ALL
|
||||||
selectedFilter = initialFilter
|
selectedFilter = initialFilter
|
||||||
setupFilterTabs(initialFilter)
|
setupFilterTabs(initialFilter)
|
||||||
@@ -67,6 +74,17 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
viewModel.loadFirstPage(initialFilter)
|
viewModel.loadFirstPage(initialFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (!shouldRefreshChatRoomsOnResume) {
|
||||||
|
shouldRefreshChatRoomsOnResume = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cancelChatPullRefresh()
|
||||||
|
bindChatRooms(emptyList(), showEmpty = false)
|
||||||
|
viewModel.loadFirstPage(selectedFilter)
|
||||||
|
}
|
||||||
|
|
||||||
fun selectFilter(filter: ChatRoomFilter) {
|
fun selectFilter(filter: ChatRoomFilter) {
|
||||||
if (refreshingChatFilter != null && refreshingChatFilter != filter) {
|
if (refreshingChatFilter != null && refreshingChatFilter != filter) {
|
||||||
cancelChatPullRefresh()
|
cancelChatPullRefresh()
|
||||||
@@ -82,20 +100,6 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
binding.viewChatTitleBar.ivTitleBarMenu.setOnClickListener {
|
binding.viewChatTitleBar.ivTitleBarMenu.setOnClickListener {
|
||||||
openWithLoginGuard(CanChargeActivity::class.java)
|
openWithLoginGuard(CanChargeActivity::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
val searchAction = ImageView(requireContext()).apply {
|
|
||||||
setImageResource(R.drawable.ic_bar_search)
|
|
||||||
layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
).apply {
|
|
||||||
marginStart = resources.getDimensionPixelSize(R.dimen.spacing_14)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
searchAction.setOnClickListener {
|
|
||||||
openWithLoginGuard(SearchActivity::class.java)
|
|
||||||
}
|
|
||||||
binding.viewChatTitleBar.llTitleBarActions.addView(searchAction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openWithLoginGuard(activityClass: Class<*>) {
|
private fun openWithLoginGuard(activityClass: Class<*>) {
|
||||||
@@ -174,6 +178,7 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
binding.rvChatRooms.scrollToPosition(0)
|
binding.rvChatRooms.scrollToPosition(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatRoomListUiState.Empty -> {
|
ChatRoomListUiState.Empty -> {
|
||||||
lastRenderedChatContentState = null
|
lastRenderedChatContentState = null
|
||||||
bindChatRooms(emptyList(), showEmpty = true)
|
bindChatRooms(emptyList(), showEmpty = true)
|
||||||
@@ -182,6 +187,7 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
refreshingChatFilter = null
|
refreshingChatFilter = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ChatRoomListUiState.Error -> {
|
is ChatRoomListUiState.Error -> {
|
||||||
lastRenderedChatContentState = null
|
lastRenderedChatContentState = null
|
||||||
if (!isChatPullRefreshing || !isRefreshForCurrentFilter) {
|
if (!isChatPullRefreshing || !isRefreshForCurrentFilter) {
|
||||||
@@ -192,6 +198,7 @@ class ChatMainFragment : BaseFragment<FragmentV2MainChatBinding>(
|
|||||||
refreshingChatFilter = null
|
refreshingChatFilter = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatRoomListUiState.Loading -> {
|
ChatRoomListUiState.Loading -> {
|
||||||
if (!isChatPullRefreshing) {
|
if (!isChatPullRefreshing) {
|
||||||
binding.tvChatEmptyMessage.isVisible = false
|
binding.tvChatEmptyMessage.isVisible = false
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import com.google.gson.annotations.SerializedName
|
|||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
data class CreateDmChatRoomRequest(
|
data class CreateDmChatRoomRequest(
|
||||||
@SerializedName("creatorId") val creatorId: Long
|
@SerializedName("recipientId") val recipientId: Long? = null,
|
||||||
|
@SerializedName("creatorId") val creatorId: Long? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
|
|||||||
@@ -18,6 +18,14 @@ class DmChatRepository(
|
|||||||
request = CreateDmChatRoomRequest(creatorId = creatorId)
|
request = CreateDmChatRoomRequest(creatorId = creatorId)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun createOrGetRoomByRecipientId(
|
||||||
|
token: String,
|
||||||
|
recipientId: Long
|
||||||
|
): Single<ApiResponse<CreateDmChatRoomResponse>> = api.createDmChatRoom(
|
||||||
|
authHeader = bearer(token),
|
||||||
|
request = CreateDmChatRoomRequest(recipientId = recipientId)
|
||||||
|
)
|
||||||
|
|
||||||
fun openRoom(
|
fun openRoom(
|
||||||
token: String,
|
token: String,
|
||||||
roomId: Long,
|
roomId: Long,
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemDmRecipientBinding
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.home.ui.loadHomeCreatorProfileImage
|
||||||
|
|
||||||
|
class DmRecipientAdapter(
|
||||||
|
private val onClick: (DmRecipientUiModel) -> Unit
|
||||||
|
) : RecyclerView.Adapter<DmRecipientAdapter.RecipientViewHolder>() {
|
||||||
|
private var items: List<DmRecipientUiModel> = emptyList()
|
||||||
|
|
||||||
|
fun submitItems(items: List<DmRecipientUiModel>) {
|
||||||
|
this.items = items
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = items.size
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecipientViewHolder =
|
||||||
|
RecipientViewHolder(ItemDmRecipientBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecipientViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class RecipientViewHolder(private val binding: ItemDmRecipientBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: DmRecipientUiModel) {
|
||||||
|
binding.ivProfile.loadHomeCreatorProfileImage(item.profileImageUrl)
|
||||||
|
binding.tvNickname.text = item.nickname
|
||||||
|
binding.root.setOnClickListener { onClick(item) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.Spanned
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.doAfterTextChanged
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityDmRecipientPickerBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.user.UserRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.chat.dm.data.DmChatRepository
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class DmRecipientPickerActivity : BaseActivity<ActivityDmRecipientPickerBinding>(
|
||||||
|
ActivityDmRecipientPickerBinding::inflate
|
||||||
|
) {
|
||||||
|
private val explorerRepository: ExplorerRepository by inject()
|
||||||
|
private val userRepository: UserRepository by inject()
|
||||||
|
private val dmRepository: DmChatRepository by inject()
|
||||||
|
private val viewModel: DmRecipientPickerViewModel by viewModels {
|
||||||
|
dmRecipientPickerFactory(explorerRepository, userRepository)
|
||||||
|
}
|
||||||
|
private val adapter = DmRecipientAdapter(::confirmRecipient)
|
||||||
|
private val loadingDialog by lazy { LoadingDialog(this, layoutInflater) }
|
||||||
|
private var isOpeningRoom = false
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
if (SharedPreferenceManager.role != MemberRole.CREATOR.name) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
binding.btnBack.setOnClickListener { finish() }
|
||||||
|
binding.rvRecipients.layoutManager = LinearLayoutManager(this)
|
||||||
|
binding.rvRecipients.adapter = adapter
|
||||||
|
binding.etSearchNickname.doAfterTextChanged {
|
||||||
|
viewModel.onSearchQueryChanged(it?.toString().orEmpty())
|
||||||
|
}
|
||||||
|
viewModel.recipientStateLiveData.observe(this) { state ->
|
||||||
|
adapter.submitItems(state.recipients)
|
||||||
|
binding.tvFollowers.isVisible = state.mode == DmRecipientPickerMode.FOLLOWERS && state.recipients.isNotEmpty()
|
||||||
|
binding.tvSearchResultCount.isVisible = state.mode == DmRecipientPickerMode.SEARCH
|
||||||
|
val searchResultCount = state.searchResultCount.toString()
|
||||||
|
val searchResultText = getString(
|
||||||
|
R.string.dm_recipient_search_result_count,
|
||||||
|
state.searchResultCount
|
||||||
|
)
|
||||||
|
binding.tvSearchResultCount.text = SpannableString(searchResultText).apply {
|
||||||
|
val start = searchResultText.lastIndexOf(searchResultCount)
|
||||||
|
setSpan(
|
||||||
|
ForegroundColorSpan(ContextCompat.getColor(this@DmRecipientPickerActivity, R.color.gray_500)),
|
||||||
|
start,
|
||||||
|
start + searchResultCount.length,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.tvSearchEmpty.isVisible = state.isSearchEmpty
|
||||||
|
binding.rvRecipients.isVisible = !state.isSearchEmpty
|
||||||
|
if (state.isError) showToast(getString(R.string.common_error_request))
|
||||||
|
}
|
||||||
|
viewModel.enter()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun confirmRecipient(recipient: DmRecipientUiModel) {
|
||||||
|
if (isOpeningRoom) return
|
||||||
|
V2ModalDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = getString(R.string.dm_recipient_confirm_title),
|
||||||
|
desc = getString(R.string.dm_recipient_confirm_message, recipient.nickname),
|
||||||
|
cancelButtonTitle = getString(R.string.cancel),
|
||||||
|
confirmButtonTitle = getString(R.string.dm_recipient_send),
|
||||||
|
confirmButtonClick = { openRoom(recipient.id) }
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openRoom(recipientId: Long) {
|
||||||
|
if (isOpeningRoom) return
|
||||||
|
isOpeningRoom = true
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
compositeDisposable.add(
|
||||||
|
dmRepository.createOrGetRoomByRecipientId(SharedPreferenceManager.token, recipientId)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doFinally {
|
||||||
|
isOpeningRoom = false
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
.subscribe({ response ->
|
||||||
|
val data = response.data
|
||||||
|
if (response.success && data != null) {
|
||||||
|
startActivity(DmChatRoomActivity.newIntentByRoomId(this, data.roomId))
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
showToast(getString(R.string.common_error_request))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
showToast(getString(R.string.common_error_request))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
|
import kr.co.vividnext.sodalive.user.UserRepository
|
||||||
|
|
||||||
|
internal fun dmRecipientPickerFactory(
|
||||||
|
explorerRepository: ExplorerRepository,
|
||||||
|
userRepository: UserRepository
|
||||||
|
) = viewModelFactory {
|
||||||
|
initializer {
|
||||||
|
DmRecipientPickerViewModel(
|
||||||
|
loadFollowers = {
|
||||||
|
explorerRepository.getFollowerList(
|
||||||
|
userId = SharedPreferenceManager.userId,
|
||||||
|
page = 1,
|
||||||
|
size = 20,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
).map { response ->
|
||||||
|
val data = response.data
|
||||||
|
check(response.success && data != null)
|
||||||
|
data.items.map { DmRecipientUiModel(it.userId, it.nickname, it.profileImage) }
|
||||||
|
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||||
|
},
|
||||||
|
searchUsers = { nickname ->
|
||||||
|
userRepository.searchUser(nickname, "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.map { response ->
|
||||||
|
val data = response.data
|
||||||
|
check(response.success && data != null)
|
||||||
|
data.map { DmRecipientUiModel(it.id, it.nickname, it.profileImageUrl) }
|
||||||
|
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||||
|
},
|
||||||
|
debounceScheduler = AndroidSchedulers.mainThread()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import io.reactivex.rxjava3.core.Scheduler
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
|
import io.reactivex.rxjava3.disposables.SerialDisposable
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
data class DmRecipientUiModel(
|
||||||
|
val id: Long,
|
||||||
|
val nickname: String,
|
||||||
|
val profileImageUrl: String
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class DmRecipientPickerMode {
|
||||||
|
FOLLOWERS,
|
||||||
|
SEARCH
|
||||||
|
}
|
||||||
|
|
||||||
|
data class DmRecipientPickerUiState(
|
||||||
|
val mode: DmRecipientPickerMode = DmRecipientPickerMode.FOLLOWERS,
|
||||||
|
val recipients: List<DmRecipientUiModel> = emptyList(),
|
||||||
|
val searchResultCount: Int = 0,
|
||||||
|
val isSearchEmpty: Boolean = false,
|
||||||
|
val isError: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
class DmRecipientPickerViewModel(
|
||||||
|
private val loadFollowers: () -> Single<List<DmRecipientUiModel>>,
|
||||||
|
private val searchUsers: (String) -> Single<List<DmRecipientUiModel>>,
|
||||||
|
private val debounceScheduler: Scheduler = Schedulers.computation()
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
private val _recipientStateLiveData = MutableLiveData(DmRecipientPickerUiState())
|
||||||
|
val recipientStateLiveData: LiveData<DmRecipientPickerUiState> get() = _recipientStateLiveData
|
||||||
|
private var searchDisposable: Disposable? = null
|
||||||
|
private val requestDisposable = SerialDisposable().also(compositeDisposable::add)
|
||||||
|
|
||||||
|
fun enter() {
|
||||||
|
requestDisposable.set(null)
|
||||||
|
requestDisposable.set(
|
||||||
|
loadFollowers()
|
||||||
|
.subscribe({ recipients ->
|
||||||
|
_recipientStateLiveData.value = DmRecipientPickerUiState(
|
||||||
|
mode = DmRecipientPickerMode.FOLLOWERS,
|
||||||
|
recipients = recipients
|
||||||
|
)
|
||||||
|
}, {
|
||||||
|
_recipientStateLiveData.value = DmRecipientPickerUiState(isError = true)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onSearchQueryChanged(query: String) {
|
||||||
|
val keyword = query.trim()
|
||||||
|
searchDisposable?.dispose()
|
||||||
|
requestDisposable.set(null)
|
||||||
|
|
||||||
|
if (keyword.length < MIN_SEARCH_QUERY_LENGTH) {
|
||||||
|
enter()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val scheduledSearch = debounceScheduler.scheduleDirect(
|
||||||
|
{
|
||||||
|
requestDisposable.set(
|
||||||
|
searchUsers(keyword).subscribe({ recipients ->
|
||||||
|
_recipientStateLiveData.value = DmRecipientPickerUiState(
|
||||||
|
mode = DmRecipientPickerMode.SEARCH,
|
||||||
|
recipients = recipients,
|
||||||
|
searchResultCount = recipients.size,
|
||||||
|
isSearchEmpty = recipients.isEmpty()
|
||||||
|
)
|
||||||
|
}, {
|
||||||
|
_recipientStateLiveData.value = DmRecipientPickerUiState(
|
||||||
|
mode = DmRecipientPickerMode.SEARCH,
|
||||||
|
isError = true
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
},
|
||||||
|
SEARCH_DEBOUNCE_MILLIS,
|
||||||
|
TimeUnit.MILLISECONDS
|
||||||
|
)
|
||||||
|
searchDisposable = scheduledSearch
|
||||||
|
compositeDisposable.add(scheduledSearch)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val MIN_SEARCH_QUERY_LENGTH = 2
|
||||||
|
const val SEARCH_DEBOUNCE_MILLIS = 500L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 288 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 549 B |
|
Before Width: | Height: | Size: 603 B |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 482 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 847 B |
|
After Width: | Height: | Size: 286 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -27,7 +27,7 @@
|
|||||||
android:textSize="18.3sp"
|
android:textSize="18.3sp"
|
||||||
app:drawableStartCompat="@drawable/ic_back"
|
app:drawableStartCompat="@drawable/ic_back"
|
||||||
tools:ignore="RelativeOverlap"
|
tools:ignore="RelativeOverlap"
|
||||||
tools:text="보이스온" />
|
tools:text="소다라이브" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -226,6 +226,14 @@
|
|||||||
tools:src="@drawable/ic_bar_bell"
|
tools:src="@drawable/ic_bar_bell"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_share"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:contentDescription="@string/screen_user_profile_share_channel"
|
||||||
|
android:src="@drawable/ic_audio_content_share"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_more"
|
android:id="@+id/iv_more"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
|
|||||||
@@ -53,6 +53,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_creator_channel_community_detail_creator"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/btn_creator_channel_community_detail_more"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_creator_channel_community_detail_profile"
|
android:id="@+id/iv_creator_channel_community_detail_profile"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
@@ -73,7 +81,7 @@
|
|||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
app:layout_constraintEnd_toStartOf="@id/btn_creator_channel_community_detail_more"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/iv_creator_channel_community_detail_profile"
|
app:layout_constraintStart_toEndOf="@id/iv_creator_channel_community_detail_profile"
|
||||||
app:layout_constraintTop_toTopOf="@id/iv_creator_channel_community_detail_profile"
|
app:layout_constraintTop_toTopOf="@id/iv_creator_channel_community_detail_profile"
|
||||||
tools:text="크리에이터" />
|
tools:text="크리에이터" />
|
||||||
@@ -91,6 +99,8 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@id/tv_creator_channel_community_detail_nickname"
|
app:layout_constraintTop_toBottomOf="@id/tv_creator_channel_community_detail_nickname"
|
||||||
tools:text="2분 전" />
|
tools:text="2분 전" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/btn_creator_channel_community_detail_more"
|
android:id="@+id/btn_creator_channel_community_detail_more"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:includeFontPadding="false"
|
android:includeFontPadding="false"
|
||||||
android:text="/500자"
|
android:text="/500"
|
||||||
android:textColor="@color/gray_500" />
|
android:textColor="@color/gray_500" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/black"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="54dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btn_back"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:padding="@dimen/spacing_12"
|
||||||
|
android:src="@drawable/ic_back" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/search_container"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginEnd="@dimen/spacing_14"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_round_corner_10_232323"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_12">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_search"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_title_search_black" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et_search_nickname"
|
||||||
|
style="@style/Typography.Body3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/spacing_8"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/dm_recipient_search_hint"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/color_979797"
|
||||||
|
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||||
|
tools:ignore="LabelFor" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_followers"
|
||||||
|
style="@style/Typography.Body1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_14"
|
||||||
|
android:text="@string/dm_recipient_followers"
|
||||||
|
android:textColor="@color/color_e2e2e2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_search_result_count"
|
||||||
|
style="@style/Typography.Body1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_14"
|
||||||
|
android:text="@string/dm_recipient_search_result_count"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="검색결과 0" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/recipient_content_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_recipients"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_search_empty"
|
||||||
|
style="@style/Typography.Body5"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="@dimen/spacing_20"
|
||||||
|
android:text="@string/dm_recipient_search_empty"
|
||||||
|
android:textColor="@color/color_777777"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
android:fontFamily="@font/medium"
|
android:fontFamily="@font/medium"
|
||||||
android:textColor="@color/color_eeeeee"
|
android:textColor="@color/color_eeeeee"
|
||||||
android:textSize="14.7sp"
|
android:textSize="14.7sp"
|
||||||
tools:text="보이스온 App 오픈 관련 공지사항입니다." />
|
tools:text="소다라이브 App 오픈 관련 공지사항입니다." />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_date"
|
android:id="@+id/tv_date"
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
android:textSize="18.3sp"
|
android:textSize="18.3sp"
|
||||||
app:drawableStartCompat="@drawable/ic_back"
|
app:drawableStartCompat="@drawable/ic_back"
|
||||||
tools:ignore="RelativeOverlap"
|
tools:ignore="RelativeOverlap"
|
||||||
tools:text="보이스온" />
|
tools:text="소다라이브" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
|||||||
@@ -15,17 +15,19 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/Typography.Heading3"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/screen_splash_tagline"
|
|
||||||
android:textColor="@color/white" />
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/splash_text_logo" />
|
android:src="@drawable/splash_text_logo" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/Typography.Heading4"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/spacing_8"
|
||||||
|
android:text="@string/screen_splash_tagline"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -21,6 +21,6 @@
|
|||||||
android:textSize="18.3sp"
|
android:textSize="18.3sp"
|
||||||
app:drawableStartCompat="@drawable/ic_back"
|
app:drawableStartCompat="@drawable/ic_back"
|
||||||
tools:ignore="RelativeOverlap"
|
tools:ignore="RelativeOverlap"
|
||||||
tools:text="보이스온" />
|
tools:text="소다라이브" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|||||||
@@ -16,6 +16,16 @@
|
|||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:background="@drawable/bg_bottom_sheet_handle" />
|
android:background="@drawable/bg_bottom_sheet_handle" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_channel_share"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:paddingVertical="16dp"
|
||||||
|
android:text="@string/screen_user_profile_share_channel"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/tv_user_block"
|
android:id="@+id/tv_user_block"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -222,7 +222,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:fontFamily="@font/bold"
|
android:fontFamily="@font/bold"
|
||||||
android:text="@string/voiceon_original_only"
|
android:text="@string/sodalive_original_only"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="24sp" />
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
|||||||
@@ -291,18 +291,20 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="32dp"
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_marginBottom="@dimen/spacing_32"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/img_apply_creator" />
|
android:src="@drawable/img_apply_creator" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/iv_introduce_voiceon"
|
android:id="@+id/iv_introduce_sodalive"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:src="@drawable/img_introduce_voiceon" />
|
android:src="@drawable/img_introduce_sodalive" />
|
||||||
|
|
||||||
<!-- Recent Content Section -->
|
<!-- Recent Content Section -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -58,4 +58,17 @@
|
|||||||
tools:text="아직 나눈 대화가 없어요.\n크리에이터와 이야기를 시작해 보세요." />
|
tools:text="아직 나눈 대화가 없어요.\n크리에이터와 이야기를 시작해 보세요." />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btn_new_dm"
|
||||||
|
android:layout_width="66dp"
|
||||||
|
android:layout_height="66dp"
|
||||||
|
android:layout_margin="@dimen/spacing_14"
|
||||||
|
android:background="@drawable/bg_creator_channel_owner_fab"
|
||||||
|
android:contentDescription="@string/screen_chat_floating_button"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:padding="@dimen/spacing_14"
|
||||||
|
android:src="@drawable/ic_new_talk_add"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="2dp"
|
android:layout_marginStart="2dp"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
tools:text="20캔" />
|
tools:text="20" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|||||||