Compare commits
95 Commits
7e32727773
...
6fbb98ca7b
Author | SHA1 | Date |
---|---|---|
|
6fbb98ca7b | |
|
b33c8ffd6d | |
|
14b3bfbae7 | |
|
7386c93d73 | |
|
4af8d7dce1 | |
|
08d2ccdab4 | |
|
0a8abeefbe | |
|
f90e089f8a | |
|
1eb905fe30 | |
|
fcc55288b1 | |
|
97c5dc4363 | |
|
4223f0bc5d | |
|
7ada4515aa | |
|
8456f2b30b | |
|
c20802f89c | |
|
804f993b25 | |
|
869b83804d | |
|
9d97feb184 | |
|
42a69609a1 | |
|
3a541f71a6 | |
|
d75e4af348 | |
|
2dac54b3ec | |
|
82cf1658cb | |
|
127e1f6673 | |
|
22f1e4024e | |
|
b0bfe2ac06 | |
|
d67bb8be50 | |
|
eeac702cd7 | |
|
c2216ab054 | |
|
45e5494653 | |
|
5f7ed22711 | |
|
49a823895d | |
|
92324e3409 | |
|
13057af98a | |
|
144ff4af05 | |
|
315e0627d1 | |
|
4bd6a766f5 | |
|
32f99cc678 | |
|
bd1800c2b5 | |
|
bf3e6230a0 | |
|
2400123a92 | |
|
525e399423 | |
|
5da644a607 | |
|
3d231ea8be | |
|
d9ad230804 | |
|
41a92a871d | |
|
5634e0787f | |
|
8a7406aa22 | |
|
ab24042863 | |
|
5d3891c1db | |
|
7d9fc13192 | |
|
12f944c79d | |
|
e0da65e64f | |
|
857b4de792 | |
|
c896be5ece | |
|
6c96c4afe5 | |
|
6b2e59c09d | |
|
481cad1a46 | |
|
62ecf3dd51 | |
|
116dde1b7e | |
|
5db097d67c | |
|
fbcdbf3b48 | |
|
479f956db3 | |
|
72d16c4d18 | |
|
2984aac0a5 | |
|
8ddf85c1be | |
|
8f3a2f16ad | |
|
6a72bc63c0 | |
|
f74d8bfc16 | |
|
29e293e6b5 | |
|
2883c63e07 | |
|
dfaf45a83d | |
|
c2b99552da | |
|
e4a92e0f2b | |
|
dabf8563b8 | |
|
fb9c138eb4 | |
|
7da0e2509c | |
|
63c2d607cc | |
|
9f66cb91fc | |
|
91db6caec9 | |
|
4a4940f04d | |
|
952df91619 | |
|
b359ca58ba | |
|
fe121ee89b | |
|
9e3859e2c2 | |
|
f4ca63af9d | |
|
61ee1fc5be | |
|
ead7aa3011 | |
|
720df22df5 | |
|
74c56c2061 | |
|
e391fcbb6e | |
|
87e1156b02 | |
|
a77708dfbf | |
|
664f34ed5b | |
|
48d1db3b79 |
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="deploymentTargetDropDown">
|
||||||
|
<value>
|
||||||
|
<entry key="app">
|
||||||
|
<State />
|
||||||
|
</entry>
|
||||||
|
</value>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectMigrations">
|
||||||
|
<option name="MigrateToGradleLocalJavaHome">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -40,8 +40,8 @@ android {
|
||||||
applicationId "kr.co.vividnext.sodalive"
|
applicationId "kr.co.vividnext.sodalive"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 10
|
versionCode 19
|
||||||
versionName "1.1.0"
|
versionName "1.4.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -138,7 +138,7 @@ dependencies {
|
||||||
implementation "io.github.bootpay:android:4.3.4"
|
implementation "io.github.bootpay:android:4.3.4"
|
||||||
|
|
||||||
// agora
|
// agora
|
||||||
implementation "io.agora.rtc:voice-sdk:4.1.0-1"
|
implementation "io.agora.rtc:voice-sdk:4.2.6"
|
||||||
implementation 'io.agora.rtm:rtm-sdk:1.5.3'
|
implementation 'io.agora.rtm:rtm-sdk:1.5.3'
|
||||||
|
|
||||||
// sound visualizer
|
// sound visualizer
|
||||||
|
@ -149,7 +149,4 @@ dependencies {
|
||||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
|
|
||||||
implementation "com.michalsvec:single-row-calednar:1.0.0"
|
implementation "com.michalsvec:single-row-calednar:1.0.0"
|
||||||
|
|
||||||
// PointClick Maven Remote Repo
|
|
||||||
implementation 'kr.co.pointclick.sdk.offerwall:pointclick-sdk-offerwall:1.0.17'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
|
@ -85,6 +86,7 @@
|
||||||
<activity android:name=".mypage.can.status.CanStatusActivity" />
|
<activity android:name=".mypage.can.status.CanStatusActivity" />
|
||||||
<activity android:name=".mypage.can.charge.CanChargeActivity" />
|
<activity android:name=".mypage.can.charge.CanChargeActivity" />
|
||||||
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
||||||
|
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
||||||
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
||||||
<activity android:name=".live.room.update.LiveRoomEditActivity" />
|
<activity android:name=".live.room.update.LiveRoomEditActivity" />
|
||||||
<activity android:name=".live.reservation.complete.LiveReservationCompleteActivity" />
|
<activity android:name=".live.reservation.complete.LiveReservationCompleteActivity" />
|
||||||
|
@ -94,8 +96,10 @@
|
||||||
<activity android:name=".explorer.profile.UserProfileActivity" />
|
<activity android:name=".explorer.profile.UserProfileActivity" />
|
||||||
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
|
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
|
||||||
<activity android:name=".explorer.profile.fantalk.UserProfileFantalkAllViewActivity" />
|
<activity android:name=".explorer.profile.fantalk.UserProfileFantalkAllViewActivity" />
|
||||||
<activity android:name=".explorer.profile.CreatorNoticeWriteActivity" />
|
|
||||||
<activity android:name=".explorer.profile.follow.UserFollowerListActivity" />
|
<activity android:name=".explorer.profile.follow.UserFollowerListActivity" />
|
||||||
|
<activity android:name=".explorer.profile.creator_community.all.CreatorCommunityAllActivity" />
|
||||||
|
<activity android:name=".explorer.profile.creator_community.write.CreatorCommunityWriteActivity" />
|
||||||
|
<activity android:name=".explorer.profile.creator_community.modify.CreatorCommunityModifyActivity" />
|
||||||
<activity android:name=".message.text.TextMessageWriteActivity" />
|
<activity android:name=".message.text.TextMessageWriteActivity" />
|
||||||
<activity android:name=".message.text.TextMessageDetailActivity" />
|
<activity android:name=".message.text.TextMessageDetailActivity" />
|
||||||
<activity android:name=".message.SelectMessageRecipientActivity" />
|
<activity android:name=".message.SelectMessageRecipientActivity" />
|
||||||
|
@ -124,6 +128,7 @@
|
||||||
<activity android:name=".audio_content.curation.AudioContentCurationActivity" />
|
<activity android:name=".audio_content.curation.AudioContentCurationActivity" />
|
||||||
<activity android:name=".audio_content.all.AudioContentNewAllActivity" />
|
<activity android:name=".audio_content.all.AudioContentNewAllActivity" />
|
||||||
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
||||||
|
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||||
|
@ -134,9 +139,13 @@
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".common.SodaLiveService"
|
android:name=".common.SodaLiveService"
|
||||||
|
android:foregroundServiceType="microphone|mediaPlayback"
|
||||||
android:stopWithTask="false" />
|
android:stopWithTask="false" />
|
||||||
|
|
||||||
<service android:name=".audio_content.AudioContentPlayService" />
|
<service
|
||||||
|
android:name=".audio_content.AudioContentPlayService"
|
||||||
|
android:foregroundServiceType="mediaPlayback"
|
||||||
|
android:stopWithTask="false" />
|
||||||
|
|
||||||
<!-- [START firebase_service] -->
|
<!-- [START firebase_service] -->
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||||
import com.orhanobut.logger.AndroidLogAdapter
|
import com.orhanobut.logger.AndroidLogAdapter
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
import kr.co.vividnext.sodalive.BuildConfig
|
import kr.co.vividnext.sodalive.BuildConfig
|
||||||
|
import kr.co.vividnext.sodalive.common.ImageLoaderProvider
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.di.AppDI
|
import kr.co.vividnext.sodalive.di.AppDI
|
||||||
|
|
||||||
|
@ -26,6 +27,8 @@ class SodaLiveApp : Application() {
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
|
|
||||||
SharedPreferenceManager.init(applicationContext)
|
SharedPreferenceManager.init(applicationContext)
|
||||||
|
|
||||||
|
ImageLoaderProvider.init(applicationContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isDebuggable(): Boolean {
|
private fun isDebuggable(): Boolean {
|
||||||
|
|
|
@ -43,6 +43,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
||||||
) {
|
) {
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
viewModel.page = 1
|
viewModel.page = 1
|
||||||
|
viewModel.isLast = false
|
||||||
viewModel.getAudioContentList(userId = userId) { finish() }
|
viewModel.getAudioContentList(userId = userId) { finish() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content
|
package kr.co.vividnext.sodalive.audio_content
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
|
@ -33,6 +34,12 @@ class AudioContentAdapter(
|
||||||
binding.tvLikeCount.text = item.likeCount.moneyFormat()
|
binding.tvLikeCount.text = item.likeCount.moneyFormat()
|
||||||
binding.tvCommentCount.text = item.commentCount.moneyFormat()
|
binding.tvCommentCount.text = item.commentCount.moneyFormat()
|
||||||
|
|
||||||
|
binding.tvScheduledToOpen.visibility = if (item.isScheduledToOpen) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
if (item.price < 1) {
|
if (item.price < 1) {
|
||||||
binding.tvPrice.text = "무료"
|
binding.tvPrice.text = "무료"
|
||||||
binding.tvPrice.setCompoundDrawables(null, null, null, null)
|
binding.tvPrice.setCompoundDrawables(null, null, null, null)
|
||||||
|
|
|
@ -10,9 +10,11 @@ import kr.co.vividnext.sodalive.audio_content.detail.GetAudioContentDetailRespon
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest
|
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeResponse
|
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeResponse
|
||||||
import kr.co.vividnext.sodalive.audio_content.donation.AudioContentDonationRequest
|
import kr.co.vividnext.sodalive.audio_content.donation.AudioContentDonationRequest
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentCurationResponse
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainResponse
|
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRanking
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRanking
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetNewContentUploadCreator
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse
|
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
|
import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
|
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
|
||||||
|
@ -125,11 +127,6 @@ interface AudioContentApi {
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<Any>>
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
@GET("/audio-content/main")
|
|
||||||
fun getMain(
|
|
||||||
@Header("Authorization") authHeader: String
|
|
||||||
): Single<ApiResponse<GetAudioContentMainResponse>>
|
|
||||||
|
|
||||||
@GET("/audio-content/main/new")
|
@GET("/audio-content/main/new")
|
||||||
fun getNewContentOfTheme(
|
fun getNewContentOfTheme(
|
||||||
@Query("theme") theme: String,
|
@Query("theme") theme: String,
|
||||||
|
@ -182,4 +179,26 @@ interface AudioContentApi {
|
||||||
@Query("sort-type") sortType: String,
|
@Query("sort-type") sortType: String,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<GetAudioContentRanking>>
|
): Single<ApiResponse<GetAudioContentRanking>>
|
||||||
|
|
||||||
|
@GET("/audio-content/main/curation-list")
|
||||||
|
fun getCurationList(
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetAudioContentCurationResponse>>>
|
||||||
|
|
||||||
|
@GET("/audio-content/main/new-content-upload-creator")
|
||||||
|
fun getNewContentUploadCreatorList(
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetNewContentUploadCreator>>>
|
||||||
|
|
||||||
|
@GET("/audio-content/main/banner-list")
|
||||||
|
fun getMainBannerList(
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetAudioContentBannerResponse>>>
|
||||||
|
|
||||||
|
@GET("/audio-content/main/order-list")
|
||||||
|
fun getMainOrderList(
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetAudioContentMainItem>>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,8 +129,6 @@ class AudioContentRepository(
|
||||||
token: String
|
token: String
|
||||||
) = api.likeContent(request, authHeader = token)
|
) = api.likeContent(request, authHeader = token)
|
||||||
|
|
||||||
fun getMain(token: String) = api.getMain(authHeader = token)
|
|
||||||
|
|
||||||
fun getNewContentOfTheme(theme: String, token: String) = api.getNewContentOfTheme(
|
fun getNewContentOfTheme(theme: String, token: String) = api.getNewContentOfTheme(
|
||||||
theme = theme,
|
theme = theme,
|
||||||
authHeader = token
|
authHeader = token
|
||||||
|
@ -177,4 +175,17 @@ class AudioContentRepository(
|
||||||
sortType = sortType,
|
sortType = sortType,
|
||||||
authHeader = token
|
authHeader = token
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun getCurationList(page: Int, size: Int, token: String) = api.getCurationList(
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getNewContentUploadCreatorList(
|
||||||
|
token: String
|
||||||
|
) = api.getNewContentUploadCreatorList(authHeader = token)
|
||||||
|
|
||||||
|
fun getMainBannerList(token: String) = api.getMainBannerList(authHeader = token)
|
||||||
|
fun getMainOrderList(token: String) = api.getMainOrderList(authHeader = token)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
|
||||||
PRICE_LOW
|
PRICE_LOW
|
||||||
}
|
}
|
||||||
|
|
||||||
private var isLast = false
|
var isLast = false
|
||||||
var page = 1
|
var page = 1
|
||||||
private val size = 10
|
private val size = 10
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainNewContentThemeAdapter
|
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentThemeAdapter
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
|
|
@ -9,7 +9,7 @@ import android.widget.Toast
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainNewContentThemeAdapter
|
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentThemeAdapter
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
|
|
@ -44,27 +44,27 @@ class AudioContentCommentAdapter(
|
||||||
binding.tvDonationCan.text = can.moneyFormat()
|
binding.tvDonationCan.text = can.moneyFormat()
|
||||||
binding.llDonationCan.setBackgroundResource(
|
binding.llDonationCan.setBackgroundResource(
|
||||||
when {
|
when {
|
||||||
can >= 100000 -> {
|
can >= 10000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_973a3a
|
R.drawable.bg_round_corner_10_7_973a3a
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 50000 -> {
|
can >= 5000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_d85e37
|
R.drawable.bg_round_corner_10_7_d85e37
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 10000 -> {
|
can >= 1000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_d38c38
|
R.drawable.bg_round_corner_10_7_d38c38
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 5000 -> {
|
can >= 500 -> {
|
||||||
R.drawable.bg_round_corner_10_7_59548f
|
R.drawable.bg_round_corner_10_7_59548f
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 1000 -> {
|
can >= 100 -> {
|
||||||
R.drawable.bg_round_corner_10_7_4d6aa4
|
R.drawable.bg_round_corner_10_7_4d6aa4
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 500 -> {
|
can >= 50 -> {
|
||||||
R.drawable.bg_round_corner_10_7_2d7390
|
R.drawable.bg_round_corner_10_7_2d7390
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,27 +124,27 @@ class AudioContentCommentReplyHeaderViewHolder(
|
||||||
binding.tvDonationCan.text = can.moneyFormat()
|
binding.tvDonationCan.text = can.moneyFormat()
|
||||||
binding.llDonationCan.setBackgroundResource(
|
binding.llDonationCan.setBackgroundResource(
|
||||||
when {
|
when {
|
||||||
can >= 100000 -> {
|
can >= 10000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_973a3a
|
R.drawable.bg_round_corner_10_7_973a3a
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 50000 -> {
|
can >= 5000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_d85e37
|
R.drawable.bg_round_corner_10_7_d85e37
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 10000 -> {
|
can >= 1000 -> {
|
||||||
R.drawable.bg_round_corner_10_7_d38c38
|
R.drawable.bg_round_corner_10_7_d38c38
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 5000 -> {
|
can >= 500 -> {
|
||||||
R.drawable.bg_round_corner_10_7_59548f
|
R.drawable.bg_round_corner_10_7_59548f
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 1000 -> {
|
can >= 100 -> {
|
||||||
R.drawable.bg_round_corner_10_7_4d6aa4
|
R.drawable.bg_round_corner_10_7_4d6aa4
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 500 -> {
|
can >= 50 -> {
|
||||||
R.drawable.bg_round_corner_10_7_2d7390
|
R.drawable.bg_round_corner_10_7_2d7390
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import android.widget.RelativeLayout
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
|
@ -60,10 +61,6 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
private var creatorId: Long = 0
|
private var creatorId: Long = 0
|
||||||
|
|
||||||
private var refresh = false
|
private var refresh = false
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
setResult(RESULT_OK)
|
|
||||||
}
|
|
||||||
private var title = ""
|
private var title = ""
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
@ -97,7 +94,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val intentFilter = IntentFilter(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
|
val intentFilter = IntentFilter(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
|
||||||
registerReceiver(audioContentReceiver, intentFilter)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
registerReceiver(audioContentReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
|
||||||
|
} else {
|
||||||
|
registerReceiver(audioContentReceiver, intentFilter)
|
||||||
|
}
|
||||||
|
|
||||||
if (refresh) {
|
if (refresh) {
|
||||||
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
||||||
|
@ -283,6 +284,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
when (it.itemId) {
|
when (it.itemId) {
|
||||||
R.id.menu_modify -> {
|
R.id.menu_modify -> {
|
||||||
refresh = true
|
refresh = true
|
||||||
|
setResult(RESULT_OK)
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(applicationContext, AudioContentModifyActivity::class.java)
|
Intent(applicationContext, AudioContentModifyActivity::class.java)
|
||||||
.apply {
|
.apply {
|
||||||
|
@ -496,14 +498,30 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupPurchaseButton(response: GetAudioContentDetailResponse) {
|
private fun setupPurchaseButton(response: GetAudioContentDetailResponse) {
|
||||||
if (
|
if (response.releaseDate != null) {
|
||||||
|
binding.llPurchase.visibility = View.VISIBLE
|
||||||
|
binding.llPurchasePrice.visibility = View.GONE
|
||||||
|
binding.tvReleaseDate.visibility = View.VISIBLE
|
||||||
|
binding.llPurchase.background = ContextCompat.getDrawable(
|
||||||
|
applicationContext,
|
||||||
|
R.drawable.bg_round_corner_5_3_525252
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.tvReleaseDate.text = response.releaseDate
|
||||||
|
} else if (
|
||||||
response.price > 0 &&
|
response.price > 0 &&
|
||||||
!response.existOrdered &&
|
!response.existOrdered &&
|
||||||
response.orderType == null &&
|
response.orderType == null &&
|
||||||
response.creator.creatorId != SharedPreferenceManager.userId
|
response.creator.creatorId != SharedPreferenceManager.userId
|
||||||
) {
|
) {
|
||||||
|
binding.tvReleaseDate.visibility = View.GONE
|
||||||
binding.llPurchase.visibility = View.VISIBLE
|
binding.llPurchase.visibility = View.VISIBLE
|
||||||
|
binding.llPurchasePrice.visibility = View.VISIBLE
|
||||||
binding.tvPrice.text = response.price.toString()
|
binding.tvPrice.text = response.price.toString()
|
||||||
|
binding.llPurchase.background = ContextCompat.getDrawable(
|
||||||
|
applicationContext,
|
||||||
|
R.drawable.bg_round_corner_5_3_3bb9f1
|
||||||
|
)
|
||||||
|
|
||||||
binding.tvStrPurchaseOrRental.text = if (response.isOnlyRental) {
|
binding.tvStrPurchaseOrRental.text = if (response.isOnlyRental) {
|
||||||
" 대여하기"
|
" 대여하기"
|
||||||
|
@ -529,22 +547,36 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
.apply(RequestOptions().override((screenWidth - 13.3f.dpToPx()).toInt()))
|
.apply(RequestOptions().override((screenWidth - 13.3f.dpToPx()).toInt()))
|
||||||
.into(binding.ivCover)
|
.into(binding.ivCover)
|
||||||
|
|
||||||
binding.ivPlayOrPause.setOnClickListener {
|
if (
|
||||||
startService(
|
response.releaseDate == null ||
|
||||||
Intent(this, AudioContentPlayService::class.java).apply {
|
response.creator.creatorId == SharedPreferenceManager.userId
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL, response.coverImageUrl)
|
) {
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_URL, response.contentUrl)
|
binding.ivPlayOrPause.visibility = View.VISIBLE
|
||||||
putExtra(Constants.EXTRA_NICKNAME, response.creator.nickname)
|
binding.ivPlayOrPause.setOnClickListener {
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_TITLE, response.title)
|
startService(
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, response.contentId)
|
Intent(this, AudioContentPlayService::class.java).apply {
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID, response.creator.creatorId)
|
putExtra(
|
||||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, response.price <= 0)
|
Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL,
|
||||||
putExtra(
|
response.coverImageUrl
|
||||||
Constants.EXTRA_AUDIO_CONTENT_PREVIEW,
|
)
|
||||||
!response.existOrdered && response.price > 0
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_URL, response.contentUrl)
|
||||||
)
|
putExtra(Constants.EXTRA_NICKNAME, response.creator.nickname)
|
||||||
}
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_TITLE, response.title)
|
||||||
)
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, response.contentId)
|
||||||
|
putExtra(
|
||||||
|
Constants.EXTRA_AUDIO_CONTENT_CREATOR_ID,
|
||||||
|
response.creator.creatorId
|
||||||
|
)
|
||||||
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, response.price <= 0)
|
||||||
|
putExtra(
|
||||||
|
Constants.EXTRA_AUDIO_CONTENT_PREVIEW,
|
||||||
|
!response.existOrdered && response.price > 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.ivPlayOrPause.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvTotalDuration.text = " / ${response.duration}"
|
binding.tvTotalDuration.text = " / ${response.duration}"
|
||||||
|
@ -552,6 +584,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun setupInfoArea(response: GetAudioContentDetailResponse) {
|
private fun setupInfoArea(response: GetAudioContentDetailResponse) {
|
||||||
|
binding.tvScheduledToOpen.visibility = if (response.releaseDate != null) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
binding.tvTheme.text = response.themeStr
|
binding.tvTheme.text = response.themeStr
|
||||||
binding.tv19.visibility = if (response.isAdult) {
|
binding.tv19.visibility = if (response.isAdult) {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
|
|
|
@ -14,6 +14,7 @@ data class GetAudioContentDetailResponse(
|
||||||
@SerializedName("tag") val tag: String,
|
@SerializedName("tag") val tag: String,
|
||||||
@SerializedName("price") val price: Int,
|
@SerializedName("price") val price: Int,
|
||||||
@SerializedName("duration") val duration: String,
|
@SerializedName("duration") val duration: String,
|
||||||
|
@SerializedName("releaseDate") val releaseDate: String?,
|
||||||
@SerializedName("isAdult") val isAdult: Boolean,
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
@SerializedName("isMosaic") val isMosaic: Boolean,
|
@SerializedName("isMosaic") val isMosaic: Boolean,
|
||||||
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
||||||
|
|
|
@ -17,17 +17,26 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.zhpan.bannerview.BaseBannerAdapter
|
import com.zhpan.bannerview.BaseBannerAdapter
|
||||||
import com.zhpan.indicator.enums.IndicatorSlideMode
|
import com.zhpan.indicator.enums.IndicatorSlideMode
|
||||||
import com.zhpan.indicator.enums.IndicatorStyle
|
import com.zhpan.indicator.enums.IndicatorStyle
|
||||||
import kr.co.pointclick.sdk.offerwall.core.PointClickAd
|
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllActivity
|
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.all.AudioContentRankingAllActivity
|
import kr.co.vividnext.sodalive.audio_content.all.AudioContentRankingAllActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationActivity
|
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCurationAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCurationViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentThemeAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderListViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity
|
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
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.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
|
@ -40,32 +49,37 @@ import kotlin.math.roundToInt
|
||||||
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
FragmentAudioContentMainBinding::inflate
|
FragmentAudioContentMainBinding::inflate
|
||||||
) {
|
) {
|
||||||
private val viewModel: AudioContentMainViewModel by inject()
|
private val newContentCreatorViewModel: AudioContentMainNewContentCreatorViewModel by inject()
|
||||||
|
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
|
||||||
private lateinit var imm: InputMethodManager
|
|
||||||
|
|
||||||
private lateinit var newContentCreatorAdapter: AudioContentMainNewContentCreatorAdapter
|
private lateinit var newContentCreatorAdapter: AudioContentMainNewContentCreatorAdapter
|
||||||
|
|
||||||
|
private val bannerViewModel: AudioContentMainBannerViewModel by inject()
|
||||||
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
||||||
|
|
||||||
|
private val orderListViewModel: AudioContentMainOrderListViewModel by inject()
|
||||||
private lateinit var orderListAdapter: AudioContentMainContentAdapter
|
private lateinit var orderListAdapter: AudioContentMainContentAdapter
|
||||||
|
|
||||||
|
private val newContentViewModel: AudioContentMainNewContentViewModel by inject()
|
||||||
private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter
|
private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter
|
||||||
private lateinit var newContentAdapter: AudioContentMainContentAdapter
|
private lateinit var newContentAdapter: AudioContentMainContentAdapter
|
||||||
|
|
||||||
|
private val contentRankingViewModel: AudioContentMainRankingViewModel by inject()
|
||||||
private lateinit var contentRankingSortAdapter: AudioContentMainNewContentThemeAdapter
|
private lateinit var contentRankingSortAdapter: AudioContentMainNewContentThemeAdapter
|
||||||
private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter
|
private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter
|
||||||
|
|
||||||
|
private val curationViewModel: AudioContentMainCurationViewModel by inject()
|
||||||
private lateinit var curationAdapter: AudioContentMainCurationAdapter
|
private lateinit var curationAdapter: AudioContentMainCurationAdapter
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
|
||||||
imm = requireContext().getSystemService(
|
|
||||||
Service.INPUT_METHOD_SERVICE
|
|
||||||
) as InputMethodManager
|
|
||||||
|
|
||||||
setupView()
|
setupView()
|
||||||
bindData()
|
|
||||||
|
|
||||||
viewModel.getMain()
|
curationViewModel.getCurationList()
|
||||||
|
bannerViewModel.getMainBannerList()
|
||||||
|
newContentViewModel.getThemeList()
|
||||||
|
newContentViewModel.getNewContentOfTheme("전체")
|
||||||
|
contentRankingViewModel.getContentRanking()
|
||||||
|
contentRankingViewModel.getContentRankingSortType()
|
||||||
|
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
|
@ -94,11 +108,13 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
binding.swipeRefreshLayout.isRefreshing = false
|
||||||
viewModel.getMain()
|
curationViewModel.refresh()
|
||||||
}
|
bannerViewModel.getMainBannerList()
|
||||||
|
newContentViewModel.getThemeList()
|
||||||
binding.ivCanFree.setOnClickListener {
|
newContentViewModel.getNewContentOfTheme("전체")
|
||||||
PointClickAd.showOfferwall(requireActivity(), "무료충전")
|
contentRankingViewModel.getContentRanking()
|
||||||
|
contentRankingViewModel.getContentRankingSortType()
|
||||||
|
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +160,21 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvNewContentCreator.adapter = newContentCreatorAdapter
|
binding.rvNewContentCreator.adapter = newContentCreatorAdapter
|
||||||
|
|
||||||
|
newContentCreatorViewModel.newContentUploadCreatorListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
newContentCreatorAdapter.addItems(it)
|
||||||
|
binding.rvNewContentCreator.visibility = if (
|
||||||
|
newContentCreatorAdapter.itemCount <= 0 && it.isEmpty()
|
||||||
|
) {
|
||||||
|
View.GONE
|
||||||
|
} else {
|
||||||
|
View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newContentCreatorViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBanner() {
|
private fun setupBanner() {
|
||||||
|
@ -208,6 +239,21 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
)
|
)
|
||||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||||
.setIndicatorHeight(4f.dpToPx().toInt())
|
.setIndicatorHeight(4f.dpToPx().toInt())
|
||||||
|
|
||||||
|
bannerViewModel.bannerLiveData.observe(viewLifecycleOwner) {
|
||||||
|
if (bannerAdapter.itemCount <= 0 && it.isEmpty()) {
|
||||||
|
binding.rvBanner.visibility = View.GONE
|
||||||
|
binding.indicatorBanner.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.rvBanner.visibility = View.VISIBLE
|
||||||
|
binding.indicatorBanner.visibility = View.VISIBLE
|
||||||
|
binding.rvBanner.refreshData(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bannerViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupOrderList() {
|
private fun setupOrderList() {
|
||||||
|
@ -266,11 +312,26 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
binding.tvMyStashViewAll.setOnClickListener {
|
binding.tvMyStashViewAll.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), AudioContentOrderListActivity::class.java))
|
startActivity(Intent(requireContext(), AudioContentOrderListActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orderListViewModel.orderListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
orderListAdapter.addItems(it)
|
||||||
|
binding.llMyStash.visibility = if (
|
||||||
|
orderListAdapter.itemCount <= 0 && it.isEmpty()
|
||||||
|
) {
|
||||||
|
View.GONE
|
||||||
|
} else {
|
||||||
|
View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
orderListViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNewContentTheme() {
|
private fun setupNewContentTheme() {
|
||||||
newContentThemeAdapter = AudioContentMainNewContentThemeAdapter {
|
newContentThemeAdapter = AudioContentMainNewContentThemeAdapter {
|
||||||
viewModel.getNewContentOfTheme(theme = it)
|
newContentViewModel.getNewContentOfTheme(theme = it)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.rvNewContentTheme.layoutManager = LinearLayoutManager(
|
binding.rvNewContentTheme.layoutManager = LinearLayoutManager(
|
||||||
|
@ -308,6 +369,11 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvNewContentTheme.adapter = newContentThemeAdapter
|
binding.rvNewContentTheme.adapter = newContentThemeAdapter
|
||||||
|
|
||||||
|
newContentViewModel.themeListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
binding.llNewContent.visibility = View.VISIBLE
|
||||||
|
newContentThemeAdapter.addItems(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNewContent() {
|
private fun setupNewContent() {
|
||||||
|
@ -367,11 +433,27 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvNewContent.adapter = newContentAdapter
|
binding.rvNewContent.adapter = newContentAdapter
|
||||||
|
|
||||||
|
newContentViewModel.newContentListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
newContentAdapter.addItems(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
newContentViewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
|
binding.pbNewContent.visibility = if (it) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newContentViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupContentRankingSortType() {
|
private fun setupContentRankingSortType() {
|
||||||
contentRankingSortAdapter = AudioContentMainNewContentThemeAdapter {
|
contentRankingSortAdapter = AudioContentMainNewContentThemeAdapter {
|
||||||
viewModel.getContentRanking(sort = it)
|
contentRankingViewModel.getContentRanking(sort = it)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.rvContentRankingSort.layoutManager = LinearLayoutManager(
|
binding.rvContentRankingSort.layoutManager = LinearLayoutManager(
|
||||||
|
@ -409,8 +491,14 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvContentRankingSort.adapter = contentRankingSortAdapter
|
binding.rvContentRankingSort.adapter = contentRankingSortAdapter
|
||||||
|
|
||||||
|
contentRankingViewModel.contentRankingSortListLiveData.observe(viewLifecycleOwner) {
|
||||||
|
binding.llContentRanking.visibility = View.VISIBLE
|
||||||
|
contentRankingSortAdapter.addItems(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
private fun setupContentRanking() {
|
private fun setupContentRanking() {
|
||||||
binding.ivContentRankingAll.setOnClickListener {
|
binding.ivContentRankingAll.setOnClickListener {
|
||||||
startActivity(Intent(requireContext(), AudioContentRankingAllActivity::class.java))
|
startActivity(Intent(requireContext(), AudioContentRankingAllActivity::class.java))
|
||||||
|
@ -449,6 +537,16 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvContentRanking.adapter = contentRankingAdapter
|
binding.rvContentRanking.adapter = contentRankingAdapter
|
||||||
|
|
||||||
|
contentRankingViewModel.contentRankingLiveData.observe(viewLifecycleOwner) {
|
||||||
|
binding.llContentRanking.visibility = View.VISIBLE
|
||||||
|
binding.tvDate.text = "${it.startDate}~${it.endDate}"
|
||||||
|
contentRankingAdapter.addItems(it.items)
|
||||||
|
}
|
||||||
|
|
||||||
|
contentRankingViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupCuration() {
|
private fun setupCuration() {
|
||||||
|
@ -511,85 +609,50 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
binding.rvCuration.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
|
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||||
|
.findLastCompletelyVisibleItemPosition()
|
||||||
|
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||||
|
|
||||||
|
// 스크롤이 끝에 도달했는지 확인
|
||||||
|
if (!recyclerView.canScrollVertically(1) &&
|
||||||
|
lastVisibleItemPosition == itemTotalCount
|
||||||
|
) {
|
||||||
|
curationViewModel.getCurationList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
binding.rvCuration.adapter = curationAdapter
|
binding.rvCuration.adapter = curationAdapter
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
curationViewModel.curationListLiveData.observe(viewLifecycleOwner) {
|
||||||
private fun bindData() {
|
if (curationViewModel.page == 2) {
|
||||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
curationAdapter.clear()
|
||||||
if (it) {
|
|
||||||
loadingDialog.show(screenWidth)
|
|
||||||
} else {
|
|
||||||
loadingDialog.dismiss()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
|
||||||
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.newContentUploadCreatorListLiveData.observe(viewLifecycleOwner) {
|
|
||||||
newContentCreatorAdapter.addItems(it)
|
|
||||||
binding.rvNewContentCreator.visibility = if (
|
|
||||||
newContentCreatorAdapter.itemCount <= 0 && it.isEmpty()
|
|
||||||
) {
|
|
||||||
View.GONE
|
|
||||||
} else {
|
|
||||||
View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.bannerLiveData.observe(viewLifecycleOwner) {
|
|
||||||
if (bannerAdapter.itemCount <= 0 && it.isEmpty()) {
|
|
||||||
binding.rvBanner.visibility = View.GONE
|
|
||||||
binding.indicatorBanner.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.rvBanner.visibility = View.VISIBLE
|
|
||||||
binding.indicatorBanner.visibility = View.VISIBLE
|
|
||||||
binding.rvBanner.refreshData(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.orderListLiveData.observe(viewLifecycleOwner) {
|
|
||||||
orderListAdapter.addItems(it)
|
|
||||||
binding.llMyStash.visibility = if (
|
|
||||||
orderListAdapter.itemCount <= 0 && it.isEmpty()
|
|
||||||
) {
|
|
||||||
View.GONE
|
|
||||||
} else {
|
|
||||||
View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.newContentListLiveData.observe(viewLifecycleOwner) {
|
|
||||||
newContentAdapter.addItems(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.themeListLiveData.observe(viewLifecycleOwner) {
|
|
||||||
binding.llNewContent.visibility = View.VISIBLE
|
|
||||||
newContentThemeAdapter.addItems(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.curationListLiveData.observe(viewLifecycleOwner) {
|
|
||||||
curationAdapter.addItems(it)
|
curationAdapter.addItems(it)
|
||||||
binding.rvCuration.visibility = if (
|
|
||||||
curationAdapter.itemCount <= 0 && it.isEmpty()
|
binding.rvCuration.visibility = if (curationAdapter.itemCount <= 0 && it.isEmpty()) {
|
||||||
) {
|
|
||||||
View.GONE
|
View.GONE
|
||||||
} else {
|
} else {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.contentRankingSortListLiveData.observe(viewLifecycleOwner) {
|
curationViewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
binding.llContentRanking.visibility = View.VISIBLE
|
binding.pbCuration.visibility = if (it) {
|
||||||
contentRankingSortAdapter.addItems(it)
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.contentRankingLiveData.observe(viewLifecycleOwner) {
|
curationViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
binding.llContentRanking.visibility = View.VISIBLE
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
binding.tvDate.text = "${it.startDate}~${it.endDate}"
|
|
||||||
contentRankingAdapter.addItems(it.items)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import com.orhanobut.logger.Logger
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
|
||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
|
||||||
|
|
||||||
class AudioContentMainViewModel(
|
|
||||||
private val repository: AudioContentRepository
|
|
||||||
) : BaseViewModel() {
|
|
||||||
private val _toastLiveData = MutableLiveData<String?>()
|
|
||||||
val toastLiveData: LiveData<String?>
|
|
||||||
get() = _toastLiveData
|
|
||||||
|
|
||||||
private var _isLoading = MutableLiveData(false)
|
|
||||||
val isLoading: LiveData<Boolean>
|
|
||||||
get() = _isLoading
|
|
||||||
|
|
||||||
private var _newContentUploadCreatorListLiveData =
|
|
||||||
MutableLiveData<List<GetNewContentUploadCreator>>()
|
|
||||||
val newContentUploadCreatorListLiveData: LiveData<List<GetNewContentUploadCreator>>
|
|
||||||
get() = _newContentUploadCreatorListLiveData
|
|
||||||
|
|
||||||
private var _newContentListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
|
|
||||||
val newContentListLiveData: LiveData<List<GetAudioContentMainItem>>
|
|
||||||
get() = _newContentListLiveData
|
|
||||||
|
|
||||||
private var _bannerLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
|
|
||||||
val bannerLiveData: LiveData<List<GetAudioContentBannerResponse>>
|
|
||||||
get() = _bannerLiveData
|
|
||||||
|
|
||||||
private var _orderListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
|
|
||||||
val orderListLiveData: LiveData<List<GetAudioContentMainItem>>
|
|
||||||
get() = _orderListLiveData
|
|
||||||
|
|
||||||
private var _themeListLiveData = MutableLiveData<List<String>>()
|
|
||||||
val themeListLiveData: LiveData<List<String>>
|
|
||||||
get() = _themeListLiveData
|
|
||||||
|
|
||||||
private var _curationListLiveData = MutableLiveData<List<GetAudioContentCurationResponse>>()
|
|
||||||
val curationListLiveData: LiveData<List<GetAudioContentCurationResponse>>
|
|
||||||
get() = _curationListLiveData
|
|
||||||
|
|
||||||
private var _contentRankingSortListLiveData = MutableLiveData<List<String>>()
|
|
||||||
val contentRankingSortListLiveData: LiveData<List<String>>
|
|
||||||
get() = _contentRankingSortListLiveData
|
|
||||||
|
|
||||||
private var _contentRankingLiveData = MutableLiveData<GetAudioContentRanking>()
|
|
||||||
val contentRankingLiveData: LiveData<GetAudioContentRanking>
|
|
||||||
get() = _contentRankingLiveData
|
|
||||||
|
|
||||||
fun getMain() {
|
|
||||||
_isLoading.value = true
|
|
||||||
compositeDisposable.add(
|
|
||||||
repository.getMain(token = "Bearer ${SharedPreferenceManager.token}")
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
{
|
|
||||||
if (it.success && it.data != null) {
|
|
||||||
val data = it.data
|
|
||||||
_newContentUploadCreatorListLiveData.value =
|
|
||||||
data.newContentUploadCreatorList
|
|
||||||
_newContentListLiveData.value = data.newContentList
|
|
||||||
_orderListLiveData.value = data.orderList
|
|
||||||
_bannerLiveData.value = data.bannerList
|
|
||||||
_curationListLiveData.value = data.curationList
|
|
||||||
_contentRankingLiveData.value = data.contentRanking
|
|
||||||
_contentRankingSortListLiveData.value = data.contentRankingSortTypeList
|
|
||||||
|
|
||||||
val themeList = listOf("전체").union(data.themeList).toList()
|
|
||||||
_themeListLiveData.value = themeList
|
|
||||||
} else {
|
|
||||||
if (it.message != null) {
|
|
||||||
_toastLiveData.postValue(it.message)
|
|
||||||
} else {
|
|
||||||
_toastLiveData.postValue(
|
|
||||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_isLoading.value = false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_isLoading.value = false
|
|
||||||
it.message?.let { message -> Logger.e(message) }
|
|
||||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getNewContentOfTheme(theme: String) {
|
|
||||||
compositeDisposable.add(
|
|
||||||
repository.getNewContentOfTheme(
|
|
||||||
theme = if (theme == "전체") {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
theme
|
|
||||||
},
|
|
||||||
token = "Bearer ${SharedPreferenceManager.token}"
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
{
|
|
||||||
if (it.success && it.data != null) {
|
|
||||||
_newContentListLiveData.value = it.data!!
|
|
||||||
} else {
|
|
||||||
if (it.message != null) {
|
|
||||||
_toastLiveData.postValue(it.message)
|
|
||||||
} else {
|
|
||||||
_toastLiveData.postValue(
|
|
||||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
it.message?.let { message -> Logger.e(message) }
|
|
||||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getContentRanking(sort: String) {
|
|
||||||
_isLoading.value = true
|
|
||||||
compositeDisposable.add(
|
|
||||||
repository.getContentRanking(
|
|
||||||
page = 1,
|
|
||||||
size = 12,
|
|
||||||
sortType = sort,
|
|
||||||
token = "Bearer ${SharedPreferenceManager.token}"
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
{
|
|
||||||
if (it.success && it.data != null) {
|
|
||||||
_isLoading.value = false
|
|
||||||
_contentRankingLiveData.value = it.data!!
|
|
||||||
} else {
|
|
||||||
_isLoading.value = false
|
|
||||||
if (it.message != null) {
|
|
||||||
_toastLiveData.postValue(it.message)
|
|
||||||
} else {
|
|
||||||
_toastLiveData.postValue(
|
|
||||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
it.message?.let { message -> Logger.e(message) }
|
|
||||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,18 +3,6 @@ package kr.co.vividnext.sodalive.audio_content.main
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import kr.co.vividnext.sodalive.settings.event.EventItem
|
import kr.co.vividnext.sodalive.settings.event.EventItem
|
||||||
|
|
||||||
data class GetAudioContentMainResponse(
|
|
||||||
@SerializedName("newContentUploadCreatorList")
|
|
||||||
val newContentUploadCreatorList: List<GetNewContentUploadCreator>,
|
|
||||||
@SerializedName("bannerList") val bannerList: List<GetAudioContentBannerResponse>,
|
|
||||||
@SerializedName("orderList") val orderList: List<GetAudioContentMainItem>,
|
|
||||||
@SerializedName("themeList") val themeList: List<String>,
|
|
||||||
@SerializedName("newContentList") val newContentList: List<GetAudioContentMainItem>,
|
|
||||||
@SerializedName("curationList") val curationList: List<GetAudioContentCurationResponse>,
|
|
||||||
@SerializedName("contentRankingSortTypeList") val contentRankingSortTypeList: List<String>,
|
|
||||||
@SerializedName("contentRanking") val contentRanking: GetAudioContentRanking
|
|
||||||
)
|
|
||||||
|
|
||||||
data class GetNewContentUploadCreator(
|
data class GetNewContentUploadCreator(
|
||||||
@SerializedName("creatorId") val creatorId: Long,
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
@SerializedName("creatorNickname") val creatorNickname: String,
|
@SerializedName("creatorNickname") val creatorNickname: String,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main.banner
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
@ -11,6 +11,7 @@ import com.bumptech.glide.request.transition.Transition
|
||||||
import com.zhpan.bannerview.BaseBannerAdapter
|
import com.zhpan.bannerview.BaseBannerAdapter
|
||||||
import com.zhpan.bannerview.BaseViewHolder
|
import com.zhpan.bannerview.BaseViewHolder
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||||
|
|
||||||
class AudioContentMainBannerAdapter(
|
class AudioContentMainBannerAdapter(
|
||||||
private val context: Context,
|
private val context: Context,
|
|
@ -0,0 +1,54 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.banner
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainBannerViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _bannerLiveData = MutableLiveData<List<GetAudioContentBannerResponse>>()
|
||||||
|
val bannerLiveData: LiveData<List<GetAudioContentBannerResponse>>
|
||||||
|
get() = _bannerLiveData
|
||||||
|
|
||||||
|
fun getMainBannerList() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getMainBannerList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_bannerLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"배너를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"배너를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main.curation
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -8,6 +8,9 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainContentAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentCurationResponse
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainCurationBinding
|
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainCurationBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
@ -89,8 +92,11 @@ class AudioContentMainCurationAdapter(
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
fun addItems(items: List<GetAudioContentCurationResponse>) {
|
fun addItems(items: List<GetAudioContentCurationResponse>) {
|
||||||
this.items.clear()
|
|
||||||
this.items.addAll(items)
|
this.items.addAll(items)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
this.items.clear()
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.curation
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentCurationResponse
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainCurationViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private var _curationListLiveData = MutableLiveData<List<GetAudioContentCurationResponse>>()
|
||||||
|
val curationListLiveData: LiveData<List<GetAudioContentCurationResponse>>
|
||||||
|
get() = _curationListLiveData
|
||||||
|
|
||||||
|
var page = 1
|
||||||
|
var isLast = false
|
||||||
|
private val pageSize = 10
|
||||||
|
|
||||||
|
fun getCurationList() {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getCurationList(
|
||||||
|
page = page,
|
||||||
|
size = pageSize,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
page += 1
|
||||||
|
|
||||||
|
if (it.data.isNotEmpty()) {
|
||||||
|
_curationListLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
_curationListLiveData.postValue(listOf())
|
||||||
|
isLast = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"큐레이션을 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"큐레이션을 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refresh() {
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
getCurationList()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main.new_content
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -28,9 +28,9 @@ class AudioContentMainNewContentThemeAdapter(
|
||||||
(selectedTheme == "" && theme == "매출")
|
(selectedTheme == "" && theme == "매출")
|
||||||
) {
|
) {
|
||||||
binding.tvTheme.setBackgroundResource(
|
binding.tvTheme.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvTheme.setTextColor(ContextCompat.getColor(context, R.color.color_9970ff))
|
binding.tvTheme.setTextColor(ContextCompat.getColor(context, R.color.color_3bb9f1))
|
||||||
} else {
|
} else {
|
||||||
binding.tvTheme.setBackgroundResource(
|
binding.tvTheme.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_777777
|
R.drawable.bg_round_corner_16_7_transparent_777777
|
|
@ -0,0 +1,96 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.new_content
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainNewContentViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private var _newContentListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
|
||||||
|
val newContentListLiveData: LiveData<List<GetAudioContentMainItem>>
|
||||||
|
get() = _newContentListLiveData
|
||||||
|
|
||||||
|
private var _themeListLiveData = MutableLiveData<List<String>>()
|
||||||
|
val themeListLiveData: LiveData<List<String>>
|
||||||
|
get() = _themeListLiveData
|
||||||
|
|
||||||
|
fun getThemeList() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getNewContentThemeList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
val themeList = listOf("전체").union(it.data).toList()
|
||||||
|
_themeListLiveData.postValue(themeList)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getNewContentOfTheme(theme: String) {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getNewContentOfTheme(
|
||||||
|
theme = if (theme == "전체") {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
theme
|
||||||
|
},
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_newContentListLiveData.value = it.data!!
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
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.audio_content.main.GetNewContentUploadCreator
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainNewContentCreatorBinding
|
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainNewContentCreatorBinding
|
||||||
|
|
||||||
class AudioContentMainNewContentCreatorAdapter(
|
class AudioContentMainNewContentCreatorAdapter(
|
|
@ -0,0 +1,57 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetNewContentUploadCreator
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainNewContentCreatorViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _newContentUploadCreatorListLiveData =
|
||||||
|
MutableLiveData<List<GetNewContentUploadCreator>>()
|
||||||
|
val newContentUploadCreatorListLiveData: LiveData<List<GetNewContentUploadCreator>>
|
||||||
|
get() = _newContentUploadCreatorListLiveData
|
||||||
|
|
||||||
|
fun getNewContentUploadCreatorList() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getNewContentUploadCreatorList(
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_newContentUploadCreatorListLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.order
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainOrderListViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _orderListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
|
||||||
|
val orderListLiveData: LiveData<List<GetAudioContentMainItem>>
|
||||||
|
get() = _orderListLiveData
|
||||||
|
|
||||||
|
fun getOrderList() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getMainOrderList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_orderListLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"주문정보를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"주문정보를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main.ranking
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainRankingBinding
|
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainRankingBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.main.ranking
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRanking
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class AudioContentMainRankingViewModel(
|
||||||
|
private val repository: AudioContentRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _contentRankingSortListLiveData = MutableLiveData<List<String>>()
|
||||||
|
val contentRankingSortListLiveData: LiveData<List<String>>
|
||||||
|
get() = _contentRankingSortListLiveData
|
||||||
|
|
||||||
|
private var _contentRankingLiveData = MutableLiveData<GetAudioContentRanking>()
|
||||||
|
val contentRankingLiveData: LiveData<GetAudioContentRanking>
|
||||||
|
get() = _contentRankingLiveData
|
||||||
|
|
||||||
|
fun getContentRankingSortType() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getContentRankingSortType(token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_contentRankingSortListLiveData.value = it.data!!
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getContentRanking(sort: String = "매출") {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getContentRanking(
|
||||||
|
page = 1,
|
||||||
|
size = 12,
|
||||||
|
sortType = sort,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_contentRankingLiveData.value = it.data!!
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,8 @@ package kr.co.vividnext.sodalive.audio_content.upload
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.DatePickerDialog
|
||||||
|
import android.app.TimePickerDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
@ -28,9 +30,15 @@ import kr.co.vividnext.sodalive.common.RealPathUtil
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentUploadBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentUploadBinding
|
||||||
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
||||||
|
import kr.co.vividnext.sodalive.dialog.SodaLiveTimePickerDialog
|
||||||
|
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBinding>(
|
class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBinding>(
|
||||||
ActivityAudioContentUploadBinding::inflate
|
ActivityAudioContentUploadBinding::inflate
|
||||||
|
@ -111,6 +119,26 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val datePickerDialogListener =
|
||||||
|
DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
|
||||||
|
viewModel.releaseDate = String.format("%d-%02d-%02d", year, monthOfYear + 1, dayOfMonth)
|
||||||
|
viewModel.setReservationDate(
|
||||||
|
String.format(
|
||||||
|
"%d.%02d.%02d",
|
||||||
|
year,
|
||||||
|
monthOfYear + 1,
|
||||||
|
dayOfMonth
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val timePickerDialogListener =
|
||||||
|
TimePickerDialog.OnTimeSetListener { _, hourOfDay, minute ->
|
||||||
|
val timeString = String.format("%02d:%02d", hourOfDay, minute)
|
||||||
|
viewModel.releaseTime = timeString
|
||||||
|
viewModel.setReservationTime(timeString.convertDateFormat("HH:mm", "a hh:mm"))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
checkPermissions()
|
checkPermissions()
|
||||||
|
@ -173,6 +201,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
binding.llOnlyRental.setOnClickListener { viewModel.setIsOnlyRental(true) }
|
binding.llOnlyRental.setOnClickListener { viewModel.setIsOnlyRental(true) }
|
||||||
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
|
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
|
||||||
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
|
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
|
||||||
|
binding.llActiveNow.setOnClickListener { viewModel.setActiveReservation(false) }
|
||||||
|
binding.llActiveReservation.setOnClickListener { viewModel.setActiveReservation(true) }
|
||||||
|
|
||||||
binding.tvCancel.setOnClickListener { finish() }
|
binding.tvCancel.setOnClickListener { finish() }
|
||||||
binding.tvUpload.setOnClickListener {
|
binding.tvUpload.setOnClickListener {
|
||||||
|
@ -189,6 +219,71 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
).show(screenWidth)
|
).show(screenWidth)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.tvReservationDate.setOnClickListener {
|
||||||
|
val reservationDate = viewModel.releaseDate.split("-")
|
||||||
|
val datePicker: DatePickerDialog
|
||||||
|
|
||||||
|
if (reservationDate.isNotEmpty() && reservationDate.size == 3) {
|
||||||
|
datePicker = DatePickerDialog(
|
||||||
|
this,
|
||||||
|
R.style.DatePickerStyle,
|
||||||
|
datePickerDialogListener,
|
||||||
|
reservationDate[0].toInt(),
|
||||||
|
reservationDate[1].toInt() - 1,
|
||||||
|
reservationDate[2].toInt()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val dateString = SimpleDateFormat(
|
||||||
|
"yyyy.MM.dd",
|
||||||
|
Locale.getDefault()
|
||||||
|
).format(Date()).split(".")
|
||||||
|
|
||||||
|
datePicker = DatePickerDialog(
|
||||||
|
this,
|
||||||
|
R.style.DatePickerStyle,
|
||||||
|
datePickerDialogListener,
|
||||||
|
dateString[0].toInt(),
|
||||||
|
dateString[1].toInt() - 1,
|
||||||
|
dateString[2].toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
datePicker.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvReservationTime.setOnClickListener {
|
||||||
|
val reservationTime = viewModel.releaseTime.split(":")
|
||||||
|
val timePicker: TimePickerDialog
|
||||||
|
|
||||||
|
if (reservationTime.isNotEmpty() && reservationTime.size == 2) {
|
||||||
|
timePicker = SodaLiveTimePickerDialog(
|
||||||
|
this,
|
||||||
|
R.style.TimePickerStyle,
|
||||||
|
timePickerDialogListener,
|
||||||
|
reservationTime[0].toInt(),
|
||||||
|
reservationTime[1].toInt(),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val calendar = Calendar.getInstance().apply {
|
||||||
|
add(Calendar.HOUR_OF_DAY, 1)
|
||||||
|
}
|
||||||
|
val initialHour = calendar.get(Calendar.HOUR_OF_DAY)
|
||||||
|
val initialMinute = calendar.get(Calendar.MINUTE) / 15 * 15
|
||||||
|
|
||||||
|
timePicker = SodaLiveTimePickerDialog(
|
||||||
|
this,
|
||||||
|
R.style.TimePickerStyle,
|
||||||
|
timePickerDialogListener,
|
||||||
|
initialHour,
|
||||||
|
initialMinute,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
timePicker.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPermissions() {
|
private fun checkPermissions() {
|
||||||
|
@ -323,17 +418,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivCommentNo.visibility = View.GONE
|
binding.ivCommentNo.visibility = View.GONE
|
||||||
binding.tvCommentNo.setTextColor(
|
binding.tvCommentNo.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentNo.setBackgroundResource(
|
binding.llCommentNo.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.ivCommentNo.visibility = View.VISIBLE
|
binding.ivCommentNo.visibility = View.VISIBLE
|
||||||
|
@ -343,17 +438,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivCommentYes.visibility = View.GONE
|
binding.ivCommentYes.visibility = View.GONE
|
||||||
binding.tvCommentYes.setTextColor(
|
binding.tvCommentYes.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentYes
|
binding.llCommentYes
|
||||||
.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734_9970ff)
|
.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,16 +464,16 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
viewModel.isAdultLiveData.observe(this) {
|
viewModel.isAdultLiveData.observe(this) {
|
||||||
if (it) {
|
if (it) {
|
||||||
binding.ivAgeAll.visibility = View.GONE
|
binding.ivAgeAll.visibility = View.GONE
|
||||||
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAge19.visibility = View.VISIBLE
|
binding.ivAge19.visibility = View.VISIBLE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -387,16 +482,16 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.ivAge19.visibility = View.GONE
|
binding.ivAge19.visibility = View.GONE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAgeAll.visibility = View.VISIBLE
|
binding.ivAgeAll.visibility = View.VISIBLE
|
||||||
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -406,6 +501,69 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.isActiveReservationLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
checkActiveReservation()
|
||||||
|
} else {
|
||||||
|
checkActiveNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.reservationDateLiveData.observe(this) {
|
||||||
|
binding.tvReservationDate.text = it
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.reservationTimeLiveData.observe(this) {
|
||||||
|
binding.tvReservationTime.text = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkActiveNow() {
|
||||||
|
binding.llReservationDatetime.visibility = View.GONE
|
||||||
|
|
||||||
|
binding.ivActiveNow.visibility = View.VISIBLE
|
||||||
|
binding.tvActiveNow.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_eeeeee
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llActiveNow.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivActiveReservation.visibility = View.GONE
|
||||||
|
binding.tvActiveReservation.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llActiveReservation.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkActiveReservation() {
|
||||||
|
binding.llReservationDatetime.visibility = View.VISIBLE
|
||||||
|
binding.ivActiveReservation.visibility = View.VISIBLE
|
||||||
|
binding.tvActiveReservation.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_eeeeee
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llActiveReservation.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivActiveNow.visibility = View.GONE
|
||||||
|
binding.tvActiveNow.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llActiveNow.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPriceFree() {
|
private fun checkPriceFree() {
|
||||||
|
@ -422,17 +580,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llPriceFree.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llPriceFree.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivPricePaid.visibility = View.GONE
|
binding.ivPricePaid.visibility = View.GONE
|
||||||
binding.tvPricePaid.setTextColor(
|
binding.tvPricePaid.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llPricePaid.setBackgroundResource(
|
binding.llPricePaid.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.llConfigPreviewTime.visibility = View.GONE
|
binding.llConfigPreviewTime.visibility = View.GONE
|
||||||
|
@ -450,17 +608,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llPricePaid.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llPricePaid.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivPriceFree.visibility = View.GONE
|
binding.ivPriceFree.visibility = View.GONE
|
||||||
binding.tvPriceFree.setTextColor(
|
binding.tvPriceFree.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llPriceFree.setBackgroundResource(
|
binding.llPriceFree.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
binding.llConfigPreviewTime.visibility = View.VISIBLE
|
binding.llConfigPreviewTime.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
@ -474,17 +632,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llRentalAndKeep.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llRentalAndKeep.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivOnlyRental.visibility = View.GONE
|
binding.ivOnlyRental.visibility = View.GONE
|
||||||
binding.tvOnlyRental.setTextColor(
|
binding.tvOnlyRental.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llOnlyRental.setBackgroundResource(
|
binding.llOnlyRental.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,17 +655,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llOnlyRental.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llOnlyRental.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivRentalAndKeep.visibility = View.GONE
|
binding.ivRentalAndKeep.visibility = View.GONE
|
||||||
binding.tvRentalAndKeep.setTextColor(
|
binding.tvRentalAndKeep.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llRentalAndKeep.setBackgroundResource(
|
binding.llRentalAndKeep.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import okio.BufferedSink
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
class AudioContentUploadViewModel(
|
class AudioContentUploadViewModel(
|
||||||
private val repository: AudioContentRepository
|
private val repository: AudioContentRepository
|
||||||
|
@ -49,12 +50,26 @@ class AudioContentUploadViewModel(
|
||||||
val isPriceFreeLiveData: LiveData<Boolean>
|
val isPriceFreeLiveData: LiveData<Boolean>
|
||||||
get() = _isPriceFreeLiveData
|
get() = _isPriceFreeLiveData
|
||||||
|
|
||||||
|
private val _isActiveReservationLiveData = MutableLiveData(false)
|
||||||
|
val isActiveReservationLiveData: LiveData<Boolean>
|
||||||
|
get() = _isActiveReservationLiveData
|
||||||
|
|
||||||
|
private val _reservationDateLiveData = MutableLiveData("날짜를 선택해주세요")
|
||||||
|
val reservationDateLiveData: LiveData<String>
|
||||||
|
get() = _reservationDateLiveData
|
||||||
|
|
||||||
|
private val _reservationTimeLiveData = MutableLiveData("시간을 설정해주세요")
|
||||||
|
val reservationTimeLiveData: LiveData<String>
|
||||||
|
get() = _reservationTimeLiveData
|
||||||
|
|
||||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||||
|
|
||||||
var title = ""
|
var title = ""
|
||||||
var detail = ""
|
var detail = ""
|
||||||
var tags = ""
|
var tags = ""
|
||||||
var price = 0
|
var price = 0
|
||||||
|
var releaseDate = ""
|
||||||
|
var releaseTime = ""
|
||||||
var theme: GetAudioContentThemeResponse? = null
|
var theme: GetAudioContentThemeResponse? = null
|
||||||
var coverImageUri: Uri? = null
|
var coverImageUri: Uri? = null
|
||||||
var contentUri: Uri? = null
|
var contentUri: Uri? = null
|
||||||
|
@ -81,6 +96,10 @@ class AudioContentUploadViewModel(
|
||||||
_isOnlyRentalLiveData.postValue(isOnlyRental)
|
_isOnlyRentalLiveData.postValue(isOnlyRental)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setActiveReservation(isActiveReservation: Boolean) {
|
||||||
|
_isActiveReservationLiveData.postValue(isActiveReservation)
|
||||||
|
}
|
||||||
|
|
||||||
fun uploadAudioContent(onSuccess: () -> Unit) {
|
fun uploadAudioContent(onSuccess: () -> Unit) {
|
||||||
if (!_isLoading.value!! && validateData()) {
|
if (!_isLoading.value!! && validateData()) {
|
||||||
_isLoading.postValue(true)
|
_isLoading.postValue(true)
|
||||||
|
@ -90,6 +109,12 @@ class AudioContentUploadViewModel(
|
||||||
detail = detail,
|
detail = detail,
|
||||||
tags = tags,
|
tags = tags,
|
||||||
price = price,
|
price = price,
|
||||||
|
releaseDate = if (_isActiveReservationLiveData.value!!) {
|
||||||
|
"$releaseDate $releaseTime"
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
themeId = theme!!.id,
|
themeId = theme!!.id,
|
||||||
isAdult = _isAdultLiveData.value!!,
|
isAdult = _isAdultLiveData.value!!,
|
||||||
isOnlyRental = _isOnlyRentalLiveData.value!!,
|
isOnlyRental = _isOnlyRentalLiveData.value!!,
|
||||||
|
@ -281,6 +306,14 @@ class AudioContentUploadViewModel(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
_isActiveReservationLiveData.value!! &&
|
||||||
|
(releaseDate.isBlank() || releaseTime.isBlank())
|
||||||
|
) {
|
||||||
|
_toastLiveData.postValue("예약날짜와 시간을 선택해주세요.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,4 +340,12 @@ class AudioContentUploadViewModel(
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setReservationDate(dateString: String) {
|
||||||
|
_reservationDateLiveData.postValue(dateString)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setReservationTime(timeString: String) {
|
||||||
|
_reservationTimeLiveData.postValue(timeString)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@ data class CreateAudioContentRequest(
|
||||||
@SerializedName("detail") val detail: String,
|
@SerializedName("detail") val detail: String,
|
||||||
@SerializedName("tags") val tags: String,
|
@SerializedName("tags") val tags: String,
|
||||||
@SerializedName("price") val price: Int,
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("releaseDate") val releaseDate: String?,
|
||||||
|
@SerializedName("timezone") val timezone: String,
|
||||||
@SerializedName("themeId") val themeId: Long,
|
@SerializedName("themeId") val themeId: Long,
|
||||||
@SerializedName("isAdult") val isAdult: Boolean,
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
||||||
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
||||||
@SerializedName("previewStartTime") val previewStartTime: String? = null,
|
@SerializedName("previewStartTime") val previewStartTime: String? = null,
|
||||||
@SerializedName("previewEndTime") val previewEndTime: String? = null
|
@SerializedName("previewEndTime") val previewEndTime: String? = null,
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,6 +29,7 @@ object Constants {
|
||||||
const val EXTRA_MESSAGE_BOX = "extra_message_box"
|
const val EXTRA_MESSAGE_BOX = "extra_message_box"
|
||||||
const val EXTRA_TEXT_MESSAGE = "extra_text_message"
|
const val EXTRA_TEXT_MESSAGE = "extra_text_message"
|
||||||
const val EXTRA_LIVE_TIME_NOW = "extra_live_time_now"
|
const val EXTRA_LIVE_TIME_NOW = "extra_live_time_now"
|
||||||
|
const val EXTRA_RESULT_ROULETTE = "extra_result_roulette"
|
||||||
const val EXTRA_GO_TO_PREV_PAGE = "extra_go_to_prev_page"
|
const val EXTRA_GO_TO_PREV_PAGE = "extra_go_to_prev_page"
|
||||||
const val EXTRA_SELECT_RECIPIENT = "extra_select_recipient"
|
const val EXTRA_SELECT_RECIPIENT = "extra_select_recipient"
|
||||||
const val EXTRA_ROOM_CHANNEL_NAME = "extra_room_channel_name"
|
const val EXTRA_ROOM_CHANNEL_NAME = "extra_room_channel_name"
|
||||||
|
@ -56,4 +57,8 @@ object Constants {
|
||||||
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
|
const val LIVE_SERVICE_NOTIFICATION_ID: Int = 2
|
||||||
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"
|
const val ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_content_receiver"
|
||||||
const val ACTION_MAIN_AUDIO_CONTENT_RECEIVER = "soda_live_action_main_content_receiver"
|
const val ACTION_MAIN_AUDIO_CONTENT_RECEIVER = "soda_live_action_main_content_receiver"
|
||||||
|
|
||||||
|
const val EXTRA_COMMUNITY_POST_ID = "community_post_id"
|
||||||
|
const val EXTRA_COMMUNITY_CREATOR_ID = "community_creator_id"
|
||||||
|
const val EXTRA_COMMUNITY_POST_COMMENT = "community_post_comment_id"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import coil.ImageLoader
|
||||||
|
import okhttp3.Cache
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object ImageLoaderProvider {
|
||||||
|
lateinit var imageLoader: ImageLoader
|
||||||
|
private set
|
||||||
|
|
||||||
|
val isInitialized: Boolean
|
||||||
|
get() = ::imageLoader.isInitialized
|
||||||
|
fun init(context: Context) {
|
||||||
|
val cacheSize = 250L * 1024L * 1024L // 250 MB
|
||||||
|
val cacheDirectory = File(
|
||||||
|
context.cacheDir,
|
||||||
|
"image_cache"
|
||||||
|
).apply { mkdirs() }
|
||||||
|
|
||||||
|
val cache = Cache(cacheDirectory, cacheSize)
|
||||||
|
|
||||||
|
imageLoader = ImageLoader.Builder(context)
|
||||||
|
.okHttpClient {
|
||||||
|
OkHttpClient().newBuilder()
|
||||||
|
.cache(cache)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,12 @@ import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentReplyVi
|
||||||
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository
|
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository
|
||||||
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationViewModel
|
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainViewModel
|
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCurationViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderListViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
|
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
|
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
|
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
|
||||||
|
@ -25,6 +30,12 @@ import kr.co.vividnext.sodalive.explorer.ExplorerApi
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
|
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityApi
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllViewModel
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentListViewModel
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.CreatorCommunityModifyViewModel
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewModel
|
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewModel
|
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
|
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
|
||||||
|
@ -43,6 +54,9 @@ import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewMo
|
||||||
import kr.co.vividnext.sodalive.live.room.tag.LiveTagRepository
|
import kr.co.vividnext.sodalive.live.room.tag.LiveTagRepository
|
||||||
import kr.co.vividnext.sodalive.live.room.tag.LiveTagViewModel
|
import kr.co.vividnext.sodalive.live.room.tag.LiveTagViewModel
|
||||||
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditViewModel
|
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditViewModel
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteApi
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteSettingsViewModel
|
||||||
import kr.co.vividnext.sodalive.main.MainViewModel
|
import kr.co.vividnext.sodalive.main.MainViewModel
|
||||||
import kr.co.vividnext.sodalive.message.MessageApi
|
import kr.co.vividnext.sodalive.message.MessageApi
|
||||||
import kr.co.vividnext.sodalive.message.MessageRepository
|
import kr.co.vividnext.sodalive.message.MessageRepository
|
||||||
|
@ -58,6 +72,7 @@ import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
|
||||||
import kr.co.vividnext.sodalive.mypage.can.CanApi
|
import kr.co.vividnext.sodalive.mypage.can.CanApi
|
||||||
import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeViewModel
|
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeViewModel
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
||||||
|
@ -145,6 +160,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
single { ApiBuilder().build(get(), AudioContentApi::class.java) }
|
single { ApiBuilder().build(get(), AudioContentApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), FaqApi::class.java) }
|
single { ApiBuilder().build(get(), FaqApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), MemberTagApi::class.java) }
|
single { ApiBuilder().build(get(), MemberTagApi::class.java) }
|
||||||
|
single { ApiBuilder().build(get(), RouletteApi::class.java) }
|
||||||
|
single { ApiBuilder().build(get(), CreatorCommunityApi::class.java) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val viewModelModule = module {
|
private val viewModelModule = module {
|
||||||
|
@ -153,7 +170,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { TermsViewModel(get()) }
|
viewModel { TermsViewModel(get()) }
|
||||||
viewModel { FindPasswordViewModel(get()) }
|
viewModel { FindPasswordViewModel(get()) }
|
||||||
viewModel { MainViewModel(get(), get(), get(), get()) }
|
viewModel { MainViewModel(get(), get(), get(), get()) }
|
||||||
viewModel { LiveViewModel(get(), get(), get()) }
|
viewModel { LiveViewModel(get(), get(), get(), get()) }
|
||||||
viewModel { MyPageViewModel(get(), get()) }
|
viewModel { MyPageViewModel(get(), get()) }
|
||||||
viewModel { CanStatusViewModel(get()) }
|
viewModel { CanStatusViewModel(get()) }
|
||||||
viewModel { CanChargeViewModel(get()) }
|
viewModel { CanChargeViewModel(get()) }
|
||||||
|
@ -162,7 +179,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { LiveRoomCreateViewModel(get()) }
|
viewModel { LiveRoomCreateViewModel(get()) }
|
||||||
viewModel { LiveTagViewModel(get()) }
|
viewModel { LiveTagViewModel(get()) }
|
||||||
viewModel { LiveRoomEditViewModel(get()) }
|
viewModel { LiveRoomEditViewModel(get()) }
|
||||||
viewModel { LiveRoomViewModel(get(), get(), get()) }
|
viewModel { LiveRoomViewModel(get(), get(), get(), get()) }
|
||||||
viewModel { LiveRoomDonationMessageViewModel(get()) }
|
viewModel { LiveRoomDonationMessageViewModel(get()) }
|
||||||
viewModel { ExplorerViewModel(get()) }
|
viewModel { ExplorerViewModel(get()) }
|
||||||
viewModel { UserProfileViewModel(get(), get(), get()) }
|
viewModel { UserProfileViewModel(get(), get(), get()) }
|
||||||
|
@ -179,7 +196,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { SettingsViewModel(get()) }
|
viewModel { SettingsViewModel(get()) }
|
||||||
viewModel { TextMessageDetailViewModel(get()) }
|
viewModel { TextMessageDetailViewModel(get()) }
|
||||||
viewModel { LiveReservationStatusViewModel(get()) }
|
viewModel { LiveReservationStatusViewModel(get()) }
|
||||||
viewModel { AudioContentMainViewModel(get()) }
|
viewModel { AudioContentMainBannerViewModel(get()) }
|
||||||
|
viewModel { AudioContentMainRankingViewModel(get()) }
|
||||||
|
viewModel { AudioContentMainCurationViewModel(get()) }
|
||||||
|
viewModel { AudioContentMainOrderListViewModel(get()) }
|
||||||
|
viewModel { AudioContentMainNewContentViewModel(get()) }
|
||||||
|
viewModel { AudioContentMainNewContentCreatorViewModel(get()) }
|
||||||
viewModel { AudioContentViewModel(get()) }
|
viewModel { AudioContentViewModel(get()) }
|
||||||
viewModel { AudioContentOrderListViewModel(get()) }
|
viewModel { AudioContentOrderListViewModel(get()) }
|
||||||
viewModel { AudioContentUploadViewModel(get()) }
|
viewModel { AudioContentUploadViewModel(get()) }
|
||||||
|
@ -197,6 +219,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { AudioContentCurationViewModel(get()) }
|
viewModel { AudioContentCurationViewModel(get()) }
|
||||||
viewModel { AudioContentNewAllViewModel(get()) }
|
viewModel { AudioContentNewAllViewModel(get()) }
|
||||||
viewModel { AudioContentRankingAllViewModel(get()) }
|
viewModel { AudioContentRankingAllViewModel(get()) }
|
||||||
|
viewModel { RouletteSettingsViewModel(get()) }
|
||||||
|
viewModel { CreatorCommunityAllViewModel(get(), get()) }
|
||||||
|
viewModel { CreatorCommunityCommentListViewModel(get()) }
|
||||||
|
viewModel { CreatorCommunityWriteViewModel(get()) }
|
||||||
|
viewModel { CreatorCommunityModifyViewModel(get()) }
|
||||||
|
viewModel { CanCouponViewModel(get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val repositoryModule = module {
|
private val repositoryModule = module {
|
||||||
|
@ -219,6 +247,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
factory { FaqRepository(get()) }
|
factory { FaqRepository(get()) }
|
||||||
factory { MemberTagRepository(get()) }
|
factory { MemberTagRepository(get()) }
|
||||||
factory { UserProfileFantalkAllViewModel(get(), get()) }
|
factory { UserProfileFantalkAllViewModel(get(), get()) }
|
||||||
|
factory { RouletteRepository(get()) }
|
||||||
|
factory { CreatorCommunityRepository(get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val moduleList = listOf(
|
private val moduleList = listOf(
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package kr.co.vividnext.sodalive.dialog
|
||||||
|
|
||||||
|
import android.app.TimePickerDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.TimePicker
|
||||||
|
|
||||||
|
class SodaLiveTimePickerDialog(
|
||||||
|
context: Context,
|
||||||
|
themeResId: Int,
|
||||||
|
private val onTimeSetListener: OnTimeSetListener,
|
||||||
|
hourOfDay: Int,
|
||||||
|
minute: Int,
|
||||||
|
is24HourView: Boolean
|
||||||
|
) : TimePickerDialog(context, themeResId, null, hourOfDay, minute, is24HourView) {
|
||||||
|
private var timePicker: TimePicker? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
this.setTitle("Select Time")
|
||||||
|
setOnShowListener {
|
||||||
|
timePicker = window?.findViewById(
|
||||||
|
context.resources.getIdentifier(
|
||||||
|
"android:id/timePicker",
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
timePicker?.apply {
|
||||||
|
setIs24HourView(is24HourView)
|
||||||
|
setOnTimeChangedListener { _, _, minute ->
|
||||||
|
// Snap minute to nearest quarter (0, 15, 30, 45)
|
||||||
|
val snappedMinute = minute / 15 * 15
|
||||||
|
if (snappedMinute != minute) {
|
||||||
|
this.minute = snappedMinute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getButton(BUTTON_POSITIVE).setOnClickListener {
|
||||||
|
timePicker?.let { picker ->
|
||||||
|
onTimeSetListener.onTimeSet(picker, picker.hour, picker.minute)
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,73 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.explorer.profile
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.Toast
|
|
||||||
import com.orhanobut.logger.Logger
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
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.ActivityCreatorNoticeWriteBinding
|
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
|
||||||
import org.koin.android.ext.android.inject
|
|
||||||
|
|
||||||
class CreatorNoticeWriteActivity : BaseActivity<ActivityCreatorNoticeWriteBinding>(
|
|
||||||
ActivityCreatorNoticeWriteBinding::inflate
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val repository: ExplorerRepository by inject()
|
|
||||||
|
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
|
||||||
|
|
||||||
override fun setupView() {
|
|
||||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
|
||||||
binding.toolbar.tvBack.text = "공지사항 쓰기"
|
|
||||||
binding.toolbar.tvBack.setOnClickListener { finish() }
|
|
||||||
|
|
||||||
val notice = intent.getStringExtra("notice")
|
|
||||||
binding.etContent.setText(notice)
|
|
||||||
|
|
||||||
binding.tvSave.setOnClickListener {
|
|
||||||
loadingDialog.show(screenWidth)
|
|
||||||
|
|
||||||
val writtenNotice = binding.etContent.text.toString()
|
|
||||||
compositeDisposable.add(
|
|
||||||
repository.writeCreatorNotice(
|
|
||||||
notice = writtenNotice,
|
|
||||||
token = "Bearer ${SharedPreferenceManager.token}"
|
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(
|
|
||||||
{
|
|
||||||
loadingDialog.dismiss()
|
|
||||||
|
|
||||||
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
|
||||||
Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
message,
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
|
|
||||||
if (it.success) {
|
|
||||||
val dataIntent = Intent()
|
|
||||||
dataIntent.putExtra("notice", writtenNotice)
|
|
||||||
setResult(RESULT_OK, dataIntent)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loadingDialog.dismiss()
|
|
||||||
it.message?.let { message -> Logger.e(message) }
|
|
||||||
Toast.makeText(
|
|
||||||
applicationContext,
|
|
||||||
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +1,21 @@
|
||||||
package kr.co.vividnext.sodalive.explorer.profile
|
package kr.co.vividnext.sodalive.explorer.profile
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
|
||||||
data class GetCreatorProfileResponse(
|
data class GetCreatorProfileResponse(
|
||||||
@SerializedName("creator")
|
@SerializedName("creator")
|
||||||
val creator: CreatorResponse,
|
val creator: CreatorResponse,
|
||||||
@SerializedName("userDonationRanking")
|
@SerializedName("userDonationRanking")
|
||||||
val userDonationRanking: List<UserDonationRankingResponse>,
|
val userDonationRanking: List<UserDonationRankingResponse>,
|
||||||
@SerializedName("similarCreatorList")
|
|
||||||
val similarCreatorList: List<SimilarCreatorResponse>,
|
|
||||||
@SerializedName("liveRoomList")
|
@SerializedName("liveRoomList")
|
||||||
val liveRoomList: List<LiveRoomResponse>,
|
val liveRoomList: List<LiveRoomResponse>,
|
||||||
@SerializedName("contentList")
|
@SerializedName("contentList")
|
||||||
val contentList: List<GetAudioContentListItem>,
|
val contentList: List<GetAudioContentListItem>,
|
||||||
@SerializedName("notice")
|
@SerializedName("notice")
|
||||||
val notice: String,
|
val notice: String,
|
||||||
|
@SerializedName("communityPostList")
|
||||||
|
val communityPostList: List<GetCommunityPostListResponse>,
|
||||||
@SerializedName("cheers")
|
@SerializedName("cheers")
|
||||||
val cheers: GetCheersResponse,
|
val cheers: GetCheersResponse,
|
||||||
@SerializedName("activitySummary")
|
@SerializedName("activitySummary")
|
||||||
|
@ -45,13 +46,6 @@ data class UserDonationRankingResponse(
|
||||||
@SerializedName("donationCan") val donationCan: Int
|
@SerializedName("donationCan") val donationCan: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
data class SimilarCreatorResponse(
|
|
||||||
@SerializedName("userId") val userId: Long,
|
|
||||||
@SerializedName("nickname") val nickname: String,
|
|
||||||
@SerializedName("profileImage") val profileImage: String,
|
|
||||||
@SerializedName("tags") val tags: List<String>
|
|
||||||
)
|
|
||||||
|
|
||||||
data class LiveRoomResponse(
|
data class LiveRoomResponse(
|
||||||
@SerializedName("roomId") val roomId: Long,
|
@SerializedName("roomId") val roomId: Long,
|
||||||
@SerializedName("title") val title: String,
|
@SerializedName("title") val title: String,
|
||||||
|
@ -82,7 +76,8 @@ data class GetAudioContentListItem(
|
||||||
@SerializedName("duration") val duration: String?,
|
@SerializedName("duration") val duration: String?,
|
||||||
@SerializedName("likeCount") val likeCount: Int,
|
@SerializedName("likeCount") val likeCount: Int,
|
||||||
@SerializedName("commentCount") val commentCount: Int,
|
@SerializedName("commentCount") val commentCount: Int,
|
||||||
@SerializedName("isAdult") val isAdult: Boolean
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
|
@SerializedName("isScheduledToOpen") val isScheduledToOpen: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
data class GetCreatorActivitySummary(
|
data class GetCreatorActivitySummary(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package kr.co.vividnext.sodalive.explorer.profile
|
package kr.co.vividnext.sodalive.explorer.profile
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Activity
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -11,17 +10,18 @@ import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
|
import android.widget.LinearLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
|
import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
|
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
|
||||||
|
@ -33,12 +33,17 @@ import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAdapter
|
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAdapter
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
||||||
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.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.live.LiveViewModel
|
import kr.co.vividnext.sodalive.live.LiveViewModel
|
||||||
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
|
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
|
||||||
|
@ -50,6 +55,9 @@ 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 org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
ActivityUserProfileBinding::inflate
|
ActivityUserProfileBinding::inflate
|
||||||
|
@ -63,11 +71,8 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
private lateinit var liveAdapter: UserProfileLiveAdapter
|
private lateinit var liveAdapter: UserProfileLiveAdapter
|
||||||
private lateinit var audioContentAdapter: AudioContentAdapter
|
private lateinit var audioContentAdapter: AudioContentAdapter
|
||||||
private lateinit var donationAdapter: UserProfileDonationAdapter
|
private lateinit var donationAdapter: UserProfileDonationAdapter
|
||||||
private lateinit var similarCreatorAdapter: UserProfileSimilarCreatorAdapter
|
|
||||||
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
||||||
|
|
||||||
private lateinit var noticeWriteLauncher: ActivityResultLauncher<Intent>
|
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private var userId: Long = 0
|
private var userId: Long = 0
|
||||||
|
|
||||||
|
@ -76,17 +81,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
imm = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
imm = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
noticeWriteLauncher = registerForActivityResult(
|
|
||||||
ActivityResultContracts.StartActivityForResult()
|
|
||||||
) {
|
|
||||||
if (it.resultCode == Activity.RESULT_OK) {
|
|
||||||
val writtenNotice = it.data?.getStringExtra("notice")
|
|
||||||
binding.tvNotice.text = writtenNotice?.ifBlank {
|
|
||||||
"공지사항이 없습니다."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userId <= 0) {
|
if (userId <= 0) {
|
||||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
finish()
|
finish()
|
||||||
|
@ -122,9 +116,9 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
|
|
||||||
setupLiveView()
|
setupLiveView()
|
||||||
setupDonationView()
|
setupDonationView()
|
||||||
setupSimilarCreatorView()
|
|
||||||
setupFanTalkView()
|
setupFanTalkView()
|
||||||
setupAudioContentListView()
|
setupAudioContentListView()
|
||||||
|
setupCreatorCommunityView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideKeyboard(onAfterExecute: () -> Unit) {
|
private fun hideKeyboard(onAfterExecute: () -> Unit) {
|
||||||
|
@ -310,51 +304,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
recyclerView.adapter = donationAdapter
|
recyclerView.adapter = donationAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupSimilarCreatorView() {
|
|
||||||
val recyclerView = binding.layoutUserProfileSimilarCreator.rvSimilarCreator
|
|
||||||
similarCreatorAdapter = UserProfileSimilarCreatorAdapter {
|
|
||||||
val intent = Intent(applicationContext, UserProfileActivity::class.java)
|
|
||||||
intent.putExtra(Constants.EXTRA_USER_ID, it.userId)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
recyclerView.layoutManager = LinearLayoutManager(
|
|
||||||
applicationContext,
|
|
||||||
LinearLayoutManager.VERTICAL,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
|
||||||
override fun getItemOffsets(
|
|
||||||
outRect: Rect,
|
|
||||||
view: View,
|
|
||||||
parent: RecyclerView,
|
|
||||||
state: RecyclerView.State
|
|
||||||
) {
|
|
||||||
super.getItemOffsets(outRect, view, parent, state)
|
|
||||||
|
|
||||||
when (parent.getChildAdapterPosition(view)) {
|
|
||||||
0 -> {
|
|
||||||
outRect.top = 0
|
|
||||||
outRect.bottom = 10f.dpToPx().toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
similarCreatorAdapter.itemCount - 1 -> {
|
|
||||||
outRect.top = 10f.dpToPx().toInt()
|
|
||||||
outRect.bottom = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
outRect.top = 10f.dpToPx().toInt()
|
|
||||||
outRect.bottom = 10f.dpToPx().toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
recyclerView.adapter = similarCreatorAdapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupFanTalkView() {
|
private fun setupFanTalkView() {
|
||||||
binding.layoutUserProfileFanTalk.tvAll.setOnClickListener {
|
binding.layoutUserProfileFanTalk.tvAll.setOnClickListener {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
|
@ -528,6 +477,19 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
dialog.show(screenWidth)
|
dialog.show(screenWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupCreatorCommunityView() {
|
||||||
|
binding.layoutCreatorCommunityPost.ivWrite.setOnClickListener {
|
||||||
|
startActivity(Intent(applicationContext, CreatorCommunityWriteActivity::class.java))
|
||||||
|
}
|
||||||
|
binding.layoutCreatorCommunityPost.llAll.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, userId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun bindData() {
|
private fun bindData() {
|
||||||
liveViewModel.toastLiveData.observe(this) {
|
liveViewModel.toastLiveData.observe(this) {
|
||||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
@ -556,20 +518,11 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
viewModel.creatorProfileLiveData.observe(this) {
|
viewModel.creatorProfileLiveData.observe(this) {
|
||||||
setCheers(it.cheers)
|
setCheers(it.cheers)
|
||||||
setCreatorProfile(it.creator)
|
setCreatorProfile(it.creator)
|
||||||
setCreatorNotice(it.notice, it.creator.creatorId)
|
|
||||||
setAudioContentList(it.contentList)
|
setAudioContentList(it.contentList)
|
||||||
setLiveRoomList(it.liveRoomList)
|
setLiveRoomList(it.liveRoomList)
|
||||||
setSimilarCreatorList(it.similarCreatorList)
|
|
||||||
setUserDonationRanking(it.userDonationRanking)
|
setUserDonationRanking(it.userDonationRanking)
|
||||||
setActivitySummary(it.activitySummary)
|
setActivitySummary(it.activitySummary)
|
||||||
}
|
setCommunityPostList(it.communityPostList)
|
||||||
|
|
||||||
viewModel.isExpandNotice.observe(this) {
|
|
||||||
if (it) {
|
|
||||||
binding.tvNotice.maxLines = Int.MAX_VALUE
|
|
||||||
} else {
|
|
||||||
binding.tvNotice.maxLines = 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -684,28 +637,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
binding.layoutUserProfileIntroduce.tvIntroduce.text = introduce
|
binding.layoutUserProfileIntroduce.tvIntroduce.text = introduce
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setCreatorNotice(notice: String, creatorId: Long) {
|
|
||||||
binding.tvNotice.text = notice.ifBlank {
|
|
||||||
"공지사항이 없습니다."
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.rlNotice.setOnClickListener {
|
|
||||||
if (creatorId == SharedPreferenceManager.userId) {
|
|
||||||
val intent = Intent(applicationContext, CreatorNoticeWriteActivity::class.java)
|
|
||||||
intent.putExtra("notice", notice)
|
|
||||||
noticeWriteLauncher.launch(intent)
|
|
||||||
} else {
|
|
||||||
viewModel.toggleExpandNotice()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.ivWrite.visibility = if (creatorId == SharedPreferenceManager.userId) {
|
|
||||||
View.VISIBLE
|
|
||||||
} else {
|
|
||||||
View.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun setAudioContentList(audioContentList: List<GetAudioContentListItem>) {
|
private fun setAudioContentList(audioContentList: List<GetAudioContentListItem>) {
|
||||||
binding.layoutUserProfileAudioContent.root.visibility =
|
binding.layoutUserProfileAudioContent.root.visibility =
|
||||||
|
@ -748,18 +679,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
|
||||||
private fun setSimilarCreatorList(similarCreatorList: List<SimilarCreatorResponse>) {
|
|
||||||
if (similarCreatorList.isEmpty()) {
|
|
||||||
binding.llUserProfileSimilarCreator.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.llUserProfileSimilarCreator.visibility = View.VISIBLE
|
|
||||||
similarCreatorAdapter.items.clear()
|
|
||||||
similarCreatorAdapter.items.addAll(similarCreatorList)
|
|
||||||
similarCreatorAdapter.notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun setUserDonationRanking(userDonationRanking: List<UserDonationRankingResponse>) {
|
private fun setUserDonationRanking(userDonationRanking: List<UserDonationRankingResponse>) {
|
||||||
if (userDonationRanking.isEmpty()) {
|
if (userDonationRanking.isEmpty()) {
|
||||||
|
@ -772,6 +691,88 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setCommunityPostList(communityPostList: List<GetCommunityPostListResponse>) {
|
||||||
|
if (communityPostList.isEmpty()) {
|
||||||
|
if (userId == SharedPreferenceManager.userId) {
|
||||||
|
binding.layoutCreatorCommunityPost.root.visibility = View.VISIBLE
|
||||||
|
binding.layoutCreatorCommunityPost.llNoPost.visibility = View.VISIBLE
|
||||||
|
binding.layoutCreatorCommunityPost.llNoPost.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
applicationContext,
|
||||||
|
CreatorCommunityWriteActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.layoutCreatorCommunityPost.root.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutCreatorCommunityPost.hsvPost.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.layoutCreatorCommunityPost.root.visibility = View.VISIBLE
|
||||||
|
binding.layoutCreatorCommunityPost.llNoPost.visibility = View.GONE
|
||||||
|
binding.layoutCreatorCommunityPost.hsvPost.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
if (userId == SharedPreferenceManager.userId) {
|
||||||
|
binding.layoutCreatorCommunityPost.ivWrite.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.layoutCreatorCommunityPost.ivWrite.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutCreatorCommunityPost.llContainer.removeAllViews()
|
||||||
|
communityPostList.forEachIndexed { index, item ->
|
||||||
|
val layout = ItemCreatorCommunityBinding.inflate(
|
||||||
|
LayoutInflater.from(this@UserProfileActivity),
|
||||||
|
binding.layoutCreatorCommunityPost.llContainer,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
setCommunityPost(layout, item, index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setCommunityPost(
|
||||||
|
layout: ItemCreatorCommunityBinding,
|
||||||
|
item: GetCommunityPostListResponse,
|
||||||
|
index: Int
|
||||||
|
) {
|
||||||
|
layout.ivCreatorProfile.loadUrl(item.creatorProfileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
layout.tvCreatorNickname.text = item.creatorNickname
|
||||||
|
layout.tvDate.text = item.date
|
||||||
|
|
||||||
|
layout.tvContent.text = item.content
|
||||||
|
layout.ivPostImage.loadUrl(item.imageUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.tvLikeCount.text = "${item.likeCount}"
|
||||||
|
layout.tvCommentCount.text = "${item.commentCount}"
|
||||||
|
|
||||||
|
layout.root.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, userId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
val lp = layout.root.layoutParams as LinearLayout.LayoutParams
|
||||||
|
lp.marginStart = 13.3f.dpToPx().toInt()
|
||||||
|
layout.root.layoutParams = lp
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutCreatorCommunityPost.llContainer.addView(layout.root)
|
||||||
|
}
|
||||||
|
|
||||||
private fun reservationRoom(roomId: Long) {
|
private fun reservationRoom(roomId: Long) {
|
||||||
liveViewModel.getRoomDetail(roomId) {
|
liveViewModel.getRoomDetail(roomId) {
|
||||||
if (it.manager.id == SharedPreferenceManager.userId) {
|
if (it.manager.id == SharedPreferenceManager.userId) {
|
||||||
|
@ -850,6 +851,15 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
val beginDateFormat = SimpleDateFormat("yyyy.MM.dd EEE hh:mm a", Locale.ENGLISH)
|
||||||
|
val beginDate = beginDateFormat.parse(it.beginDateTime)!!
|
||||||
|
val now = Date()
|
||||||
|
|
||||||
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd, HH:mm", Locale.getDefault())
|
||||||
|
val diffTime: Long = now.time - beginDate.time
|
||||||
|
val hours = (diffTime / (1000 * 60 * 60)).toInt()
|
||||||
|
val mins = (diffTime / (1000 * 60)).toInt() % 60
|
||||||
|
|
||||||
if (it.isPrivateRoom) {
|
if (it.isPrivateRoom) {
|
||||||
LiveRoomPasswordDialog(
|
LiveRoomPasswordDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
|
@ -867,8 +877,23 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
LivePaymentDialog(
|
LivePaymentDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
layoutInflater = layoutInflater,
|
layoutInflater = layoutInflater,
|
||||||
title = "${it.price.moneyFormat()}캔으로 입장",
|
title = "유료 라이브 입장",
|
||||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
startDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(beginDate)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
nowDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(now)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
desc = "${it.price}캔을 차감하고\n라이브에 입장 하시겠습니까?",
|
||||||
|
desc2 = if (hours >= 1) {
|
||||||
|
"라이브를 시작한 지 ${hours}시간 ${mins}분이 지났습니다. 라이브에 입장 후 30분 이내에 라이브가 종료될 수도 있습니다."
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
confirmButtonTitle = "결제 후 입장",
|
confirmButtonTitle = "결제 후 입장",
|
||||||
confirmButtonClick = {
|
confirmButtonClick = {
|
||||||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.explorer.profile
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import coil.load
|
|
||||||
import coil.transform.CircleCropTransformation
|
|
||||||
import kr.co.vividnext.sodalive.R
|
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemUserProfileSimilarCreatorBinding
|
|
||||||
|
|
||||||
class UserProfileSimilarCreatorAdapter(
|
|
||||||
private val onClickItem: (SimilarCreatorResponse) -> Unit
|
|
||||||
) : RecyclerView.Adapter<UserProfileSimilarCreatorAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
val items = mutableListOf<SimilarCreatorResponse>()
|
|
||||||
|
|
||||||
inner class ViewHolder(
|
|
||||||
private val binding: ItemUserProfileSimilarCreatorBinding
|
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
|
||||||
fun bind(item: SimilarCreatorResponse) {
|
|
||||||
binding.ivProfile.load(item.profileImage) {
|
|
||||||
crossfade(true)
|
|
||||||
placeholder(R.drawable.ic_place_holder)
|
|
||||||
transformations(CircleCropTransformation())
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.tvNickname.text = item.nickname
|
|
||||||
binding.tvTags.text = item.tags.joinToString(" ") { "#$it" }
|
|
||||||
binding.root.setOnClickListener { onClickItem(item) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
|
||||||
ItemUserProfileSimilarCreatorBinding.inflate(
|
|
||||||
LayoutInflater.from(parent.context),
|
|
||||||
parent,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
holder.bind(items[position])
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount() = items.count()
|
|
||||||
}
|
|
|
@ -16,6 +16,7 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
import kr.co.vividnext.sodalive.report.ReportRepository
|
import kr.co.vividnext.sodalive.report.ReportRepository
|
||||||
import kr.co.vividnext.sodalive.report.ReportRequest
|
import kr.co.vividnext.sodalive.report.ReportRequest
|
||||||
import kr.co.vividnext.sodalive.report.ReportType
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
|
@ -38,10 +39,6 @@ class UserProfileViewModel(
|
||||||
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
|
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
|
||||||
get() = _creatorProfileLiveData
|
get() = _creatorProfileLiveData
|
||||||
|
|
||||||
private val _isExpandNotice = MutableLiveData(false)
|
|
||||||
val isExpandNotice: LiveData<Boolean>
|
|
||||||
get() = _isExpandNotice
|
|
||||||
|
|
||||||
private var creatorNickname = ""
|
private var creatorNickname = ""
|
||||||
|
|
||||||
fun cheersReport(cheersId: Long, reason: String) {
|
fun cheersReport(cheersId: Long, reason: String) {
|
||||||
|
@ -216,10 +213,6 @@ class UserProfileViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleExpandNotice() {
|
|
||||||
_isExpandNotice.value = !isExpandNotice.value!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeCheers(parentCheersId: Long? = null, creatorId: Long, cheersContent: String) {
|
fun writeCheers(parentCheersId: Long? = null, creatorId: Long, cheersContent: String) {
|
||||||
if (cheersContent.isBlank()) {
|
if (cheersContent.isBlank()) {
|
||||||
_toastLiveData.postValue("내용을 입력하세요")
|
_toastLiveData.postValue("내용을 입력하세요")
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
|
|
||||||
|
class CreatorCommunityAdapter(
|
||||||
|
private val onClickItem: (Long) -> Unit
|
||||||
|
) : RecyclerView.Adapter<CreatorCommunityAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetCommunityPostListResponse>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemCreatorCommunityBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: GetCommunityPostListResponse) {
|
||||||
|
binding.ivCreatorProfile.loadUrl(item.creatorProfileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
binding.tvCreatorNickname.text = item.creatorNickname
|
||||||
|
binding.tvDate.text = item.date
|
||||||
|
|
||||||
|
binding.tvContent.text = item.content
|
||||||
|
binding.ivPostImage.loadUrl(item.imageUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvLikeCount.text = "${item.likeCount}"
|
||||||
|
binding.tvCommentCount.text = "${item.commentCount}"
|
||||||
|
|
||||||
|
binding.root.setOnClickListener { onClickItem(item.creatorId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemCreatorCommunityBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.PostCommunityPostLikeRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreateCommunityPostCommentRequest
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.Multipart
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.PUT
|
||||||
|
import retrofit2.http.Part
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
interface CreatorCommunityApi {
|
||||||
|
@POST("/creator-community")
|
||||||
|
@Multipart
|
||||||
|
fun createCommunityPost(
|
||||||
|
@Part postImage: MultipartBody.Part?,
|
||||||
|
@Part("request") request: RequestBody,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@PUT("/creator-community")
|
||||||
|
@Multipart
|
||||||
|
fun modifyCommunityPost(
|
||||||
|
@Part postImage: MultipartBody.Part?,
|
||||||
|
@Part("request") request: RequestBody,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@GET("/creator-community")
|
||||||
|
fun getCommunityPostList(
|
||||||
|
@Query("creatorId") creatorId: Long,
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Query("timezone") timezone: String,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetCommunityPostListResponse>>>
|
||||||
|
|
||||||
|
@GET("/creator-community/latest")
|
||||||
|
fun getLatestPostListFromCreatorsYouFollow(
|
||||||
|
@Query("timezone") timezone: String,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetCommunityPostListResponse>>>
|
||||||
|
|
||||||
|
@POST("/creator-community/like")
|
||||||
|
fun communityPostLike(
|
||||||
|
@Body request: PostCommunityPostLikeRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@GET("/creator-community/{id}/comment")
|
||||||
|
fun getCommunityPostCommentList(
|
||||||
|
@Path("id") postId: Long,
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Query("timezone") timezone: String,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetCommunityPostCommentListResponse>>
|
||||||
|
|
||||||
|
@POST("/creator-community/comment")
|
||||||
|
fun createCommunityPostComment(
|
||||||
|
@Body request: CreateCommunityPostCommentRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@PUT("/creator-community/comment")
|
||||||
|
fun modifyComment(
|
||||||
|
@Body request: ModifyCommentRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@GET("/creator-community/comment/{id}")
|
||||||
|
fun getCommentReplyList(
|
||||||
|
@Path("id") commentId: Long,
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Query("timezone") timezone: String,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetCommunityPostCommentListResponse>>
|
||||||
|
|
||||||
|
@GET("/creator-community/{id}")
|
||||||
|
fun getCommunityPostDetail(
|
||||||
|
@Path("id") postId: Long,
|
||||||
|
@Query("timezone") timezone: String,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetCommunityPostListResponse>>
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.PostCommunityPostLikeRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreateCommunityPostCommentRequest
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
class CreatorCommunityRepository(private val api: CreatorCommunityApi) {
|
||||||
|
fun getCommunityPostList(
|
||||||
|
creatorId: Long,
|
||||||
|
page: Int,
|
||||||
|
size: Int,
|
||||||
|
token: String
|
||||||
|
) = api.getCommunityPostList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getLatestPostListFromCreatorsYouFollow(
|
||||||
|
token: String
|
||||||
|
) = api.getLatestPostListFromCreatorsYouFollow(
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun communityPostLike(postId: Long, token: String) = api.communityPostLike(
|
||||||
|
request = PostCommunityPostLikeRequest(postId = postId),
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getCommunityPostCommentList(
|
||||||
|
postId: Long,
|
||||||
|
page: Int,
|
||||||
|
size: Int,
|
||||||
|
token: String
|
||||||
|
) = api.getCommunityPostCommentList(
|
||||||
|
postId = postId,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun registerComment(
|
||||||
|
postId: Long,
|
||||||
|
comment: String,
|
||||||
|
parentId: Long? = null,
|
||||||
|
token: String
|
||||||
|
) = api.createCommunityPostComment(
|
||||||
|
request = CreateCommunityPostCommentRequest(
|
||||||
|
comment = comment,
|
||||||
|
postId = postId,
|
||||||
|
parentId = parentId
|
||||||
|
),
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun modifyComment(request: ModifyCommentRequest, token: String) = api.modifyComment(
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getCommentReplyList(commentId: Long, page: Int, size: Int, token: String) = api.getCommentReplyList(
|
||||||
|
commentId = commentId,
|
||||||
|
page = page,
|
||||||
|
size = size,
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun createCommunityPost(
|
||||||
|
postImage: MultipartBody.Part?,
|
||||||
|
request: RequestBody,
|
||||||
|
token: String
|
||||||
|
) = api.createCommunityPost(
|
||||||
|
postImage = postImage,
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun modifyCommunityPost(
|
||||||
|
postImage: MultipartBody.Part?,
|
||||||
|
request: RequestBody,
|
||||||
|
token: String
|
||||||
|
) = api.modifyCommunityPost(
|
||||||
|
postImage = postImage,
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getCommunityPostDetail(postId: Long, token: String) = api.getCommunityPostDetail(
|
||||||
|
postId = postId,
|
||||||
|
timezone = TimeZone.getDefault().id,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
data class GetCommunityPostCommentListResponse(
|
||||||
|
@SerializedName("totalCount") val totalCount: Int,
|
||||||
|
@SerializedName("items") val items: List<GetCommunityPostCommentListItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class GetCommunityPostCommentListItem(
|
||||||
|
@SerializedName("id") val id: Long,
|
||||||
|
@SerializedName("writerId") val writerId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileUrl") val profileUrl: String,
|
||||||
|
@SerializedName("comment") val comment: String,
|
||||||
|
@SerializedName("date") val date: String,
|
||||||
|
@SerializedName("replyCount") val replyCount: Int,
|
||||||
|
) : Parcelable
|
|
@ -0,0 +1,20 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class GetCommunityPostListResponse(
|
||||||
|
@SerializedName("postId") val postId: Long,
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("creatorNickname") val creatorNickname: String,
|
||||||
|
@SerializedName("creatorProfileUrl") val creatorProfileUrl: String,
|
||||||
|
@SerializedName("imageUrl") val imageUrl: String?,
|
||||||
|
@SerializedName("content") val content: String,
|
||||||
|
@SerializedName("date") val date: String,
|
||||||
|
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
||||||
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
|
@SerializedName("isLike") var isLike: Boolean,
|
||||||
|
@SerializedName("likeCount") val likeCount: Int,
|
||||||
|
@SerializedName("commentCount") val commentCount: Int,
|
||||||
|
@SerializedName("firstComment") val firstComment: GetCommunityPostCommentListItem?,
|
||||||
|
@SerializedName("isExpand") var isExpand: Boolean = false
|
||||||
|
)
|
|
@ -0,0 +1,195 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityAllBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentFragment
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.CreatorCommunityModifyActivity
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CreatorCommunityAllActivity : BaseActivity<ActivityCreatorCommunityAllBinding>(
|
||||||
|
ActivityCreatorCommunityAllBinding::inflate
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val viewModel: CreatorCommunityAllViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var adapter: CreatorCommunityAllAdapter
|
||||||
|
|
||||||
|
private var creatorId: Long = 0
|
||||||
|
|
||||||
|
private val modifyResult = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
viewModel.page = 1
|
||||||
|
viewModel.isLast = false
|
||||||
|
viewModel.getCommunityPostList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
creatorId = intent.getLongExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, 0)
|
||||||
|
if (creatorId <= 0) {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
viewModel.creatorId = creatorId
|
||||||
|
viewModel.getCommunityPostList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
binding.toolbar.tvBack.text = "커뮤니티"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
adapter = CreatorCommunityAllAdapter(
|
||||||
|
onClickLike = { viewModel.communityPostLike(it) },
|
||||||
|
writeComment = { postId, parentId, comment ->
|
||||||
|
viewModel.registerComment(
|
||||||
|
comment,
|
||||||
|
postId,
|
||||||
|
parentId
|
||||||
|
)
|
||||||
|
},
|
||||||
|
showCommentBottomSheetDialog = {
|
||||||
|
val dialog = CreatorCommunityCommentFragment(
|
||||||
|
creatorId = creatorId,
|
||||||
|
postId = it
|
||||||
|
)
|
||||||
|
dialog.show(
|
||||||
|
supportFragmentManager,
|
||||||
|
dialog.tag
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickModify = {
|
||||||
|
modifyResult.launch(
|
||||||
|
Intent(
|
||||||
|
applicationContext,
|
||||||
|
CreatorCommunityModifyActivity::class.java
|
||||||
|
).apply {
|
||||||
|
putExtra(Constants.EXTRA_COMMUNITY_POST_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickDelete = { postId ->
|
||||||
|
SodaDialog(
|
||||||
|
activity = this@CreatorCommunityAllActivity,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = "게시물 삭제",
|
||||||
|
desc = "삭제하시겠습니까?",
|
||||||
|
confirmButtonTitle = "삭제",
|
||||||
|
confirmButtonClick = {
|
||||||
|
viewModel.deleteCommunityPostList(postId = postId)
|
||||||
|
},
|
||||||
|
cancelButtonTitle = "취소",
|
||||||
|
cancelButtonClick = {}
|
||||||
|
).show(screenWidth)
|
||||||
|
},
|
||||||
|
onClickReport = { postId ->
|
||||||
|
CreatorCommunityReportDialog(this@CreatorCommunityAllActivity, layoutInflater) {
|
||||||
|
viewModel.report(
|
||||||
|
communityPostId = postId,
|
||||||
|
reason = it
|
||||||
|
)
|
||||||
|
}.show(screenWidth)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val recyclerView = binding.rvCreatorCommunity
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
|
||||||
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
|
0 -> {
|
||||||
|
outRect.top = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.itemCount - 1 -> {
|
||||||
|
outRect.top = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.top = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
|
val lastVisiblePosition = (recyclerView.layoutManager as LinearLayoutManager)
|
||||||
|
.findLastVisibleItemPosition()
|
||||||
|
val itemTotalCount = adapter.itemCount - 1
|
||||||
|
|
||||||
|
if (itemTotalCount > 0 && lastVisiblePosition == itemTotalCount) {
|
||||||
|
viewModel.getCommunityPostList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.toastLiveData.observe(this) {
|
||||||
|
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth, "")
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.communityPostListLiveData.observe(this) {
|
||||||
|
if (viewModel.page == 2) {
|
||||||
|
adapter.items.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.items.addAll(it)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.style.ClickableSpan
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityAllBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
class CreatorCommunityAllAdapter(
|
||||||
|
private val onClickLike: (Long) -> Unit,
|
||||||
|
private val writeComment: (Long, Long?, String) -> Unit,
|
||||||
|
private val showCommentBottomSheetDialog: (Long) -> Unit,
|
||||||
|
private val onClickModify: (Long) -> Unit,
|
||||||
|
private val onClickDelete: (Long) -> Unit,
|
||||||
|
private val onClickReport: (Long) -> Unit
|
||||||
|
) : RecyclerView.Adapter<CreatorCommunityAllAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetCommunityPostListResponse>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val context: Context,
|
||||||
|
private val binding: ItemCreatorCommunityAllBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun bind(item: GetCommunityPostListResponse, index: Int) {
|
||||||
|
binding.tvDate.text = item.date
|
||||||
|
binding.tvNickname.text = item.creatorNickname
|
||||||
|
binding.ivCreatorProfile.loadUrl(item.creatorProfileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
setNoticeAndClickableUrl(binding.tvContent, item.content)
|
||||||
|
binding.tvContent.setOnClickListener {
|
||||||
|
items[index] = items[index].copy(
|
||||||
|
isExpand = !item.isExpand,
|
||||||
|
)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
binding.tvContent.maxLines = if (item.isExpand) {
|
||||||
|
Int.MAX_VALUE
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivSeeMore.setOnClickListener {
|
||||||
|
showOptionMenu(
|
||||||
|
context = context,
|
||||||
|
v = binding.ivSeeMore,
|
||||||
|
postId = item.postId,
|
||||||
|
creatorId = item.creatorId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivLike.setImageResource(
|
||||||
|
if (item.isLike) {
|
||||||
|
R.drawable.ic_audio_content_heart_pressed
|
||||||
|
} else {
|
||||||
|
R.drawable.ic_audio_content_heart_normal
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.tvLike.text = "${item.likeCount}"
|
||||||
|
binding.llLike.setOnClickListener {
|
||||||
|
val isLike = !item.isLike
|
||||||
|
|
||||||
|
items[index] = items[index].copy(
|
||||||
|
isLike = !item.isLike,
|
||||||
|
likeCount = if (isLike) item.likeCount + 1 else item.likeCount - 1
|
||||||
|
)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
|
||||||
|
onClickLike(item.postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.imageUrl != null) {
|
||||||
|
binding.ivContent.visibility = View.VISIBLE
|
||||||
|
binding.ivContent.loadUrl(item.imageUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.ivContent.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isCommentAvailable) {
|
||||||
|
binding.llComment.visibility = View.VISIBLE
|
||||||
|
binding.tvCommentCount.text = "${item.commentCount}"
|
||||||
|
} else {
|
||||||
|
binding.llComment.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.commentCount > 0) {
|
||||||
|
binding.ivCommentProfile.load(item.firstComment!!.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
binding.tvCommentText.text = item.firstComment.comment
|
||||||
|
binding.tvCommentText.visibility = View.VISIBLE
|
||||||
|
binding.rlInputComment.visibility = View.GONE
|
||||||
|
|
||||||
|
binding.llComment.setOnClickListener { showCommentBottomSheetDialog(item.postId) }
|
||||||
|
} else {
|
||||||
|
binding.tvCommentText.visibility = View.GONE
|
||||||
|
binding.rlInputComment.visibility = View.VISIBLE
|
||||||
|
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivCommentSend.setOnClickListener {
|
||||||
|
val comment = binding.etComment.text.toString()
|
||||||
|
binding.etComment.setText("")
|
||||||
|
writeComment(item.postId, null, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llComment.setOnClickListener {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setNoticeAndClickableUrl(textView: TextView, text: String) {
|
||||||
|
textView.text = text
|
||||||
|
|
||||||
|
val spannable = SpannableString(text)
|
||||||
|
val pattern = Pattern.compile("https?://\\S+")
|
||||||
|
val matcher = pattern.matcher(spannable)
|
||||||
|
|
||||||
|
while (matcher.find()) {
|
||||||
|
val start = matcher.start()
|
||||||
|
val end = matcher.end()
|
||||||
|
val clickableSpan = object : ClickableSpan() {
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
val url = spannable.subSequence(start, end).toString()
|
||||||
|
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spannable.setSpan(clickableSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
textView.text = spannable
|
||||||
|
textView.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
parent.context,
|
||||||
|
ItemCreatorCommunityAllBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position], position)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showOptionMenu(
|
||||||
|
context: Context,
|
||||||
|
v: View,
|
||||||
|
postId: Long,
|
||||||
|
creatorId: Long
|
||||||
|
) {
|
||||||
|
val popup = PopupMenu(context, v)
|
||||||
|
val inflater = popup.menuInflater
|
||||||
|
|
||||||
|
if (creatorId == SharedPreferenceManager.userId) {
|
||||||
|
inflater.inflate(R.menu.community_post_creator_option_menu, popup.menu)
|
||||||
|
} else {
|
||||||
|
inflater.inflate(R.menu.community_post_option_menu, popup.menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.menu_modify -> {
|
||||||
|
onClickModify(postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_delete -> {
|
||||||
|
onClickDelete(postId)
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_report -> {
|
||||||
|
onClickReport(postId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,223 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.ModifyCommunityPostRequest
|
||||||
|
import kr.co.vividnext.sodalive.report.ReportRepository
|
||||||
|
import kr.co.vividnext.sodalive.report.ReportRequest
|
||||||
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
|
||||||
|
class CreatorCommunityAllViewModel(
|
||||||
|
private val repository: CreatorCommunityRepository,
|
||||||
|
private val reportRepository: ReportRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private var _communityPostListLiveData = MutableLiveData<List<GetCommunityPostListResponse>>()
|
||||||
|
val communityPostListLiveData: LiveData<List<GetCommunityPostListResponse>>
|
||||||
|
get() = _communityPostListLiveData
|
||||||
|
|
||||||
|
var page = 1
|
||||||
|
var isLast = false
|
||||||
|
private val pageSize = 10
|
||||||
|
|
||||||
|
var creatorId = 0L
|
||||||
|
|
||||||
|
fun getCommunityPostList() {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository
|
||||||
|
.getCommunityPostList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
page = page,
|
||||||
|
size = pageSize,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
if (it.data.isNotEmpty()) {
|
||||||
|
page += 1
|
||||||
|
_communityPostListLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
isLast = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCommunityPostList(postId: Long) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val request = ModifyCommunityPostRequest(
|
||||||
|
creatorCommunityId = postId,
|
||||||
|
isActive = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val requestJson = Gson().toJson(request)
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.modifyCommunityPost(
|
||||||
|
null,
|
||||||
|
request = requestJson.toRequestBody("text/plain".toMediaType()),
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success) {
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
getCommunityPostList()
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun communityPostLike(postId: Long) {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.communityPostLike(
|
||||||
|
postId = postId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({}, {})
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerComment(comment: String, postId: Long, parentId: Long? = null) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.registerComment(
|
||||||
|
postId = postId,
|
||||||
|
comment = comment,
|
||||||
|
parentId = parentId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
if (it.success) {
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
getCommunityPostList()
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun report(communityPostId: Long, reason: String) {
|
||||||
|
_isLoading.value = true
|
||||||
|
val request = ReportRequest(
|
||||||
|
type = ReportType.COMMUNITY_POST,
|
||||||
|
reason = reason,
|
||||||
|
communityPostId = communityPostId
|
||||||
|
)
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
reportRepository.report(
|
||||||
|
request = request,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"신고가 접수되었습니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("신고가 접수되었습니다.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogCommunityPostReportBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class CreatorCommunityReportDialog(
|
||||||
|
activity: Activity,
|
||||||
|
layoutInflater: LayoutInflater,
|
||||||
|
confirmButtonClick: (String) -> Unit
|
||||||
|
) {
|
||||||
|
private val alertDialog: AlertDialog
|
||||||
|
val dialogView = DialogCommunityPostReportBinding.inflate(layoutInflater)
|
||||||
|
var reason = ""
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
|
dialogBuilder.setView(dialogView.root)
|
||||||
|
|
||||||
|
alertDialog = dialogBuilder.create()
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
|
||||||
|
dialogView.tvCancel.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvReport.setOnClickListener {
|
||||||
|
if (reason.isNotBlank()) {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
confirmButtonClick(reason)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(activity, "신고 이유를 선택하세요.", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.radioGroup.setOnCheckedChangeListener { radioGroup, checkedId ->
|
||||||
|
val radioButton = radioGroup.findViewById<RadioButton>(checkedId)
|
||||||
|
reason = radioButton.text.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(width: Int) {
|
||||||
|
alertDialog.show()
|
||||||
|
|
||||||
|
val lp = WindowManager.LayoutParams()
|
||||||
|
lp.copyFrom(alertDialog.window?.attributes)
|
||||||
|
lp.width = width - (26.7f.dpToPx()).toInt()
|
||||||
|
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
alertDialog.window?.attributes = lp
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class PostCommunityPostLikeRequest(
|
||||||
|
@SerializedName("postId") val postId: Long
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class CreateCommunityPostCommentRequest(
|
||||||
|
@SerializedName("comment") val comment: String,
|
||||||
|
@SerializedName("postId") val postId: Long,
|
||||||
|
@SerializedName("parentId") val parentId: Long?
|
||||||
|
)
|
|
@ -0,0 +1,128 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||||
|
|
||||||
|
class CreatorCommunityCommentAdapter(
|
||||||
|
private val creatorId: Long,
|
||||||
|
private val modifyComment: (Long, String) -> Unit,
|
||||||
|
private val onClickDelete: (Long) -> Unit,
|
||||||
|
private val onItemClick: (GetCommunityPostCommentListItem) -> Unit
|
||||||
|
) : RecyclerView.Adapter<CreatorCommunityCommentAdapter.ViewHolder>() {
|
||||||
|
var items = mutableSetOf<GetCommunityPostCommentListItem>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val context: Context,
|
||||||
|
private val binding: ItemCommunityPostCommentBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
fun bind(item: GetCommunityPostCommentListItem) {
|
||||||
|
binding.ivCommentProfile.load(item.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvComment.text = item.comment
|
||||||
|
binding.tvCommentDate.text = item.date
|
||||||
|
binding.tvCommentNickname.text = item.nickname
|
||||||
|
|
||||||
|
binding.tvWriteReply.text = if (item.replyCount > 0) {
|
||||||
|
"답글 ${item.replyCount}개"
|
||||||
|
} else {
|
||||||
|
"답글 쓰기"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.writerId == SharedPreferenceManager.userId ||
|
||||||
|
creatorId == SharedPreferenceManager.userId
|
||||||
|
) {
|
||||||
|
binding.etCommentModify.setText(item.comment)
|
||||||
|
binding.ivMenu.visibility = View.VISIBLE
|
||||||
|
binding.ivMenu.setOnClickListener {
|
||||||
|
showOptionMenu(
|
||||||
|
context,
|
||||||
|
binding.ivMenu,
|
||||||
|
commentId = item.id,
|
||||||
|
writerId = item.writerId,
|
||||||
|
creatorId = creatorId,
|
||||||
|
onClickModify = {
|
||||||
|
binding.rlCommentModify.visibility = View.VISIBLE
|
||||||
|
binding.tvComment.visibility = View.GONE
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvModify.setOnClickListener {
|
||||||
|
binding.rlCommentModify.visibility = View.GONE
|
||||||
|
binding.tvComment.visibility = View.VISIBLE
|
||||||
|
modifyComment(item.id, binding.etCommentModify.text.toString())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.ivMenu.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvWriteReply.setOnClickListener { onItemClick(item) }
|
||||||
|
binding.root.setOnClickListener { onItemClick(item) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
parent.context,
|
||||||
|
ItemCommunityPostCommentBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items.toList()[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
private fun showOptionMenu(
|
||||||
|
context: Context,
|
||||||
|
v: View,
|
||||||
|
commentId: Long,
|
||||||
|
writerId: Long,
|
||||||
|
creatorId: Long,
|
||||||
|
onClickModify: () -> Unit
|
||||||
|
) {
|
||||||
|
val popup = PopupMenu(context, v)
|
||||||
|
val inflater = popup.menuInflater
|
||||||
|
|
||||||
|
if (writerId == SharedPreferenceManager.userId) {
|
||||||
|
inflater.inflate(R.menu.content_comment_option_menu, popup.menu)
|
||||||
|
} else if (creatorId == SharedPreferenceManager.userId) {
|
||||||
|
inflater.inflate(R.menu.content_comment_option_menu2, popup.menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.menu_review_modify -> {
|
||||||
|
onClickModify()
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_review_delete -> {
|
||||||
|
onClickDelete(commentId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogAudioContentCommentBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||||
|
|
||||||
|
class CreatorCommunityCommentFragment(
|
||||||
|
private val creatorId: Long,
|
||||||
|
private val postId: Long
|
||||||
|
) : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: DialogAudioContentCommentBinding
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val dialog = super.onCreateDialog(savedInstanceState)
|
||||||
|
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
val d = it as BottomSheetDialog
|
||||||
|
val bottomSheet = d.findViewById<FrameLayout>(
|
||||||
|
com.google.android.material.R.id.design_bottom_sheet
|
||||||
|
)
|
||||||
|
if (bottomSheet != null) {
|
||||||
|
BottomSheetBehavior.from(bottomSheet).state = BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = DialogAudioContentCommentBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val commentListFragmentTag = "COMMENT_LIST_FRAGMENT"
|
||||||
|
val commentListFragment = CreatorCommunityCommentListFragment.newInstance(
|
||||||
|
creatorId = creatorId,
|
||||||
|
postId = postId
|
||||||
|
)
|
||||||
|
val fragmentTransaction = childFragmentManager.beginTransaction()
|
||||||
|
fragmentTransaction.add(R.id.fl_container, commentListFragment, commentListFragmentTag)
|
||||||
|
fragmentTransaction.addToBackStack(commentListFragmentTag)
|
||||||
|
fragmentTransaction.commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hideCommentDialog() {
|
||||||
|
dialog?.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onClickComment(comment: GetCommunityPostCommentListItem) {
|
||||||
|
val commentReplyFragmentTag = "COMMENT_REPLY_FRAGMENT"
|
||||||
|
val commentReplyFragment = CreatorCommunityCommentReplyFragment.newInstance(
|
||||||
|
creatorId = creatorId,
|
||||||
|
postId = postId,
|
||||||
|
comment = comment
|
||||||
|
)
|
||||||
|
val fragmentTransaction = childFragmentManager.beginTransaction()
|
||||||
|
fragmentTransaction.add(R.id.fl_container, commentReplyFragment, commentReplyFragmentTag)
|
||||||
|
fragmentTransaction.addToBackStack(commentReplyFragmentTag)
|
||||||
|
fragmentTransaction.commit()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,214 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Service
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentListBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CreatorCommunityCommentListFragment : BaseFragment<FragmentAudioContentCommentListBinding>(
|
||||||
|
FragmentAudioContentCommentListBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: CreatorCommunityCommentListViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var imm: InputMethodManager
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var adapter: CreatorCommunityCommentAdapter
|
||||||
|
|
||||||
|
private var creatorId: Long = 0
|
||||||
|
private var postId: Long = 0
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
creatorId = arguments?.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID) ?: 0
|
||||||
|
postId = arguments?.getLong(Constants.EXTRA_COMMUNITY_POST_ID) ?: 0
|
||||||
|
return super.onCreateView(inflater, container, savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||||
|
imm = requireContext().getSystemService(
|
||||||
|
Service.INPUT_METHOD_SERVICE
|
||||||
|
) as InputMethodManager
|
||||||
|
|
||||||
|
setupView()
|
||||||
|
bindData()
|
||||||
|
viewModel.getCommentList(postId) { hideDialog() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideDialog() {
|
||||||
|
(parentFragment as CreatorCommunityCommentFragment).hideCommentDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupView() {
|
||||||
|
binding.ivClose.setOnClickListener { hideDialog() }
|
||||||
|
|
||||||
|
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivCommentSend.setOnClickListener {
|
||||||
|
hideKeyboard()
|
||||||
|
val comment = binding.etComment.text.toString()
|
||||||
|
binding.etComment.setText("")
|
||||||
|
viewModel.registerComment(postId, comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter = CreatorCommunityCommentAdapter(
|
||||||
|
creatorId = creatorId,
|
||||||
|
modifyComment = { commentId, comment ->
|
||||||
|
hideKeyboard()
|
||||||
|
viewModel.modifyComment(
|
||||||
|
commentId = commentId,
|
||||||
|
postId = postId,
|
||||||
|
comment = comment
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickDelete = {
|
||||||
|
SodaDialog(
|
||||||
|
activity = requireActivity(),
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = "댓글 삭제",
|
||||||
|
desc = "삭제하시겠습니까?",
|
||||||
|
confirmButtonTitle = "삭제",
|
||||||
|
confirmButtonClick = {
|
||||||
|
viewModel.modifyComment(
|
||||||
|
commentId = it,
|
||||||
|
postId = postId,
|
||||||
|
isActive = false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
cancelButtonTitle = "취소",
|
||||||
|
cancelButtonClick = {}
|
||||||
|
).show(screenWidth)
|
||||||
|
},
|
||||||
|
onItemClick = {
|
||||||
|
(parentFragment as CreatorCommunityCommentFragment).onClickComment(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val recyclerView = binding.rvComment
|
||||||
|
recyclerView.setHasFixedSize(true)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
activity,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
|
||||||
|
outRect.left = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.right = 13.3f.dpToPx().toInt()
|
||||||
|
|
||||||
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
|
0 -> {
|
||||||
|
outRect.top = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.itemCount - 1 -> {
|
||||||
|
outRect.top = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.top = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
|
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||||
|
.findLastCompletelyVisibleItemPosition()
|
||||||
|
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||||
|
|
||||||
|
// 스크롤이 끝에 도달했는지 확인
|
||||||
|
if (!recyclerView.canScrollVertically(1) &&
|
||||||
|
lastVisibleItemPosition == itemTotalCount
|
||||||
|
) {
|
||||||
|
viewModel.getCommentList(postId = postId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.totalCommentCount.observe(viewLifecycleOwner) {
|
||||||
|
binding.tvCommentCount.text = "$it"
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.commentList.observe(viewLifecycleOwner) {
|
||||||
|
if (viewModel.page - 1 == 1) {
|
||||||
|
adapter.items.clear()
|
||||||
|
binding.rvComment.scrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.items.addAll(it)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideKeyboard() {
|
||||||
|
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(creatorId: Long, postId: Long): CreatorCommunityCommentListFragment {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putLong(Constants.EXTRA_COMMUNITY_CREATOR_ID, creatorId)
|
||||||
|
args.putLong(Constants.EXTRA_COMMUNITY_POST_ID, postId)
|
||||||
|
|
||||||
|
val fragment = CreatorCommunityCommentListFragment()
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,248 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||||
|
|
||||||
|
class CreatorCommunityCommentListViewModel(
|
||||||
|
private val repository: CreatorCommunityRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private var _commentList = MutableLiveData<List<GetCommunityPostCommentListItem>>()
|
||||||
|
val commentList: LiveData<List<GetCommunityPostCommentListItem>>
|
||||||
|
get() = _commentList
|
||||||
|
|
||||||
|
private var _totalCommentCount = MutableLiveData(0)
|
||||||
|
val totalCommentCount: LiveData<Int>
|
||||||
|
get() = _totalCommentCount
|
||||||
|
|
||||||
|
var page = 1
|
||||||
|
private var isLast = false
|
||||||
|
private val size = 10
|
||||||
|
|
||||||
|
fun getCommentList(postId: Long, onFailure: (() -> Unit)? = null) {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getCommunityPostCommentList(
|
||||||
|
postId = postId,
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_totalCommentCount.postValue(it.data.totalCount)
|
||||||
|
|
||||||
|
page += 1
|
||||||
|
if (it.data.items.isNotEmpty()) {
|
||||||
|
_commentList.postValue(it.data.items)
|
||||||
|
} else {
|
||||||
|
isLast = true
|
||||||
|
_commentList.postValue(listOf())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerComment(postId: Long, comment: String, commentId: Long? = null) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.registerComment(
|
||||||
|
postId = postId,
|
||||||
|
comment = comment,
|
||||||
|
parentId = commentId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
if (it.success) {
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
if (commentId != null) {
|
||||||
|
getCommentReplyList(commentId = commentId)
|
||||||
|
} else {
|
||||||
|
getCommentList(postId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun modifyComment(
|
||||||
|
commentId: Long,
|
||||||
|
postId: Long,
|
||||||
|
parentCommentId: Long? = null,
|
||||||
|
comment: String? = null,
|
||||||
|
isActive: Boolean? = null
|
||||||
|
) {
|
||||||
|
if (comment == null && isActive == null) {
|
||||||
|
_toastLiveData.postValue("변경사항이 없습니다.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comment != null && comment.isBlank()) {
|
||||||
|
_toastLiveData.postValue("내용을 입력하세요")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val request = ModifyCommentRequest(commentId = commentId)
|
||||||
|
|
||||||
|
if (comment != null) {
|
||||||
|
request.comment = comment
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isActive != null) {
|
||||||
|
request.isActive = isActive
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.modifyComment(
|
||||||
|
request = request,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
if (it.success) {
|
||||||
|
page = 1
|
||||||
|
isLast = false
|
||||||
|
|
||||||
|
if (parentCommentId != null) {
|
||||||
|
getCommentReplyList(parentCommentId)
|
||||||
|
} else {
|
||||||
|
getCommentList(postId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCommentReplyList(commentId: Long, onFailure: (() -> Unit)? = null) {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getCommentReplyList(
|
||||||
|
commentId = commentId,
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
page += 1
|
||||||
|
if (it.data.items.isNotEmpty()) {
|
||||||
|
_commentList.postValue(it.data.items)
|
||||||
|
} else {
|
||||||
|
isLast = true
|
||||||
|
_commentList.postValue(listOf())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.viewbinding.ViewBinding
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentBinding
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemCommunityPostCommentReplyBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||||
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
|
|
||||||
|
class CreatorCommunityCommentReplyAdapter(
|
||||||
|
private val creatorId: Long,
|
||||||
|
private val modifyComment: (Long, String) -> Unit,
|
||||||
|
private val onClickDelete: (Long) -> Unit
|
||||||
|
) : RecyclerView.Adapter<CreatorCommunityCommentReplyViewHolder>() {
|
||||||
|
var items = mutableSetOf<GetCommunityPostCommentListItem>()
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): CreatorCommunityCommentReplyViewHolder {
|
||||||
|
return if (viewType == 0) {
|
||||||
|
CreatorCommunityCommentReplyHeaderViewHolder(
|
||||||
|
binding = ItemCommunityPostCommentBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CreatorCommunityCommentReplyItemViewHolder(
|
||||||
|
context = parent.context,
|
||||||
|
creatorId = creatorId,
|
||||||
|
binding = ItemCommunityPostCommentReplyBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
),
|
||||||
|
showOptionMenu = { context, view, commentId, writerId, creatorId, onClickModify ->
|
||||||
|
showOptionMenu(context, view, commentId, writerId, creatorId, onClickModify)
|
||||||
|
},
|
||||||
|
modifyComment = modifyComment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: CreatorCommunityCommentReplyViewHolder, position: Int) {
|
||||||
|
holder.bind(items.toList()[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return position
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showOptionMenu(
|
||||||
|
context: Context,
|
||||||
|
v: View,
|
||||||
|
commentId: Long,
|
||||||
|
writerId: Long,
|
||||||
|
creatorId: Long,
|
||||||
|
onClickModify: () -> Unit
|
||||||
|
) {
|
||||||
|
val popup = PopupMenu(context, v)
|
||||||
|
val inflater = popup.menuInflater
|
||||||
|
|
||||||
|
if (writerId == SharedPreferenceManager.userId) {
|
||||||
|
inflater.inflate(R.menu.content_comment_option_menu, popup.menu)
|
||||||
|
} else if (creatorId == SharedPreferenceManager.userId) {
|
||||||
|
inflater.inflate(R.menu.content_comment_option_menu2, popup.menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.setOnMenuItemClickListener {
|
||||||
|
when (it.itemId) {
|
||||||
|
R.id.menu_review_modify -> {
|
||||||
|
onClickModify()
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.menu_review_delete -> {
|
||||||
|
onClickDelete(commentId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class CreatorCommunityCommentReplyViewHolder(
|
||||||
|
binding: ViewBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
abstract fun bind(item: GetCommunityPostCommentListItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatorCommunityCommentReplyHeaderViewHolder(
|
||||||
|
private val binding: ItemCommunityPostCommentBinding
|
||||||
|
) : CreatorCommunityCommentReplyViewHolder(binding) {
|
||||||
|
override fun bind(item: GetCommunityPostCommentListItem) {
|
||||||
|
binding.ivCommentProfile.loadUrl(item.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvComment.text = item.comment
|
||||||
|
binding.tvCommentDate.text = item.date
|
||||||
|
binding.tvCommentNickname.text = item.nickname
|
||||||
|
|
||||||
|
binding.tvWriteReply.visibility = View.GONE
|
||||||
|
binding.ivMenu.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatorCommunityCommentReplyItemViewHolder(
|
||||||
|
private val context: Context,
|
||||||
|
private val creatorId: Long,
|
||||||
|
private val binding: ItemCommunityPostCommentReplyBinding,
|
||||||
|
private val showOptionMenu: (
|
||||||
|
Context, View, Long, Long, Long, onClickModify: () -> Unit
|
||||||
|
) -> Unit,
|
||||||
|
private val modifyComment: (Long, String) -> Unit
|
||||||
|
) : CreatorCommunityCommentReplyViewHolder(binding) {
|
||||||
|
override fun bind(item: GetCommunityPostCommentListItem) {
|
||||||
|
binding.ivCommentProfile.load(item.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvComment.text = item.comment
|
||||||
|
binding.tvCommentDate.text = item.date
|
||||||
|
binding.tvCommentNickname.text = item.nickname
|
||||||
|
|
||||||
|
if (
|
||||||
|
item.writerId == SharedPreferenceManager.userId ||
|
||||||
|
creatorId == SharedPreferenceManager.userId
|
||||||
|
) {
|
||||||
|
binding.etCommentModify.setText(item.comment)
|
||||||
|
binding.ivMenu.visibility = View.VISIBLE
|
||||||
|
binding.ivMenu.setOnClickListener {
|
||||||
|
showOptionMenu(
|
||||||
|
context,
|
||||||
|
binding.ivMenu,
|
||||||
|
item.id,
|
||||||
|
item.writerId,
|
||||||
|
creatorId
|
||||||
|
) {
|
||||||
|
binding.rlCommentModify.visibility = View.VISIBLE
|
||||||
|
binding.tvComment.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvModify.setOnClickListener {
|
||||||
|
binding.rlCommentModify.visibility = View.GONE
|
||||||
|
binding.tvComment.visibility = View.VISIBLE
|
||||||
|
modifyComment(item.id, binding.etCommentModify.text.toString())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.ivMenu.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Service
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.os.BundleCompat
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentCommentReplyBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostCommentListItem
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CreatorCommunityCommentReplyFragment : BaseFragment<FragmentAudioContentCommentReplyBinding>(
|
||||||
|
FragmentAudioContentCommentReplyBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: CreatorCommunityCommentListViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var imm: InputMethodManager
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var adapter: CreatorCommunityCommentReplyAdapter
|
||||||
|
|
||||||
|
private var originalComment: GetCommunityPostCommentListItem? = null
|
||||||
|
private var creatorId: Long = 0
|
||||||
|
private var postId: Long = 0
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
creatorId = arguments?.getLong(Constants.EXTRA_COMMUNITY_CREATOR_ID) ?: 0
|
||||||
|
postId = arguments?.getLong(Constants.EXTRA_COMMUNITY_POST_ID) ?: 0
|
||||||
|
originalComment = BundleCompat.getParcelable(
|
||||||
|
requireArguments(),
|
||||||
|
Constants.EXTRA_COMMUNITY_POST_COMMENT,
|
||||||
|
GetCommunityPostCommentListItem::class.java
|
||||||
|
)
|
||||||
|
return super.onCreateView(inflater, container, savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
if (originalComment == null) {
|
||||||
|
parentFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||||
|
imm = requireContext().getSystemService(
|
||||||
|
Service.INPUT_METHOD_SERVICE
|
||||||
|
) as InputMethodManager
|
||||||
|
|
||||||
|
setupView()
|
||||||
|
bindData()
|
||||||
|
viewModel.getCommentReplyList(commentId = originalComment!!.id) {
|
||||||
|
parentFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideDialog() {
|
||||||
|
(parentFragment as CreatorCommunityCommentFragment).hideCommentDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupView() {
|
||||||
|
binding.root.setOnClickListener { }
|
||||||
|
|
||||||
|
binding.tvBack.setOnClickListener {
|
||||||
|
parentFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivClose.setOnClickListener { hideDialog() }
|
||||||
|
|
||||||
|
binding.ivCommentProfile.load(SharedPreferenceManager.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivCommentSend.setOnClickListener {
|
||||||
|
hideKeyboard()
|
||||||
|
val comment = binding.etComment.text.toString()
|
||||||
|
binding.etComment.setText("")
|
||||||
|
viewModel.registerComment(postId, comment, originalComment!!.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter = CreatorCommunityCommentReplyAdapter(
|
||||||
|
creatorId = creatorId,
|
||||||
|
modifyComment = { commentId, comment ->
|
||||||
|
hideKeyboard()
|
||||||
|
viewModel.modifyComment(
|
||||||
|
commentId = commentId,
|
||||||
|
postId = postId,
|
||||||
|
parentCommentId = originalComment!!.id,
|
||||||
|
comment = comment
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickDelete = {
|
||||||
|
SodaDialog(
|
||||||
|
activity = requireActivity(),
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = "댓글 삭제",
|
||||||
|
desc = "삭제하시겠습니까?",
|
||||||
|
confirmButtonTitle = "삭제",
|
||||||
|
confirmButtonClick = {
|
||||||
|
viewModel.modifyComment(
|
||||||
|
commentId = it,
|
||||||
|
postId = postId,
|
||||||
|
parentCommentId = originalComment!!.id,
|
||||||
|
isActive = false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
cancelButtonTitle = "취소",
|
||||||
|
cancelButtonClick = {}
|
||||||
|
).show(screenWidth)
|
||||||
|
},
|
||||||
|
).apply {
|
||||||
|
items.add(originalComment!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
val recyclerView = binding.rvCommentReply
|
||||||
|
recyclerView.setHasFixedSize(true)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
activity,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
|
||||||
|
outRect.left = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.right = 13.3f.dpToPx().toInt()
|
||||||
|
|
||||||
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
|
0 -> {
|
||||||
|
outRect.top = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 12f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.itemCount - 1 -> {
|
||||||
|
outRect.top = 12f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 13.3f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.top = 12f.dpToPx().toInt()
|
||||||
|
outRect.bottom = 12f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
|
||||||
|
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
|
||||||
|
.findLastCompletelyVisibleItemPosition()
|
||||||
|
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
|
||||||
|
|
||||||
|
// 스크롤이 끝에 도달했는지 확인
|
||||||
|
if (!recyclerView.canScrollVertically(1) &&
|
||||||
|
lastVisibleItemPosition == itemTotalCount
|
||||||
|
) {
|
||||||
|
viewModel.getCommentReplyList(originalComment!!.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.commentList.observe(viewLifecycleOwner) {
|
||||||
|
if (viewModel.page - 1 == 1) {
|
||||||
|
adapter.items.clear()
|
||||||
|
binding.rvCommentReply.scrollToPosition(0)
|
||||||
|
adapter.items.add(originalComment!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.items.addAll(it)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideKeyboard() {
|
||||||
|
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(
|
||||||
|
creatorId: Long,
|
||||||
|
postId: Long,
|
||||||
|
comment: GetCommunityPostCommentListItem
|
||||||
|
): CreatorCommunityCommentReplyFragment {
|
||||||
|
val args = Bundle()
|
||||||
|
args.putLong(Constants.EXTRA_COMMUNITY_POST_ID, postId)
|
||||||
|
args.putLong(Constants.EXTRA_COMMUNITY_CREATOR_ID, creatorId)
|
||||||
|
args.putParcelable(Constants.EXTRA_COMMUNITY_POST_COMMENT, comment)
|
||||||
|
|
||||||
|
val fragment = CreatorCommunityCommentReplyFragment()
|
||||||
|
fragment.arguments = args
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,282 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||||
|
import com.gun0912.tedpermission.PermissionListener
|
||||||
|
import com.gun0912.tedpermission.normal.TedPermission
|
||||||
|
import com.jakewharton.rxbinding4.widget.textChanges
|
||||||
|
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.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.RealPathUtil
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityModifyBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModifyBinding>(
|
||||||
|
ActivityCreatorCommunityModifyBinding::inflate
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val viewModel: CreatorCommunityModifyViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
|
||||||
|
private val imageResult = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
val data = result.data
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val fileUri = data?.data
|
||||||
|
|
||||||
|
if (fileUri != null) {
|
||||||
|
binding.ivContent.background = null
|
||||||
|
binding.ivContent.load(fileUri) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||||
|
}
|
||||||
|
viewModel.imageUri = fileUri
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||||
|
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
checkPermissions()
|
||||||
|
|
||||||
|
viewModel.getRealPathFromURI = {
|
||||||
|
RealPathUtil.getRealPath(applicationContext, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
|
||||||
|
val postId = intent.getLongExtra(Constants.EXTRA_COMMUNITY_POST_ID, 0)
|
||||||
|
if (postId <= 0) {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.postId = postId
|
||||||
|
viewModel.getCommunityPostDetail(
|
||||||
|
onFailure = {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
|
||||||
|
binding.toolbar.tvBack.text = "게시글 등록"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
binding.ivPhotoPicker.setOnClickListener {
|
||||||
|
ImagePicker.with(this)
|
||||||
|
.crop()
|
||||||
|
.galleryOnly()
|
||||||
|
.galleryMimeTypes( // Exclude gif images
|
||||||
|
mimeTypes = arrayOf(
|
||||||
|
"image/png",
|
||||||
|
"image/jpg",
|
||||||
|
"image/jpeg"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.createIntent { imageResult.launch(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.isAuth) {
|
||||||
|
binding.llSetAdult.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.llSetAdult.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
|
||||||
|
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
|
||||||
|
binding.tvCancel.setOnClickListener { finish() }
|
||||||
|
binding.tvUpload.setOnClickListener {
|
||||||
|
viewModel.modifyCommunityPost {
|
||||||
|
setResult(RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPermissions() {
|
||||||
|
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
|
||||||
|
} else {
|
||||||
|
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
TedPermission.create()
|
||||||
|
.setPermissionListener(object : PermissionListener {
|
||||||
|
override fun onPermissionGranted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setDeniedMessage(R.string.read_storage_permission_denied_message)
|
||||||
|
.setPermissions(*permissions.toTypedArray())
|
||||||
|
.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun bindData() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
binding.etContent.textChanges().skip(1)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe {
|
||||||
|
binding.tvNumberOfCharacters.text = "${it.length}자"
|
||||||
|
viewModel.content = it.toString()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
viewModel.toastLiveData.observe(this) {
|
||||||
|
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.imageUrlLiveData.observe(this) {
|
||||||
|
if (!it.isNullOrBlank()) {
|
||||||
|
binding.ivContent.background = null
|
||||||
|
binding.ivContent.loadUrl(it) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.contentLiveData.observe(this) {
|
||||||
|
binding.etContent.setText(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isAvailableCommentLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.ivCommentYes.visibility = View.VISIBLE
|
||||||
|
binding.tvCommentYes.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivCommentNo.visibility = View.GONE
|
||||||
|
binding.tvCommentNo.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentNo.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivCommentNo.visibility = View.VISIBLE
|
||||||
|
binding.tvCommentNo.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivCommentYes.visibility = View.GONE
|
||||||
|
binding.tvCommentYes.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentYes
|
||||||
|
.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.isAuth) {
|
||||||
|
binding.llAgeAll.setOnClickListener {
|
||||||
|
viewModel.setAdult(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llAge19.setOnClickListener {
|
||||||
|
viewModel.setAdult(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isAdultLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.ivAgeAll.visibility = View.GONE
|
||||||
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAgeAll.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAge19.visibility = View.VISIBLE
|
||||||
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAge19.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivAge19.visibility = View.GONE
|
||||||
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAge19.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAgeAll.visibility = View.VISIBLE
|
||||||
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAgeAll.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import okio.BufferedSink
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class CreatorCommunityModifyViewModel(
|
||||||
|
private val repository: CreatorCommunityRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private val _imageUrlLiveData = MutableLiveData<String?>()
|
||||||
|
val imageUrlLiveData: LiveData<String?>
|
||||||
|
get() = _imageUrlLiveData
|
||||||
|
|
||||||
|
private val _contentLiveData = MutableLiveData("")
|
||||||
|
val contentLiveData: LiveData<String>
|
||||||
|
get() = _contentLiveData
|
||||||
|
|
||||||
|
private val _isAdultLiveData = MutableLiveData(false)
|
||||||
|
val isAdultLiveData: LiveData<Boolean>
|
||||||
|
get() = _isAdultLiveData
|
||||||
|
|
||||||
|
private val _isAvailableCommentLiveData = MutableLiveData(true)
|
||||||
|
val isAvailableCommentLiveData: LiveData<Boolean>
|
||||||
|
get() = _isAvailableCommentLiveData
|
||||||
|
|
||||||
|
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||||
|
|
||||||
|
var postId = 0L
|
||||||
|
var content = ""
|
||||||
|
var imageUri: Uri? = null
|
||||||
|
private var communityPost: GetCommunityPostListResponse? = null
|
||||||
|
|
||||||
|
fun setAdult(isAdult: Boolean) {
|
||||||
|
_isAdultLiveData.postValue(isAdult)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAvailableComment(isAvailableComment: Boolean) {
|
||||||
|
_isAvailableCommentLiveData.postValue(isAvailableComment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCommunityPostDetail(onFailure: (() -> Unit)? = null) {
|
||||||
|
communityPost = null
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getCommunityPostDetail(
|
||||||
|
postId = postId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
communityPost = it.data
|
||||||
|
_imageUrlLiveData.value = it.data.imageUrl
|
||||||
|
_contentLiveData.value = it.data.content
|
||||||
|
_isAdultLiveData.value = it.data.isAdult
|
||||||
|
_isAvailableCommentLiveData.value = it.data.isCommentAvailable
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
if (onFailure != null) {
|
||||||
|
onFailure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun modifyCommunityPost(onSuccess: () -> Unit) {
|
||||||
|
if (!_isLoading.value!! && validateData()) {
|
||||||
|
_isLoading.value = true
|
||||||
|
val request = ModifyCommunityPostRequest(
|
||||||
|
creatorCommunityId = postId,
|
||||||
|
content = if (communityPost!!.content != content) {
|
||||||
|
content
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
isCommentAvailable = if (
|
||||||
|
communityPost!!.isCommentAvailable != _isAvailableCommentLiveData.value!!
|
||||||
|
) {
|
||||||
|
_isAvailableCommentLiveData.value!!
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
isAdult = if (communityPost!!.isAdult != _isAdultLiveData.value!!) {
|
||||||
|
_isAdultLiveData.value!!
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val requestJson = Gson().toJson(request)
|
||||||
|
|
||||||
|
val postImage = if (imageUri != null) {
|
||||||
|
val file = File(getRealPathFromURI(imageUri!!))
|
||||||
|
MultipartBody.Part.createFormData(
|
||||||
|
"postImage",
|
||||||
|
file.name,
|
||||||
|
body = object : RequestBody() {
|
||||||
|
override fun contentType(): MediaType {
|
||||||
|
return "image/*".toMediaType()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeTo(sink: BufferedSink) {
|
||||||
|
file.inputStream().use { inputStream ->
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
var bytesRead: Int
|
||||||
|
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
sink.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contentLength(): Long {
|
||||||
|
return file.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.modifyCommunityPost(
|
||||||
|
postImage,
|
||||||
|
request = requestJson.toRequestBody("text/plain".toMediaType()),
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateData(): Boolean {
|
||||||
|
if (content.isBlank() || content.length < 5) {
|
||||||
|
_toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class ModifyCommunityPostRequest(
|
||||||
|
@SerializedName("creatorCommunityId") val creatorCommunityId: Long,
|
||||||
|
@SerializedName("content") val content: String? = null,
|
||||||
|
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean? = null,
|
||||||
|
@SerializedName("isAdult") val isAdult: Boolean? = null,
|
||||||
|
@SerializedName("isActive") val isActive: Boolean? = null
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class CreateCommunityPostRequest(
|
||||||
|
@SerializedName("content") val content: String,
|
||||||
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
|
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean
|
||||||
|
)
|
|
@ -0,0 +1,248 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import com.github.dhaval2404.imagepicker.ImagePicker
|
||||||
|
import com.gun0912.tedpermission.PermissionListener
|
||||||
|
import com.gun0912.tedpermission.normal.TedPermission
|
||||||
|
import com.jakewharton.rxbinding4.widget.textChanges
|
||||||
|
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.RealPathUtil
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityCreatorCommunityWriteBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CreatorCommunityWriteActivity : BaseActivity<ActivityCreatorCommunityWriteBinding>(
|
||||||
|
ActivityCreatorCommunityWriteBinding::inflate
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val viewModel: CreatorCommunityWriteViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
|
||||||
|
private val imageResult = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
val data = result.data
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
val fileUri = data?.data
|
||||||
|
|
||||||
|
if (fileUri != null) {
|
||||||
|
binding.ivContent.background = null
|
||||||
|
binding.ivContent.load(fileUri) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(8f.dpToPx()))
|
||||||
|
}
|
||||||
|
viewModel.imageUri = fileUri
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
"잘못된 파일입니다.\n다시 선택해 주세요.",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
} else if (resultCode == ImagePicker.RESULT_ERROR) {
|
||||||
|
Toast.makeText(this, ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
checkPermissions()
|
||||||
|
|
||||||
|
viewModel.getRealPathFromURI = {
|
||||||
|
RealPathUtil.getRealPath(applicationContext, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
|
||||||
|
binding.toolbar.tvBack.text = "게시글 등록"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
binding.ivPhotoPicker.setOnClickListener {
|
||||||
|
ImagePicker.with(this)
|
||||||
|
.crop()
|
||||||
|
.galleryOnly()
|
||||||
|
.galleryMimeTypes( // Exclude gif images
|
||||||
|
mimeTypes = arrayOf(
|
||||||
|
"image/png",
|
||||||
|
"image/jpg",
|
||||||
|
"image/jpeg"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.createIntent { imageResult.launch(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.isAuth) {
|
||||||
|
binding.llSetAdult.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.llSetAdult.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
|
||||||
|
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
|
||||||
|
binding.tvCancel.setOnClickListener { finish() }
|
||||||
|
binding.tvUpload.setOnClickListener {
|
||||||
|
viewModel.createCommunityPost { finish() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPermissions() {
|
||||||
|
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
listOf(Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
|
||||||
|
} else {
|
||||||
|
listOf(Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
}
|
||||||
|
|
||||||
|
TedPermission.create()
|
||||||
|
.setPermissionListener(object : PermissionListener {
|
||||||
|
override fun onPermissionGranted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionDenied(deniedPermissions: MutableList<String>?) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setDeniedMessage(R.string.read_storage_permission_denied_message)
|
||||||
|
.setPermissions(*permissions.toTypedArray())
|
||||||
|
.check()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun bindData() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
binding.etContent.textChanges().skip(1)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe {
|
||||||
|
binding.tvNumberOfCharacters.text = "${it.length}자"
|
||||||
|
viewModel.content = it.toString()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
viewModel.toastLiveData.observe(this) {
|
||||||
|
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isAvailableCommentLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.ivCommentYes.visibility = View.VISIBLE
|
||||||
|
binding.tvCommentYes.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivCommentNo.visibility = View.GONE
|
||||||
|
binding.tvCommentNo.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentNo.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivCommentNo.visibility = View.VISIBLE
|
||||||
|
binding.tvCommentNo.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
|
binding.ivCommentYes.visibility = View.GONE
|
||||||
|
binding.tvCommentYes.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.llCommentYes
|
||||||
|
.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.isAuth) {
|
||||||
|
binding.llAgeAll.setOnClickListener {
|
||||||
|
viewModel.setAdult(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llAge19.setOnClickListener {
|
||||||
|
viewModel.setAdult(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isAdultLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.ivAgeAll.visibility = View.GONE
|
||||||
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAgeAll.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAge19.visibility = View.VISIBLE
|
||||||
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAge19.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivAge19.visibility = View.GONE
|
||||||
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAge19.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_80d8ff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAgeAll.visibility = View.VISIBLE
|
||||||
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAgeAll.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creator_community.write
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import okio.BufferedSink
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class CreatorCommunityWriteViewModel(private val repository: CreatorCommunityRepository
|
||||||
|
): BaseViewModel() {
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private val _isAdultLiveData = MutableLiveData(false)
|
||||||
|
val isAdultLiveData: LiveData<Boolean>
|
||||||
|
get() = _isAdultLiveData
|
||||||
|
|
||||||
|
private val _isAvailableCommentLiveData = MutableLiveData(true)
|
||||||
|
val isAvailableCommentLiveData: LiveData<Boolean>
|
||||||
|
get() = _isAvailableCommentLiveData
|
||||||
|
|
||||||
|
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||||
|
|
||||||
|
var content = ""
|
||||||
|
var imageUri: Uri? = null
|
||||||
|
|
||||||
|
fun setAdult(isAdult: Boolean) {
|
||||||
|
_isAdultLiveData.postValue(isAdult)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAvailableComment(isAvailableComment: Boolean) {
|
||||||
|
_isAvailableCommentLiveData.postValue(isAvailableComment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createCommunityPost(onSuccess: () -> Unit) {
|
||||||
|
if (!_isLoading.value!! && validateData()) {
|
||||||
|
_isLoading.postValue(true)
|
||||||
|
|
||||||
|
val request = CreateCommunityPostRequest(
|
||||||
|
content = content,
|
||||||
|
isAdult = _isAdultLiveData.value!!,
|
||||||
|
isCommentAvailable = _isAvailableCommentLiveData.value!!
|
||||||
|
)
|
||||||
|
|
||||||
|
val requestJson = Gson().toJson(request)
|
||||||
|
|
||||||
|
val postImage = if (imageUri != null) {
|
||||||
|
val file = File(getRealPathFromURI(imageUri!!))
|
||||||
|
MultipartBody.Part.createFormData(
|
||||||
|
"postImage",
|
||||||
|
file.name,
|
||||||
|
body = object : RequestBody() {
|
||||||
|
override fun contentType(): MediaType {
|
||||||
|
return "image/*".toMediaType()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeTo(sink: BufferedSink) {
|
||||||
|
file.inputStream().use { inputStream ->
|
||||||
|
val buffer = ByteArray(1024)
|
||||||
|
var bytesRead: Int
|
||||||
|
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
|
sink.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun contentLength(): Long {
|
||||||
|
return file.length()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.createCommunityPost(
|
||||||
|
postImage = postImage,
|
||||||
|
request = requestJson.toRequestBody("text/plain".toMediaType()),
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isLoading.postValue(false)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.postValue(false)
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateData(): Boolean {
|
||||||
|
if (content.isBlank() || content.length < 5) {
|
||||||
|
_toastLiveData.postValue("내용을 5자 이상 입력해 주세요.")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package kr.co.vividnext.sodalive.extensions
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
|
import coil.load
|
||||||
|
import coil.request.ImageRequest
|
||||||
|
import kr.co.vividnext.sodalive.common.ImageLoaderProvider
|
||||||
|
import kr.co.vividnext.sodalive.common.ImageLoaderProvider.imageLoader
|
||||||
|
|
||||||
|
fun ImageView.loadUrl(url: String?, builder: ImageRequest.Builder.() -> Unit = {}) {
|
||||||
|
if (!ImageLoaderProvider.isInitialized) {
|
||||||
|
throw IllegalStateException("ImageLoaderProvider is not initialized")
|
||||||
|
}
|
||||||
|
this.load(url, imageLoader, builder)
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ data class GetRoomListResponse(
|
||||||
@SerializedName("price") val price: Int,
|
@SerializedName("price") val price: Int,
|
||||||
@SerializedName("tags") val tags: List<String>,
|
@SerializedName("tags") val tags: List<String>,
|
||||||
@SerializedName("channelName") val channelName: String?,
|
@SerializedName("channelName") val channelName: String?,
|
||||||
|
@SerializedName("creatorProfileImage") val creatorProfileImage: String,
|
||||||
@SerializedName("creatorNickname") val creatorNickname: String,
|
@SerializedName("creatorNickname") val creatorNickname: String,
|
||||||
@SerializedName("creatorId") val creatorId: Long,
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
@SerializedName("isReservation") val isReservation: Boolean,
|
@SerializedName("isReservation") val isReservation: Boolean,
|
||||||
|
|
|
@ -27,6 +27,8 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentLiveBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentLiveBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityAdapter
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.following.FollowingCreatorActivity
|
import kr.co.vividnext.sodalive.following.FollowingCreatorActivity
|
||||||
|
@ -49,6 +51,9 @@ import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditActivity
|
||||||
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
||||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::inflate) {
|
class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::inflate) {
|
||||||
|
@ -56,6 +61,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
|
|
||||||
private lateinit var liveNowAdapter: LiveNowAdapter
|
private lateinit var liveNowAdapter: LiveNowAdapter
|
||||||
private lateinit var liveReservationAdapter: LiveReservationAdapter
|
private lateinit var liveReservationAdapter: LiveReservationAdapter
|
||||||
|
private lateinit var creatorCommunityAdapter: CreatorCommunityAdapter
|
||||||
private lateinit var liveRecommendChannelAdapter: LiveRecommendChannelAdapter
|
private lateinit var liveRecommendChannelAdapter: LiveRecommendChannelAdapter
|
||||||
|
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
@ -91,6 +97,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
setupLiveNow()
|
setupLiveNow()
|
||||||
setupLiveReservation()
|
setupLiveReservation()
|
||||||
setupEvent()
|
setupEvent()
|
||||||
|
setupCommunityPost()
|
||||||
|
|
||||||
message = "라이브를 불러오고 있습니다."
|
message = "라이브를 불러오고 있습니다."
|
||||||
viewModel.getSummary()
|
viewModel.getSummary()
|
||||||
|
@ -494,6 +501,68 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun setupCommunityPost() {
|
||||||
|
val recyclerView = binding.rvCommunityPost
|
||||||
|
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
requireContext(),
|
||||||
|
LinearLayoutManager.HORIZONTAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
|
||||||
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
|
0 -> {
|
||||||
|
outRect.left = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.right = 5.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
liveNowAdapter.itemCount - 1 -> {
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 13.3f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
creatorCommunityAdapter = CreatorCommunityAdapter {
|
||||||
|
startActivity(
|
||||||
|
Intent(
|
||||||
|
requireActivity(),
|
||||||
|
CreatorCommunityAllActivity::class.java
|
||||||
|
).apply {
|
||||||
|
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.rvCommunityPost.adapter = creatorCommunityAdapter
|
||||||
|
|
||||||
|
viewModel.communityPostItemLiveData.observe(viewLifecycleOwner) {
|
||||||
|
if (it.isNotEmpty()) {
|
||||||
|
binding.rvCommunityPost.visibility = View.VISIBLE
|
||||||
|
creatorCommunityAdapter.items.clear()
|
||||||
|
creatorCommunityAdapter.items.addAll(it)
|
||||||
|
creatorCommunityAdapter.notifyDataSetChanged()
|
||||||
|
} else {
|
||||||
|
binding.rvCommunityPost.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun startLive(roomId: Long) {
|
private fun startLive(roomId: Long) {
|
||||||
val onEnterRoomSuccess = {
|
val onEnterRoomSuccess = {
|
||||||
viewModel.getSummary()
|
viewModel.getSummary()
|
||||||
|
@ -629,6 +698,15 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
val beginDateFormat = SimpleDateFormat("yyyy.MM.dd EEE hh:mm a", Locale.ENGLISH)
|
||||||
|
val beginDate = beginDateFormat.parse(it.beginDateTime)!!
|
||||||
|
val now = Date()
|
||||||
|
|
||||||
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd, HH:mm", Locale.getDefault())
|
||||||
|
val diffTime: Long = now.time - beginDate.time
|
||||||
|
val hours = (diffTime / (1000 * 60 * 60)).toInt()
|
||||||
|
val mins = (diffTime / (1000 * 60)).toInt() % 60
|
||||||
|
|
||||||
if (it.isPrivateRoom) {
|
if (it.isPrivateRoom) {
|
||||||
LiveRoomPasswordDialog(
|
LiveRoomPasswordDialog(
|
||||||
activity = requireActivity(),
|
activity = requireActivity(),
|
||||||
|
@ -648,8 +726,23 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
LivePaymentDialog(
|
LivePaymentDialog(
|
||||||
activity = requireActivity(),
|
activity = requireActivity(),
|
||||||
layoutInflater = layoutInflater,
|
layoutInflater = layoutInflater,
|
||||||
title = "${it.price.moneyFormat()}캔으로 입장",
|
title = "유료 라이브 입장",
|
||||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
startDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(beginDate)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
nowDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(now)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
desc = "${it.price}캔을 차감하고\n라이브에 입장 하시겠습니까?",
|
||||||
|
desc2 = if (hours >= 1) {
|
||||||
|
"라이브를 시작한 지 ${hours}시간 ${mins}분이 지났습니다. 라이브에 입장 후 30분 이내에 라이브가 종료될 수도 있습니다."
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
confirmButtonTitle = "결제 후 입장",
|
confirmButtonTitle = "결제 후 입장",
|
||||||
confirmButtonClick = {
|
confirmButtonClick = {
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
|
|
|
@ -8,6 +8,8 @@ import io.reactivex.rxjava3.core.Flowable
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
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.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
|
import kr.co.vividnext.sodalive.live.recommend.GetRecommendLiveResponse
|
||||||
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
|
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
|
||||||
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
|
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
|
||||||
|
@ -24,7 +26,8 @@ import kr.co.vividnext.sodalive.settings.event.EventRepository
|
||||||
class LiveViewModel(
|
class LiveViewModel(
|
||||||
private val repository: LiveRepository,
|
private val repository: LiveRepository,
|
||||||
private val eventRepository: EventRepository,
|
private val eventRepository: EventRepository,
|
||||||
private val liveRecommendRepository: LiveRecommendRepository
|
private val liveRecommendRepository: LiveRecommendRepository,
|
||||||
|
private val creatorCommunityRepository: CreatorCommunityRepository
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
private var _isLoading = MutableLiveData(false)
|
private var _isLoading = MutableLiveData(false)
|
||||||
val isLoading: LiveData<Boolean>
|
val isLoading: LiveData<Boolean>
|
||||||
|
@ -60,6 +63,10 @@ class LiveViewModel(
|
||||||
val eventLiveData: LiveData<List<EventItem>>
|
val eventLiveData: LiveData<List<EventItem>>
|
||||||
get() = _eventLiveData
|
get() = _eventLiveData
|
||||||
|
|
||||||
|
private val _communityPostItemLiveData = MutableLiveData<List<GetCommunityPostListResponse>>()
|
||||||
|
val communityPostItemLiveData: LiveData<List<GetCommunityPostListResponse>>
|
||||||
|
get() = _communityPostItemLiveData
|
||||||
|
|
||||||
var page = 1
|
var page = 1
|
||||||
var isLast = false
|
var isLast = false
|
||||||
private val pageSize = 10
|
private val pageSize = 10
|
||||||
|
@ -135,6 +142,36 @@ class LiveViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getLatestPostListFromCreatorsYouFollow() {
|
||||||
|
compositeDisposable.add(
|
||||||
|
creatorCommunityRepository.getLatestPostListFromCreatorsYouFollow(
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_communityPostItemLiveData.postValue(it.data!!)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun getSummary() {
|
fun getSummary() {
|
||||||
if (!_isLoading.value!!) {
|
if (!_isLoading.value!!) {
|
||||||
if (_isFollowedCreatorLive.value!!) {
|
if (_isFollowedCreatorLive.value!!) {
|
||||||
|
@ -142,6 +179,7 @@ class LiveViewModel(
|
||||||
} else {
|
} else {
|
||||||
getRecommendChannelList()
|
getRecommendChannelList()
|
||||||
}
|
}
|
||||||
|
getLatestPostListFromCreatorsYouFollow()
|
||||||
|
|
||||||
val liveNow = repository.roomList(
|
val liveNow = repository.roomList(
|
||||||
status = LiveRoomStatus.NOW,
|
status = LiveRoomStatus.NOW,
|
||||||
|
|
|
@ -5,11 +5,12 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.transform.CircleCropTransformation
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemLiveNowBinding
|
import kr.co.vividnext.sodalive.databinding.ItemLiveNowBinding
|
||||||
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.live.GetRoomListResponse
|
import kr.co.vividnext.sodalive.live.GetRoomListResponse
|
||||||
|
|
||||||
class LiveNowAdapter(
|
class LiveNowAdapter(
|
||||||
|
@ -23,13 +24,11 @@ class LiveNowAdapter(
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
fun bind(item: GetRoomListResponse) {
|
fun bind(item: GetRoomListResponse) {
|
||||||
binding.ivCover.load(item.coverImageUrl) {
|
binding.ivCover.loadUrl(item.coverImageUrl) {
|
||||||
crossfade(true)
|
crossfade(true)
|
||||||
placeholder(R.drawable.ic_place_holder)
|
placeholder(R.drawable.ic_place_holder)
|
||||||
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
|
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
|
||||||
}
|
}
|
||||||
binding.tvManager.text = item.creatorNickname
|
|
||||||
binding.tvNumberOfMembers.text = "${item.numberOfParticipate}"
|
|
||||||
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,6 +43,21 @@ class LiveNowAdapter(
|
||||||
binding.tvPrice.setBackgroundResource(R.drawable.bg_round_corner_10_643bc8)
|
binding.tvPrice.setBackgroundResource(R.drawable.bg_round_corner_10_643bc8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.tags.isNotEmpty()) {
|
||||||
|
binding.tvTags.visibility = View.VISIBLE
|
||||||
|
binding.tvTags.text = item.tags.joinToString(" ") { "#$it" }
|
||||||
|
} else {
|
||||||
|
binding.tvTags.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvTitle.text = item.title
|
||||||
|
binding.tvNickname.text = item.creatorNickname
|
||||||
|
binding.ivProfile.loadUrl(item.creatorProfileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
binding.root.setOnClickListener { onClick(item) }
|
binding.root.setOnClickListener { onClick(item) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@ import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
|
||||||
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
||||||
ActivityLiveNowAllBinding::inflate
|
ActivityLiveNowAllBinding::inflate
|
||||||
|
@ -157,6 +160,15 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
||||||
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
val beginDateFormat = SimpleDateFormat("yyyy.MM.dd EEE hh:mm a", Locale.ENGLISH)
|
||||||
|
val beginDate = beginDateFormat.parse(it.beginDateTime)!!
|
||||||
|
val now = Date()
|
||||||
|
|
||||||
|
val dateFormat = SimpleDateFormat("yyyy-MM-dd, HH:mm", Locale.getDefault())
|
||||||
|
val diffTime: Long = now.time - beginDate.time
|
||||||
|
val hours = (diffTime / (1000 * 60 * 60)).toInt()
|
||||||
|
val mins = (diffTime / (1000 * 60)).toInt() % 60
|
||||||
|
|
||||||
if (it.isPrivateRoom) {
|
if (it.isPrivateRoom) {
|
||||||
LiveRoomPasswordDialog(
|
LiveRoomPasswordDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
|
@ -174,8 +186,23 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
||||||
LivePaymentDialog(
|
LivePaymentDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
layoutInflater = layoutInflater,
|
layoutInflater = layoutInflater,
|
||||||
title = "${it.price.moneyFormat()} 캔으로 입장",
|
title = "유료 라이브 입장",
|
||||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
startDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(beginDate)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
nowDateTime = if (hours >= 1) {
|
||||||
|
dateFormat.format(now)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
desc = "${it.price.moneyFormat()}캔을 차감하고\n라이브에 입장 하시겠습니까?",
|
||||||
|
desc2 = if (hours >= 1) {
|
||||||
|
"라이브를 시작한 지 ${hours}시간 ${mins}분이 지났습니다. 라이브에 입장 후 30분 이내에 라이브가 종료될 수도 있습니다."
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
confirmButtonTitle = "결제 후 입장",
|
confirmButtonTitle = "결제 후 입장",
|
||||||
confirmButtonClick = {
|
confirmButtonClick = {
|
||||||
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||||
|
|
|
@ -34,8 +34,6 @@ class LiveNowAllAdapter(
|
||||||
}
|
}
|
||||||
binding.tvNickname.text = item.creatorNickname
|
binding.tvNickname.text = item.creatorNickname
|
||||||
binding.tvTitle.text = item.title
|
binding.tvTitle.text = item.title
|
||||||
binding.tvTotal.text = "/${item.numberOfPeople}"
|
|
||||||
binding.tvNumberOfParticipants.text = item.numberOfParticipate.toString()
|
|
||||||
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
||||||
View.VISIBLE
|
View.VISIBLE
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +45,7 @@ class LiveNowAllAdapter(
|
||||||
binding.tvAvailableParticipate.setTextColor(
|
binding.tvAvailableParticipate.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,8 +26,8 @@ import android.widget.Toast
|
||||||
import androidx.activity.OnBackPressedCallback
|
import androidx.activity.OnBackPressedCallback
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.load
|
||||||
|
@ -55,6 +55,7 @@ import kr.co.vividnext.sodalive.common.SodaLiveService
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityLiveRoomBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityLiveRoomBinding
|
||||||
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
||||||
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.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomChatAdapter
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomChatAdapter
|
||||||
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomChatRawMessage
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomChatRawMessage
|
||||||
|
@ -63,6 +64,7 @@ import kr.co.vividnext.sodalive.live.room.chat.LiveRoomDonationChat
|
||||||
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomDonationStatusChat
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomDonationStatusChat
|
||||||
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomJoinChat
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomJoinChat
|
||||||
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomNormalChat
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomNormalChat
|
||||||
|
import kr.co.vividnext.sodalive.live.room.chat.LiveRoomRouletteDonationChat
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageDialog
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
|
||||||
|
@ -72,6 +74,9 @@ import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileListAdapter
|
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileListAdapter
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomUserProfileDialog
|
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomUserProfileDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.update.LiveRoomInfoEditDialog
|
import kr.co.vividnext.sodalive.live.room.update.LiveRoomInfoEditDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteSpinDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
||||||
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
|
||||||
|
@ -106,7 +111,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
private var isSpeakerMute = false
|
private var isSpeakerMute = false
|
||||||
private var isMicrophoneMute = false
|
private var isMicrophoneMute = false
|
||||||
private var isSpeaker = false
|
private var isSpeaker = false
|
||||||
private var isSpeakerFold = false
|
|
||||||
|
|
||||||
private var isNoChatting = false
|
private var isNoChatting = false
|
||||||
private var remainingNoChattingTime = noChattingTime
|
private var remainingNoChattingTime = noChattingTime
|
||||||
|
@ -179,6 +183,27 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val rouletteConfigResult = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
val resultCode = result.resultCode
|
||||||
|
val isActiveRoulette = result.data?.getBooleanExtra(Constants.EXTRA_RESULT_ROULETTE, false)
|
||||||
|
|
||||||
|
if (resultCode == RESULT_OK && isActiveRoulette != null) {
|
||||||
|
agora.sendRawMessageToGroup(
|
||||||
|
rawMessage = Gson().toJson(
|
||||||
|
LiveRoomChatRawMessage(
|
||||||
|
type = LiveRoomChatRawMessageType.TOGGLE_ROULETTE,
|
||||||
|
message = "",
|
||||||
|
can = 0,
|
||||||
|
donationMessage = "",
|
||||||
|
isActiveRoulette = isActiveRoulette
|
||||||
|
)
|
||||||
|
).toByteArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
agora = Agora(
|
agora = Agora(
|
||||||
context = this,
|
context = this,
|
||||||
|
@ -328,8 +353,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
isStaff = {
|
isStaff = {
|
||||||
viewModel.isEqualToManagerId(it.toInt())
|
viewModel.isEqualToManagerId(it.toInt())
|
||||||
},
|
},
|
||||||
onClickSendMessage = { userId, nickname ->
|
|
||||||
},
|
|
||||||
onClickSetManager = {
|
onClickSetManager = {
|
||||||
setManagerMessageToPeer(userId = it)
|
setManagerMessageToPeer(userId = it)
|
||||||
viewModel.setManager(roomId = roomId, userId = it) {
|
viewModel.setManager(roomId = roomId, userId = it) {
|
||||||
|
@ -430,33 +453,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
|
|
||||||
dialog.show(screenWidth)
|
dialog.show(screenWidth)
|
||||||
}
|
}
|
||||||
binding.ivNotification.setOnClickListener { viewModel.toggleShowNotice() }
|
binding.tvNotification.setOnClickListener { viewModel.toggleShowNotice() }
|
||||||
binding.rlNotice.setOnClickListener { viewModel.toggleExpandNotice() }
|
|
||||||
binding.tvSpeakerFold.setOnClickListener {
|
|
||||||
isSpeakerFold = !isSpeakerFold
|
|
||||||
|
|
||||||
if (isSpeakerFold) {
|
|
||||||
binding.rlSpeaker.visibility = View.VISIBLE
|
|
||||||
binding.rvSpeakers.visibility = View.VISIBLE
|
|
||||||
binding.tvSpeakerFold.text = "접기"
|
|
||||||
binding.tvSpeakerFold.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
R.drawable.ic_live_detail_top,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
binding.rlSpeaker.visibility = View.GONE
|
|
||||||
binding.rvSpeakers.visibility = View.GONE
|
|
||||||
binding.tvSpeakerFold.text = "펼치기"
|
|
||||||
binding.tvSpeakerFold.setCompoundDrawablesWithIntrinsicBounds(
|
|
||||||
R.drawable.ic_live_detail_bottom,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
||||||
binding.llDonation.setOnClickListener {
|
binding.llDonation.setOnClickListener {
|
||||||
|
@ -551,7 +548,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
dialog.setPositiveButton("차단") { _, _ ->
|
dialog.setPositiveButton("차단") { _, _ ->
|
||||||
roomUserProfileDialog.dismiss()
|
roomUserProfileDialog.dismiss()
|
||||||
viewModel.memberBlock(userId) {
|
viewModel.memberBlock(userId) {
|
||||||
kickOut(userId)
|
if (viewModel.roomInfoResponse.creatorId == SharedPreferenceManager.userId) {
|
||||||
|
kickOut(userId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialog.setNegativeButton("취소") { _, _ -> }
|
dialog.setNegativeButton("취소") { _, _ -> }
|
||||||
|
@ -596,11 +595,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
binding.tvBgSwitch.setTextColor(
|
binding.tvBgSwitch.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.tvBgSwitch
|
binding.tvBgSwitch
|
||||||
.setBackgroundResource(R.drawable.bg_round_corner_13_3_transparent_9970ff)
|
.setBackgroundResource(R.drawable.bg_round_corner_5_3_transparent_3bb9f1)
|
||||||
} else {
|
} else {
|
||||||
binding.ivCover.visibility = View.GONE
|
binding.ivCover.visibility = View.GONE
|
||||||
binding.tvBgSwitch.text = "배경 OFF"
|
binding.tvBgSwitch.text = "배경 OFF"
|
||||||
|
@ -611,7 +610,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.tvBgSwitch
|
binding.tvBgSwitch
|
||||||
.setBackgroundResource(R.drawable.bg_round_corner_13_3_transparent_bbbbbb)
|
.setBackgroundResource(R.drawable.bg_round_corner_5_3_transparent_bbbbbb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,10 +646,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvTitle.text = response.title
|
binding.tvTitle.text = response.title
|
||||||
binding.ivCover.load(response.coverImageUrl) {
|
|
||||||
crossfade(true)
|
|
||||||
placeholder(R.drawable.ic_place_holder)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.flDonation.visibility =
|
binding.flDonation.visibility =
|
||||||
if (response.creatorId != SharedPreferenceManager.userId) {
|
if (response.creatorId != SharedPreferenceManager.userId) {
|
||||||
|
@ -693,7 +688,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
|
|
||||||
speakerListAdapter.managerId = response.creatorId
|
speakerListAdapter.managerId = response.creatorId
|
||||||
speakerListAdapter.updateList(response.speakerList)
|
speakerListAdapter.updateList(
|
||||||
|
response.speakerList.filter {
|
||||||
|
it.id != response.creatorId
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
if (response.creatorId == SharedPreferenceManager.userId) {
|
if (response.creatorId == SharedPreferenceManager.userId) {
|
||||||
binding.ivEdit.setOnClickListener {
|
binding.ivEdit.setOnClickListener {
|
||||||
|
@ -710,10 +709,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
setNoticeAndClickableUrl(binding.tvNotice, newContent)
|
setNoticeAndClickableUrl(binding.tvNotice, newContent)
|
||||||
|
|
||||||
if (newCoverImageUri != null) {
|
if (newCoverImageUri != null) {
|
||||||
binding.ivCover.load(newCoverImageUri) {
|
binding.ivCover.load(newCoverImageUri)
|
||||||
crossfade(true)
|
|
||||||
placeholder(R.drawable.ic_place_holder)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
agora.sendRawMessageToGroup(
|
agora.sendRawMessageToGroup(
|
||||||
|
@ -770,7 +766,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
setNoticeAndClickableUrl(binding.tvNotice, response.notice)
|
setNoticeAndClickableUrl(binding.tvNotice, response.notice)
|
||||||
|
|
||||||
binding.tvCreatorNickname.text = response.creatorNickname
|
binding.tvCreatorNickname.text = response.creatorNickname
|
||||||
binding.ivCreatorProfile.load(response.creatorProfileUrl) {
|
binding.ivCreatorProfile.loadUrl(response.creatorProfileUrl) {
|
||||||
crossfade(true)
|
crossfade(true)
|
||||||
placeholder(R.drawable.ic_place_holder)
|
placeholder(R.drawable.ic_place_holder)
|
||||||
transformations(CircleCropTransformation())
|
transformations(CircleCropTransformation())
|
||||||
|
@ -785,7 +781,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
if (response.creatorId != SharedPreferenceManager.userId) {
|
if (response.creatorId != SharedPreferenceManager.userId) {
|
||||||
binding.ivCreatorFollow.visibility = View.VISIBLE
|
binding.ivCreatorFollow.visibility = View.VISIBLE
|
||||||
if (response.isFollowing) {
|
if (response.isFollowing) {
|
||||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_following)
|
binding.ivCreatorFollow.setImageResource(R.drawable.btn_select_checked)
|
||||||
binding.ivCreatorFollow.setOnClickListener {
|
binding.ivCreatorFollow.setOnClickListener {
|
||||||
viewModel.creatorUnFollow(
|
viewModel.creatorUnFollow(
|
||||||
creatorId = response.creatorId,
|
creatorId = response.creatorId,
|
||||||
|
@ -793,7 +789,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_follow)
|
binding.ivCreatorFollow.setImageResource(R.drawable.btn_plus_round)
|
||||||
binding.ivCreatorFollow.setOnClickListener {
|
binding.ivCreatorFollow.setOnClickListener {
|
||||||
viewModel.creatorFollow(
|
viewModel.creatorFollow(
|
||||||
creatorId = response.creatorId,
|
creatorId = response.creatorId,
|
||||||
|
@ -805,6 +801,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
binding.ivCreatorFollow.visibility = View.GONE
|
binding.ivCreatorFollow.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initRouletteSettingButton(isHost = response.creatorId == SharedPreferenceManager.userId)
|
||||||
|
activatingRouletteButton(
|
||||||
|
isHost = response.creatorId == SharedPreferenceManager.userId,
|
||||||
|
isActiveRoulette = response.isActiveRoulette
|
||||||
|
)
|
||||||
|
|
||||||
if (agora.rtmChannelIsNull()) {
|
if (agora.rtmChannelIsNull()) {
|
||||||
joinChannel(response)
|
joinChannel(response)
|
||||||
}
|
}
|
||||||
|
@ -812,25 +814,74 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
|
|
||||||
viewModel.isShowNotice.observe(this) {
|
viewModel.isShowNotice.observe(this) {
|
||||||
if (it) {
|
if (it) {
|
||||||
binding.ivNotification.setImageResource(R.drawable.ic_notice_selected)
|
binding.tvNotification.setTextColor(
|
||||||
binding.rlNotice.visibility = View.VISIBLE
|
ContextCompat.getColor(
|
||||||
} else {
|
applicationContext,
|
||||||
binding.ivNotification.setImageResource(R.drawable.ic_notice_normal)
|
R.color.color_3bb9f1
|
||||||
binding.rlNotice.visibility = View.GONE
|
)
|
||||||
}
|
)
|
||||||
}
|
binding.tvNotification.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_5_3_transparent_3bb9f1
|
||||||
|
)
|
||||||
|
|
||||||
viewModel.isExpandNotice.observe(this) {
|
binding.llNotice.visibility = View.VISIBLE
|
||||||
binding.tvNotice.maxLines = if (it) {
|
|
||||||
Int.MAX_VALUE
|
|
||||||
} else {
|
} else {
|
||||||
1
|
binding.tvNotification.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_bbbbbb
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.tvNotification.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_5_3_transparent_bbbbbb
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.llNotice.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.totalDonationCan.observe(this) {
|
viewModel.totalDonationCan.observe(this) {
|
||||||
binding.tvTotalCan.text = it.moneyFormat()
|
binding.tvTotalCan.text = it.moneyFormat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.coverImageUrlLiveData.observe(this) {
|
||||||
|
binding.ivCover.loadUrl(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initRouletteSettingButton(isHost: Boolean) {
|
||||||
|
if (isHost) {
|
||||||
|
binding.flRouletteSettings.visibility = View.VISIBLE
|
||||||
|
binding.flRouletteSettings.setOnClickListener {
|
||||||
|
rouletteConfigResult.launch(
|
||||||
|
Intent(
|
||||||
|
applicationContext,
|
||||||
|
RouletteConfigActivity::class.java
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binding.flRouletteSettings.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun activatingRouletteButton(isHost: Boolean, isActiveRoulette: Boolean) {
|
||||||
|
if (!isHost && isActiveRoulette) {
|
||||||
|
binding.flRoulette.visibility = View.VISIBLE
|
||||||
|
binding.flRoulette.setOnClickListener {
|
||||||
|
viewModel.showRoulette {
|
||||||
|
RoulettePreviewDialog(
|
||||||
|
activity = this,
|
||||||
|
preview = it,
|
||||||
|
onClickSpin = { spinRoulette() },
|
||||||
|
layoutInflater = layoutInflater
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
binding.flRoulette.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setNoticeAndClickableUrl(textView: TextView, text: String) {
|
private fun setNoticeAndClickableUrl(textView: TextView, text: String) {
|
||||||
|
@ -937,7 +988,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
val rvSpeakers = binding.rvSpeakers
|
val rvSpeakers = binding.rvSpeakers
|
||||||
speakerListAdapter = LiveRoomProfileListAdapter()
|
speakerListAdapter = LiveRoomProfileListAdapter()
|
||||||
|
|
||||||
rvSpeakers.layoutManager = GridLayoutManager(applicationContext, 5)
|
rvSpeakers.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.HORIZONTAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
rvSpeakers.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
rvSpeakers.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
override fun getItemOffsets(
|
override fun getItemOffsets(
|
||||||
outRect: Rect,
|
outRect: Rect,
|
||||||
|
@ -947,8 +1002,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
) {
|
) {
|
||||||
super.getItemOffsets(outRect, view, parent, state)
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
|
||||||
outRect.top = 5f.dpToPx().toInt()
|
outRect.left = 4f.dpToPx().toInt()
|
||||||
outRect.bottom = 5f.dpToPx().toInt()
|
outRect.right = 4f.dpToPx().toInt()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
rvSpeakers.adapter = speakerListAdapter
|
rvSpeakers.adapter = speakerListAdapter
|
||||||
|
@ -1090,10 +1145,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
isMicrophoneMute = !isMicrophoneMute
|
isMicrophoneMute = !isMicrophoneMute
|
||||||
agora.muteLocalAudioStream(isMicrophoneMute)
|
agora.muteLocalAudioStream(isMicrophoneMute)
|
||||||
|
|
||||||
if (isMicrophoneMute) {
|
if (SharedPreferenceManager.userId == viewModel.roomInfoResponse.creatorId) {
|
||||||
speakerListAdapter.muteSpeakers.add(SharedPreferenceManager.userId.toInt())
|
setMuteSpeakerCreator(isMicrophoneMute)
|
||||||
} else {
|
} else {
|
||||||
speakerListAdapter.muteSpeakers.remove(SharedPreferenceManager.userId.toInt())
|
if (isMicrophoneMute) {
|
||||||
|
speakerListAdapter.muteSpeakers.add(SharedPreferenceManager.userId.toInt())
|
||||||
|
} else {
|
||||||
|
speakerListAdapter.muteSpeakers.remove(SharedPreferenceManager.userId.toInt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,6 +1249,46 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun spinRoulette() {
|
||||||
|
viewModel.spinRoulette(roomId = roomId) { can, items, randomlySelectedItem ->
|
||||||
|
val rouletteRawMessage = Gson().toJson(
|
||||||
|
LiveRoomChatRawMessage(
|
||||||
|
type = LiveRoomChatRawMessageType.ROULETTE_DONATION,
|
||||||
|
message = randomlySelectedItem,
|
||||||
|
can = can,
|
||||||
|
donationMessage = "",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
RouletteSpinDialog(
|
||||||
|
activity = this@LiveRoomActivity,
|
||||||
|
items = items,
|
||||||
|
selectedItem = randomlySelectedItem,
|
||||||
|
layoutInflater = layoutInflater
|
||||||
|
) {
|
||||||
|
agora.sendRawMessageToGroup(
|
||||||
|
rawMessage = rouletteRawMessage.toByteArray(),
|
||||||
|
onSuccess = {
|
||||||
|
handler.post {
|
||||||
|
chatAdapter.items.add(
|
||||||
|
LiveRoomRouletteDonationChat(
|
||||||
|
profileUrl = SharedPreferenceManager.profileImage,
|
||||||
|
nickname = SharedPreferenceManager.nickname,
|
||||||
|
rouletteResult = randomlySelectedItem
|
||||||
|
)
|
||||||
|
)
|
||||||
|
invalidateChat()
|
||||||
|
viewModel.addDonationCan(can)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
viewModel.refundRouletteDonation(roomId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun joinChannel(roomInfo: GetRoomInfoResponse) {
|
private fun joinChannel(roomInfo: GetRoomInfoResponse) {
|
||||||
loadingDialog.show(width = screenWidth, message = "라이브에 입장하고 있습니다.")
|
loadingDialog.show(width = screenWidth, message = "라이브에 입장하고 있습니다.")
|
||||||
|
|
||||||
|
@ -1261,6 +1360,31 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
invalidateChat()
|
invalidateChat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LiveRoomChatRawMessageType.TOGGLE_ROULETTE -> {
|
||||||
|
handler.post {
|
||||||
|
activatingRouletteButton(
|
||||||
|
isHost = viewModel
|
||||||
|
.roomInfoResponse
|
||||||
|
.creatorId == SharedPreferenceManager.userId,
|
||||||
|
isActiveRoulette = rawMessage.isActiveRoulette ?: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveRoomChatRawMessageType.ROULETTE_DONATION -> {
|
||||||
|
handler.post {
|
||||||
|
chatAdapter.items.add(
|
||||||
|
LiveRoomRouletteDonationChat(
|
||||||
|
profileUrl = profileUrl,
|
||||||
|
nickname = nickname,
|
||||||
|
rouletteResult = rawMessage.message
|
||||||
|
)
|
||||||
|
)
|
||||||
|
invalidateChat()
|
||||||
|
viewModel.addDonationCan(rawMessage.can)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val chat = message.text
|
val chat = message.text
|
||||||
|
@ -1338,6 +1462,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setMuteSpeakerCreator(isMute: Boolean) {
|
||||||
|
binding.ivMute.visibility = if (isMute) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val rtcEventHandler = object : IRtcEngineEventHandler() {
|
private val rtcEventHandler = object : IRtcEngineEventHandler() {
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
override fun onAudioVolumeIndication(
|
override fun onAudioVolumeIndication(
|
||||||
|
@ -1345,6 +1477,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
totalVolume: Int
|
totalVolume: Int
|
||||||
) {
|
) {
|
||||||
super.onAudioVolumeIndication(speakers, totalVolume)
|
super.onAudioVolumeIndication(speakers, totalVolume)
|
||||||
|
|
||||||
|
Logger.e("onAudioVolumeIndication - $speakers")
|
||||||
|
|
||||||
val activeSpeakerIds = speakers
|
val activeSpeakerIds = speakers
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it.volume > 0 }
|
.filter { it.volume > 0 }
|
||||||
|
@ -1353,13 +1488,17 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
|
|
||||||
Logger.e("onAudioVolumeIndication - $activeSpeakerIds")
|
Logger.e("onAudioVolumeIndication - $activeSpeakerIds")
|
||||||
handler.post {
|
handler.post {
|
||||||
speakerListAdapter.activeSpeakers.clear()
|
if (!activeSpeakerIds.contains(0)) {
|
||||||
speakerListAdapter.activeSpeakers.addAll(activeSpeakerIds)
|
speakerListAdapter.activeSpeakers.clear()
|
||||||
|
speakerListAdapter.activeSpeakers.addAll(activeSpeakerIds)
|
||||||
|
speakerListAdapter.notifyDataSetChanged()
|
||||||
|
|
||||||
if (activeSpeakerIds.contains(0) && !isMicrophoneMute) {
|
if (activeSpeakerIds.contains(viewModel.roomInfoResponse.creatorId.toInt())) {
|
||||||
speakerListAdapter.activeSpeakers.add(SharedPreferenceManager.userId.toInt())
|
binding.ivCreatorProfileBg.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.ivCreatorProfileBg.visibility = View.GONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
speakerListAdapter.notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1389,12 +1528,16 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
override fun onUserMuteAudio(uid: Int, muted: Boolean) {
|
override fun onUserMuteAudio(uid: Int, muted: Boolean) {
|
||||||
super.onUserMuteAudio(uid, muted)
|
super.onUserMuteAudio(uid, muted)
|
||||||
handler.post {
|
handler.post {
|
||||||
if (muted) {
|
if (uid == viewModel.roomInfoResponse.creatorId.toInt()) {
|
||||||
speakerListAdapter.muteSpeakers.add(uid)
|
setMuteSpeakerCreator(muted)
|
||||||
} else {
|
} else {
|
||||||
speakerListAdapter.muteSpeakers.remove(uid)
|
if (muted) {
|
||||||
|
speakerListAdapter.muteSpeakers.add(uid)
|
||||||
|
} else {
|
||||||
|
speakerListAdapter.muteSpeakers.remove(uid)
|
||||||
|
}
|
||||||
|
speakerListAdapter.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
speakerListAdapter.notifyDataSetChanged()
|
|
||||||
}
|
}
|
||||||
Logger.e("onUserMuteAudio - uid: $uid, muted: $muted")
|
Logger.e("onUserMuteAudio - uid: $uid, muted: $muted")
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@ import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationStatusResp
|
||||||
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.update.EditLiveRoomInfoRequest
|
import kr.co.vividnext.sodalive.live.room.update.EditLiveRoomInfoRequest
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteItem
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
|
||||||
import kr.co.vividnext.sodalive.report.ReportRepository
|
import kr.co.vividnext.sodalive.report.ReportRepository
|
||||||
import kr.co.vividnext.sodalive.report.ReportRequest
|
import kr.co.vividnext.sodalive.report.ReportRequest
|
||||||
import kr.co.vividnext.sodalive.report.ReportType
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
|
@ -29,11 +34,13 @@ import okhttp3.MultipartBody
|
||||||
import okhttp3.RequestBody.Companion.asRequestBody
|
import okhttp3.RequestBody.Companion.asRequestBody
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
class LiveRoomViewModel(
|
class LiveRoomViewModel(
|
||||||
private val repository: LiveRepository,
|
private val repository: LiveRepository,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val reportRepository: ReportRepository
|
private val reportRepository: ReportRepository,
|
||||||
|
private val rouletteRepository: RouletteRepository
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
|
private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
|
||||||
val roomInfoLiveData: LiveData<GetRoomInfoResponse>
|
val roomInfoLiveData: LiveData<GetRoomInfoResponse>
|
||||||
|
@ -43,14 +50,10 @@ class LiveRoomViewModel(
|
||||||
val toastLiveData: LiveData<String?>
|
val toastLiveData: LiveData<String?>
|
||||||
get() = _toastLiveData
|
get() = _toastLiveData
|
||||||
|
|
||||||
private val _isShowNotice = MutableLiveData(true)
|
private val _isShowNotice = MutableLiveData(false)
|
||||||
val isShowNotice: LiveData<Boolean>
|
val isShowNotice: LiveData<Boolean>
|
||||||
get() = _isShowNotice
|
get() = _isShowNotice
|
||||||
|
|
||||||
private val _isExpandNotice = MutableLiveData(false)
|
|
||||||
val isExpandNotice: LiveData<Boolean>
|
|
||||||
get() = _isExpandNotice
|
|
||||||
|
|
||||||
private val _totalDonationCan = MutableLiveData(0)
|
private val _totalDonationCan = MutableLiveData(0)
|
||||||
val totalDonationCan: LiveData<Int>
|
val totalDonationCan: LiveData<Int>
|
||||||
get() = _totalDonationCan
|
get() = _totalDonationCan
|
||||||
|
@ -59,6 +62,10 @@ class LiveRoomViewModel(
|
||||||
val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>
|
val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>
|
||||||
get() = _userProfileLiveData
|
get() = _userProfileLiveData
|
||||||
|
|
||||||
|
private val _coverImageUrlLiveData = MutableLiveData("")
|
||||||
|
val coverImageUrlLiveData: LiveData<String>
|
||||||
|
get() = _coverImageUrlLiveData
|
||||||
|
|
||||||
lateinit var roomInfoResponse: GetRoomInfoResponse
|
lateinit var roomInfoResponse: GetRoomInfoResponse
|
||||||
|
|
||||||
fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized
|
fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized
|
||||||
|
@ -188,6 +195,10 @@ class LiveRoomViewModel(
|
||||||
Logger.e("data: ${it.data}")
|
Logger.e("data: ${it.data}")
|
||||||
_roomInfoLiveData.postValue(roomInfoResponse)
|
_roomInfoLiveData.postValue(roomInfoResponse)
|
||||||
|
|
||||||
|
if (_coverImageUrlLiveData.value!! != roomInfoResponse.coverImageUrl) {
|
||||||
|
_coverImageUrlLiveData.value = roomInfoResponse.coverImageUrl
|
||||||
|
}
|
||||||
|
|
||||||
getTotalDonationCan(roomId = roomId)
|
getTotalDonationCan(roomId = roomId)
|
||||||
|
|
||||||
if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) {
|
if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) {
|
||||||
|
@ -346,11 +357,6 @@ class LiveRoomViewModel(
|
||||||
|
|
||||||
fun toggleShowNotice() {
|
fun toggleShowNotice() {
|
||||||
_isShowNotice.value = !isShowNotice.value!!
|
_isShowNotice.value = !isShowNotice.value!!
|
||||||
_isExpandNotice.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toggleExpandNotice() {
|
|
||||||
_isExpandNotice.value = !isExpandNotice.value!!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleBackgroundImage() {
|
fun toggleBackgroundImage() {
|
||||||
|
@ -775,4 +781,154 @@ class LiveRoomViewModel(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun showRoulette(complete: (RoulettePreview) -> Unit) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
rouletteRepository.getRoulette(
|
||||||
|
creatorId = roomInfoResponse.creatorId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
val data = it.data
|
||||||
|
if (
|
||||||
|
it.success &&
|
||||||
|
data != null &&
|
||||||
|
data.isActive &&
|
||||||
|
data.items.isNotEmpty()
|
||||||
|
) {
|
||||||
|
complete(
|
||||||
|
RoulettePreview(
|
||||||
|
data.can,
|
||||||
|
items = calculatePercentages(data.items)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("룰렛을 사용할 수 없습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun spinRoulette(roomId: Long, complete: (Int, List<RouletteItem>, String) -> Unit) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
rouletteRepository.spinRoulette(
|
||||||
|
request = SpinRouletteRequest(roomId = roomId),
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
|
||||||
|
val data = it.data
|
||||||
|
if (
|
||||||
|
it.success &&
|
||||||
|
data != null &&
|
||||||
|
data.isActive &&
|
||||||
|
data.items.isNotEmpty()
|
||||||
|
) {
|
||||||
|
SharedPreferenceManager.can -= data.can
|
||||||
|
randomSelectRouletteItem(data.can, data.items, complete)
|
||||||
|
} else {
|
||||||
|
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("룰렛을 사용할 수 없습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refundRouletteDonation(roomId: Long) {
|
||||||
|
_isLoading.postValue(true)
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
rouletteRepository.refundRouletteDonation(
|
||||||
|
roomId,
|
||||||
|
"Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success) {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"후원에 실패했습니다.\n다시 후원해주세요.\n" +
|
||||||
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"후원에 실패한 캔이 환불되지 않았습니다\n고객센터로 문의해주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun randomSelectRouletteItem(
|
||||||
|
can: Int,
|
||||||
|
items: List<RouletteItem>,
|
||||||
|
complete: (Int, List<RouletteItem>, String) -> Unit
|
||||||
|
) {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val rouletteItems = mutableListOf<String>()
|
||||||
|
items.asSequence().forEach { item ->
|
||||||
|
repeat(item.weight * 10) {
|
||||||
|
rouletteItems.add(item.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
complete(can, items, rouletteItems.random())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculatePercentages(options: List<RouletteItem>): List<RoulettePreviewItem> {
|
||||||
|
val totalWeight = options.sumOf { it.weight }
|
||||||
|
val updatedOptions = options.asSequence().map { option ->
|
||||||
|
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
||||||
|
RoulettePreviewItem(
|
||||||
|
title = option.title,
|
||||||
|
percent = "${String.format("%.2f", percent)}%"
|
||||||
|
)
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
return updatedOptions
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@ package kr.co.vividnext.sodalive.live.room.chat
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Typeface
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import android.text.style.StyleSpan
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.res.ResourcesCompat
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
@ -65,12 +67,7 @@ data class LiveRoomJoinChat(
|
||||||
)
|
)
|
||||||
|
|
||||||
spStr.setSpan(
|
spStr.setSpan(
|
||||||
CustomTypefaceSpan(
|
StyleSpan(Typeface.BOLD),
|
||||||
ResourcesCompat.getFont(
|
|
||||||
context,
|
|
||||||
R.font.gmarket_sans_bold
|
|
||||||
)
|
|
||||||
),
|
|
||||||
str.indexOf("'"),
|
str.indexOf("'"),
|
||||||
str.indexOf("'님"),
|
str.indexOf("'님"),
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
@ -174,6 +171,7 @@ data class LiveRoomNormalChat(
|
||||||
itemBinding.tvNickname.text = nickname
|
itemBinding.tvNickname.text = nickname
|
||||||
|
|
||||||
itemBinding.ivBg.visibility = View.VISIBLE
|
itemBinding.ivBg.visibility = View.VISIBLE
|
||||||
|
itemBinding.ivRoulette.visibility = View.GONE
|
||||||
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
||||||
|
|
||||||
when (rank + 1) {
|
when (rank + 1) {
|
||||||
|
@ -190,7 +188,7 @@ data class LiveRoomNormalChat(
|
||||||
}
|
}
|
||||||
|
|
||||||
-1 -> {
|
-1 -> {
|
||||||
itemBinding.ivBg.setImageResource(R.drawable.bg_circle_6f3dec_9970ff)
|
itemBinding.ivBg.setImageResource(R.drawable.bg_circle_3bb9f1)
|
||||||
itemBinding.ivCrown.setImageResource(R.drawable.ic_crown)
|
itemBinding.ivCrown.setImageResource(R.drawable.ic_crown)
|
||||||
itemBinding.ivCrown.visibility = View.VISIBLE
|
itemBinding.ivCrown.visibility = View.VISIBLE
|
||||||
}
|
}
|
||||||
|
@ -229,7 +227,7 @@ data class LiveRoomNormalChat(
|
||||||
)
|
)
|
||||||
|
|
||||||
if (SharedPreferenceManager.userId == userId) {
|
if (SharedPreferenceManager.userId == userId) {
|
||||||
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_999970ff)
|
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_553bb9f1)
|
||||||
} else {
|
} else {
|
||||||
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_99000000)
|
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_99000000)
|
||||||
}
|
}
|
||||||
|
@ -288,6 +286,7 @@ data class LiveRoomDonationChat(
|
||||||
itemBinding.ivCan.visibility = View.VISIBLE
|
itemBinding.ivCan.visibility = View.VISIBLE
|
||||||
itemBinding.ivBg.visibility = View.GONE
|
itemBinding.ivBg.visibility = View.GONE
|
||||||
itemBinding.ivCrown.visibility = View.GONE
|
itemBinding.ivCrown.visibility = View.GONE
|
||||||
|
itemBinding.ivRoulette.visibility = View.GONE
|
||||||
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
||||||
|
|
||||||
if (donationMessage.isNotBlank()) {
|
if (donationMessage.isNotBlank()) {
|
||||||
|
@ -302,35 +301,89 @@ data class LiveRoomDonationChat(
|
||||||
|
|
||||||
itemBinding.root.setBackgroundResource(
|
itemBinding.root.setBackgroundResource(
|
||||||
when {
|
when {
|
||||||
can >= 100000 -> {
|
|
||||||
R.drawable.bg_round_corner_6_7_c25264
|
|
||||||
}
|
|
||||||
|
|
||||||
can >= 50000 -> {
|
|
||||||
R.drawable.bg_round_corner_6_7_e6d85e37
|
|
||||||
}
|
|
||||||
|
|
||||||
can >= 10000 -> {
|
can >= 10000 -> {
|
||||||
R.drawable.bg_round_corner_6_7_e6d38c38
|
R.drawable.bg_round_corner_6_7_ccc25264
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 5000 -> {
|
can >= 5000 -> {
|
||||||
R.drawable.bg_round_corner_6_7_e659548f
|
R.drawable.bg_round_corner_6_7_ccd85e37
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 1000 -> {
|
can >= 1000 -> {
|
||||||
R.drawable.bg_round_corner_6_7_e64d6aa4
|
R.drawable.bg_round_corner_6_7_ccd38c38
|
||||||
}
|
}
|
||||||
|
|
||||||
can >= 500 -> {
|
can >= 500 -> {
|
||||||
R.drawable.bg_round_corner_6_7_e62d7390
|
R.drawable.bg_round_corner_6_7_cc59548f
|
||||||
|
}
|
||||||
|
|
||||||
|
can >= 100 -> {
|
||||||
|
R.drawable.bg_round_corner_6_7_cc4d6aa4
|
||||||
|
}
|
||||||
|
|
||||||
|
can >= 50 -> {
|
||||||
|
R.drawable.bg_round_corner_6_7_cc2d7390
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
R.drawable.bg_round_corner_6_7_e6548f7d
|
R.drawable.bg_round_corner_6_7_cc548f7d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
itemBinding.root.setPadding(33)
|
itemBinding.root.setPadding(33)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class LiveRoomRouletteDonationChat(
|
||||||
|
@SerializedName("profileUrl") val profileUrl: String,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("rouletteResult") val rouletteResult: String
|
||||||
|
) : LiveRoomChat() {
|
||||||
|
override fun bind(context: Context, binding: ViewBinding, onClickProfile: ((Long) -> Unit)?) {
|
||||||
|
val itemBinding = binding as ItemLiveRoomChatBinding
|
||||||
|
val chat = "[$rouletteResult] 당첨!"
|
||||||
|
val spChat = SpannableString(chat)
|
||||||
|
spChat.setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
context,
|
||||||
|
R.color.color_ffe500
|
||||||
|
)
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
chat.indexOf("]", 0, true) + 1,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
val spNickname = SpannableString("${nickname}님의 룰렛 결과?")
|
||||||
|
spNickname.setSpan(
|
||||||
|
StyleSpan(Typeface.NORMAL),
|
||||||
|
0,
|
||||||
|
nickname.length,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
|
||||||
|
itemBinding.ivProfile.load(profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(RoundedCornersTransformation(23.3f.dpToPx()))
|
||||||
|
}
|
||||||
|
itemBinding.tvChat.text = spChat
|
||||||
|
itemBinding.tvNickname.text = spNickname
|
||||||
|
itemBinding.ivProfile.setOnClickListener {}
|
||||||
|
|
||||||
|
itemBinding.ivCan.visibility = View.GONE
|
||||||
|
itemBinding.ivBg.visibility = View.GONE
|
||||||
|
itemBinding.ivCrown.visibility = View.GONE
|
||||||
|
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
||||||
|
itemBinding.ivRoulette.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
itemBinding.tvDonationMessage.visibility = View.GONE
|
||||||
|
|
||||||
|
itemBinding.llMessageBg.setPadding(0)
|
||||||
|
itemBinding.llMessageBg.background = null
|
||||||
|
|
||||||
|
itemBinding.root.setBackgroundResource(R.drawable.bg_round_corner_6_7_ccc25264)
|
||||||
|
itemBinding.root.setPadding(33)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,12 +6,21 @@ data class LiveRoomChatRawMessage(
|
||||||
@SerializedName("type") val type: LiveRoomChatRawMessageType,
|
@SerializedName("type") val type: LiveRoomChatRawMessageType,
|
||||||
@SerializedName("message") val message: String,
|
@SerializedName("message") val message: String,
|
||||||
@SerializedName("can") val can: Int,
|
@SerializedName("can") val can: Int,
|
||||||
@SerializedName("donationMessage") val donationMessage: String?
|
@SerializedName("donationMessage") val donationMessage: String?,
|
||||||
|
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class LiveRoomChatRawMessageType {
|
enum class LiveRoomChatRawMessageType {
|
||||||
@SerializedName("DONATION") DONATION,
|
@SerializedName("DONATION")
|
||||||
@SerializedName("SET_MANAGER") SET_MANAGER,
|
DONATION,
|
||||||
@SerializedName("EDIT_ROOM_INFO") EDIT_ROOM_INFO,
|
@SerializedName("SET_MANAGER")
|
||||||
@SerializedName("DONATION_STATUS") DONATION_STATUS
|
SET_MANAGER,
|
||||||
|
@SerializedName("EDIT_ROOM_INFO")
|
||||||
|
EDIT_ROOM_INFO,
|
||||||
|
@SerializedName("DONATION_STATUS")
|
||||||
|
DONATION_STATUS,
|
||||||
|
@SerializedName("TOGGLE_ROULETTE")
|
||||||
|
TOGGLE_ROULETTE,
|
||||||
|
@SerializedName("ROULETTE_DONATION")
|
||||||
|
ROULETTE_DONATION
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,9 +365,9 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.llReservationDatetime.visibility = View.GONE
|
binding.llReservationDatetime.visibility = View.GONE
|
||||||
binding.ivTimeReservation.visibility = View.GONE
|
binding.ivTimeReservation.visibility = View.GONE
|
||||||
binding.ivTimeNow.visibility = View.VISIBLE
|
binding.ivTimeNow.visibility = View.VISIBLE
|
||||||
binding.llTimeNow.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llTimeNow.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.llTimeReservation.setBackgroundResource(
|
binding.llTimeReservation.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
binding.tvTimeNow.setTextColor(
|
binding.tvTimeNow.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
|
@ -379,22 +379,22 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.tvTimeReservation.setTextColor(
|
binding.tvTimeReservation.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.llReservationDatetime.visibility = View.VISIBLE
|
binding.llReservationDatetime.visibility = View.VISIBLE
|
||||||
binding.ivTimeReservation.visibility = View.VISIBLE
|
binding.ivTimeReservation.visibility = View.VISIBLE
|
||||||
binding.ivTimeNow.visibility = View.GONE
|
binding.ivTimeNow.visibility = View.GONE
|
||||||
binding.llTimeNow.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llTimeNow.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.llTimeReservation.setBackgroundResource(
|
binding.llTimeReservation.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_9970ff
|
R.drawable.bg_round_corner_6_7_3bb9f1
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.tvTimeNow.setTextColor(
|
binding.tvTimeNow.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -413,8 +413,8 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.ivPrivate.visibility = View.VISIBLE
|
binding.ivPrivate.visibility = View.VISIBLE
|
||||||
binding.ivOpen.visibility = View.GONE
|
binding.ivOpen.visibility = View.GONE
|
||||||
|
|
||||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
|
||||||
binding.tvPrivate.setTextColor(
|
binding.tvPrivate.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
|
@ -426,7 +426,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.tvOpen.setTextColor(
|
binding.tvOpen.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -437,13 +437,13 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.ivOpen.visibility = View.VISIBLE
|
binding.ivOpen.visibility = View.VISIBLE
|
||||||
binding.ivPrivate.visibility = View.GONE
|
binding.ivPrivate.visibility = View.GONE
|
||||||
|
|
||||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
|
||||||
binding.tvPrivate.setTextColor(
|
binding.tvPrivate.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -501,16 +501,16 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
viewModel.isAdultLiveData.observe(this) {
|
viewModel.isAdultLiveData.observe(this) {
|
||||||
if (it) {
|
if (it) {
|
||||||
binding.ivAgeAll.visibility = View.GONE
|
binding.ivAgeAll.visibility = View.GONE
|
||||||
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAge19.visibility = View.VISIBLE
|
binding.ivAge19.visibility = View.VISIBLE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -519,16 +519,16 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.ivAge19.visibility = View.GONE
|
binding.ivAge19.visibility = View.GONE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAgeAll.visibility = View.VISIBLE
|
binding.ivAgeAll.visibility = View.VISIBLE
|
||||||
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llAgeAll.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -605,7 +605,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
priceView.setTextColor(
|
priceView.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
priceView.typeface = ResourcesCompat.getFont(
|
priceView.typeface = ResourcesCompat.getFont(
|
||||||
|
|
|
@ -20,7 +20,9 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentLiveRoomDetailBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentLiveRoomDetailBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
|
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class LiveRoomDetailFragment(
|
class LiveRoomDetailFragment(
|
||||||
private val roomId: Long,
|
private val roomId: Long,
|
||||||
|
@ -90,7 +92,11 @@ class LiveRoomDetailFragment(
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvTitle.text = response.title
|
binding.tvTitle.text = response.title
|
||||||
binding.tvDate.text = response.beginDateTime
|
binding.tvDate.text = response.beginDateTime.convertDateFormat(
|
||||||
|
from = "yyyy.MM.dd EEE hh:mm a",
|
||||||
|
to = "yyyy년 MM월 dd일 (E) a hh시 mm분",
|
||||||
|
inputLocale = Locale.ENGLISH
|
||||||
|
)
|
||||||
|
|
||||||
if (response.price > 0) {
|
if (response.price > 0) {
|
||||||
binding.tvCan.text = response.price.toString()
|
binding.tvCan.text = response.price.toString()
|
||||||
|
|
|
@ -1,32 +1,87 @@
|
||||||
package kr.co.vividnext.sodalive.live.room.dialog
|
package kr.co.vividnext.sodalive.live.room.dialog
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.widget.LinearLayout
|
import android.view.View
|
||||||
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
import android.view.WindowManager
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogLivePaymentBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
class LivePaymentDialog(
|
class LivePaymentDialog(
|
||||||
activity: Activity,
|
activity: Activity,
|
||||||
layoutInflater: LayoutInflater,
|
layoutInflater: LayoutInflater,
|
||||||
title: String,
|
title: String,
|
||||||
desc: String,
|
desc: String,
|
||||||
|
desc2: String? = null,
|
||||||
|
startDateTime: String? = null,
|
||||||
|
nowDateTime: String? = null,
|
||||||
confirmButtonTitle: String,
|
confirmButtonTitle: String,
|
||||||
confirmButtonClick: () -> Unit,
|
confirmButtonClick: () -> Unit,
|
||||||
cancelButtonTitle: String = "",
|
cancelButtonTitle: String = "",
|
||||||
cancelButtonClick: (() -> Unit)? = null,
|
cancelButtonClick: (() -> Unit)? = null,
|
||||||
) : LiveDialog(
|
|
||||||
activity,
|
|
||||||
layoutInflater,
|
|
||||||
title,
|
|
||||||
desc,
|
|
||||||
confirmButtonTitle,
|
|
||||||
confirmButtonClick,
|
|
||||||
cancelButtonTitle,
|
|
||||||
cancelButtonClick
|
|
||||||
) {
|
) {
|
||||||
|
private val alertDialog: AlertDialog
|
||||||
|
private val dialogView = DialogLivePaymentBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val lp = dialogView.tvConfirm.layoutParams as LinearLayout.LayoutParams
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
lp.weight = 2F
|
dialogBuilder.setView(dialogView.root)
|
||||||
dialogView.tvConfirm.layoutParams = lp
|
|
||||||
|
alertDialog = dialogBuilder.create()
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
|
||||||
|
dialogView.tvTitle.text = title
|
||||||
|
dialogView.tvDesc.text = desc
|
||||||
|
|
||||||
|
if (startDateTime != null && nowDateTime != null) {
|
||||||
|
dialogView.tvDesc2.text = desc2
|
||||||
|
dialogView.tvNowDate.text = nowDateTime
|
||||||
|
dialogView.tvStartDate.text = startDateTime
|
||||||
|
|
||||||
|
dialogView.tvDesc2.visibility = View.VISIBLE
|
||||||
|
dialogView.llTimeNotice.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
dialogView.tvDesc2.visibility = View.GONE
|
||||||
|
dialogView.llTimeNotice.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvCancel.text = cancelButtonTitle
|
||||||
|
dialogView.tvCancel.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
cancelButtonClick?.let { it() }
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvConfirm.text = confirmButtonTitle
|
||||||
|
dialogView.tvConfirm.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
confirmButtonClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvCancel.visibility = if (cancelButtonTitle.isNotBlank()) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvConfirm.visibility = if (confirmButtonTitle.isNotBlank()) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(width: Int, message: String = "") {
|
||||||
|
alertDialog.show()
|
||||||
|
|
||||||
|
val lp = WindowManager.LayoutParams()
|
||||||
|
lp.copyFrom(alertDialog.window?.attributes)
|
||||||
|
lp.width = width - (26.7f.dpToPx()).toInt()
|
||||||
|
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
alertDialog.window?.attributes = lp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ data class GetRoomInfoResponse(
|
||||||
@SerializedName("listenerList") val listenerList: List<LiveRoomMember>,
|
@SerializedName("listenerList") val listenerList: List<LiveRoomMember>,
|
||||||
@SerializedName("managerList") val managerList: List<LiveRoomMember>,
|
@SerializedName("managerList") val managerList: List<LiveRoomMember>,
|
||||||
@SerializedName("donationRankingTop3UserIds") val donationRankingTop3UserIds: List<Long>,
|
@SerializedName("donationRankingTop3UserIds") val donationRankingTop3UserIds: List<Long>,
|
||||||
|
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean,
|
||||||
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean,
|
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean,
|
||||||
@SerializedName("password") val password: String? = null
|
@SerializedName("password") val password: String? = null
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,11 +5,11 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import coil.load
|
import coil.transform.CircleCropTransformation
|
||||||
import coil.transform.RoundedCornersTransformation
|
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomProfileBinding
|
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomProfileBinding
|
||||||
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.live.room.info.LiveRoomMember
|
import kr.co.vividnext.sodalive.live.room.info.LiveRoomMember
|
||||||
|
|
||||||
class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapter.ViewHolder>() {
|
class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapter.ViewHolder>() {
|
||||||
|
@ -17,10 +17,10 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
|
||||||
private val binding: ItemLiveRoomProfileBinding
|
private val binding: ItemLiveRoomProfileBinding
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(item: LiveRoomMember) {
|
fun bind(item: LiveRoomMember) {
|
||||||
binding.ivProfile.load(item.profileImage) {
|
binding.ivProfile.loadUrl(item.profileImage) {
|
||||||
crossfade(true)
|
crossfade(true)
|
||||||
placeholder(R.drawable.ic_place_holder)
|
placeholder(R.drawable.ic_place_holder)
|
||||||
transformations(RoundedCornersTransformation(23.3f.dpToPx()))
|
transformations(CircleCropTransformation())
|
||||||
|
|
||||||
if (activeSpeakers.contains(item.id.toInt())) {
|
if (activeSpeakers.contains(item.id.toInt())) {
|
||||||
binding.ivBg.visibility = View.VISIBLE
|
binding.ivBg.visibility = View.VISIBLE
|
||||||
|
@ -35,15 +35,9 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
|
||||||
}
|
}
|
||||||
|
|
||||||
val ivMuteLp = binding.ivMute.layoutParams
|
val ivMuteLp = binding.ivMute.layoutParams
|
||||||
ivMuteLp.width = 51.7f.dpToPx().toInt()
|
ivMuteLp.width = 30f.dpToPx().toInt()
|
||||||
ivMuteLp.height = 51.7f.dpToPx().toInt()
|
ivMuteLp.height = 30f.dpToPx().toInt()
|
||||||
binding.ivMute.layoutParams = ivMuteLp
|
binding.ivMute.layoutParams = ivMuteLp
|
||||||
|
|
||||||
if (managerId == item.id) {
|
|
||||||
binding.ivCrown.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
binding.ivCrown.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.tvNickname.text = item.nickname
|
binding.tvNickname.text = item.nickname
|
||||||
|
|
|
@ -20,7 +20,6 @@ class LiveRoomUserProfileDialog(
|
||||||
private val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>,
|
private val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>,
|
||||||
layoutInflater: LayoutInflater,
|
layoutInflater: LayoutInflater,
|
||||||
private val isStaff: (Long) -> Boolean,
|
private val isStaff: (Long) -> Boolean,
|
||||||
private val onClickSendMessage: (Long, String) -> Unit,
|
|
||||||
private val onClickSetManager: (Long) -> Unit,
|
private val onClickSetManager: (Long) -> Unit,
|
||||||
private val onClickReleaseManager: (Long) -> Unit,
|
private val onClickReleaseManager: (Long) -> Unit,
|
||||||
private val onClickFollow: (Long) -> Unit,
|
private val onClickFollow: (Long) -> Unit,
|
||||||
|
@ -84,18 +83,8 @@ class LiveRoomUserProfileDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.tvNickname.text = userProfile.nickname
|
dialogView.tvNickname.text = userProfile.nickname
|
||||||
dialogView.tvTags.text = userProfile.tags
|
|
||||||
dialogView.tvGender.text = userProfile.gender
|
dialogView.tvGender.text = userProfile.gender
|
||||||
dialogView.tvIntroduce.text = userProfile.introduce
|
|
||||||
|
|
||||||
dialogView.ivClose.setOnClickListener { alertDialog.dismiss() }
|
dialogView.ivClose.setOnClickListener { alertDialog.dismiss() }
|
||||||
dialogView.llSendMessage.setOnClickListener {
|
|
||||||
onClickSendMessage(
|
|
||||||
userProfile.userId,
|
|
||||||
userProfile.nickname
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
dialogView.tvIntroduce.setOnClickListener {
|
dialogView.tvIntroduce.setOnClickListener {
|
||||||
isIntroduceFold = !isIntroduceFold
|
isIntroduceFold = !isIntroduceFold
|
||||||
|
|
||||||
|
@ -169,25 +158,33 @@ class LiveRoomUserProfileDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userProfile.isFollowing != null) {
|
if (userProfile.isFollowing != null) {
|
||||||
dialogView.llFollow.visibility = View.VISIBLE
|
dialogView.ivFollow.visibility = View.VISIBLE
|
||||||
|
|
||||||
if (userProfile.isFollowing) {
|
if (userProfile.isFollowing) {
|
||||||
dialogView.tvFollow.text = "팔로잉"
|
dialogView.ivFollow.setImageResource(R.drawable.btn_following)
|
||||||
dialogView.ivFollow.setImageResource(R.drawable.ic_alarm_selected)
|
dialogView.ivFollow.setOnClickListener { onClickUnFollow(userProfile.userId) }
|
||||||
dialogView.llFollow.setBackgroundResource(
|
|
||||||
R.drawable.bg_round_corner_23_3_3e1b93_9970ff
|
|
||||||
)
|
|
||||||
dialogView.tvFollow.setOnClickListener { onClickUnFollow(userProfile.userId) }
|
|
||||||
} else {
|
} else {
|
||||||
dialogView.tvFollow.text = "팔로우"
|
dialogView.ivFollow.setImageResource(R.drawable.btn_follow)
|
||||||
dialogView.ivFollow.setImageResource(R.drawable.ic_alarm)
|
dialogView.ivFollow.setOnClickListener { onClickFollow(userProfile.userId) }
|
||||||
dialogView.llFollow.setBackgroundResource(
|
}
|
||||||
R.drawable.bg_round_corner_23_3_transparent_9970ff
|
|
||||||
)
|
if (userProfile.tags.isNotBlank()) {
|
||||||
dialogView.tvFollow.setOnClickListener { onClickFollow(userProfile.userId) }
|
dialogView.tvTags.text = userProfile.tags
|
||||||
|
dialogView.tvTags.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
dialogView.tvTags.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userProfile.introduce.isNotBlank()) {
|
||||||
|
dialogView.tvIntroduce.text = userProfile.introduce
|
||||||
|
dialogView.tvIntroduce.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
dialogView.tvIntroduce.visibility = View.GONE
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dialogView.llFollow.visibility = View.GONE
|
dialogView.tvTags.visibility = View.GONE
|
||||||
|
dialogView.ivFollow.visibility = View.GONE
|
||||||
|
dialogView.tvIntroduce.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.ivMenu.setOnClickListener {
|
dialogView.ivMenu.setOnClickListener {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class GetRouletteResponse(
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("isActive") val isActive: Boolean,
|
||||||
|
@SerializedName("items") val items: List<RouletteItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class RouletteItem(
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("weight") val weight: Int
|
||||||
|
)
|
|
@ -0,0 +1,45 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.Path
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
|
||||||
|
class RouletteInvertedTriangle @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : View(context, attrs, defStyleAttr) {
|
||||||
|
private val trianglePath = Path()
|
||||||
|
private var trianglePaint = Paint()
|
||||||
|
|
||||||
|
private val triangleSize = 60f
|
||||||
|
|
||||||
|
init {
|
||||||
|
trianglePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||||
|
color = Color.RED // Set the color of the triangle
|
||||||
|
style = Paint.Style.FILL // Fill the triangle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
// Clear the old path
|
||||||
|
trianglePath.reset()
|
||||||
|
|
||||||
|
// Define the new path for the inverted triangle
|
||||||
|
// Starting point (top of the triangle)
|
||||||
|
trianglePath.moveTo((width / 2f) - 30, -10f)
|
||||||
|
// Line to bottom left of the triangle
|
||||||
|
trianglePath.lineTo((width / 2f) + 30, -10f)
|
||||||
|
// Line to bottom right of the triangle
|
||||||
|
trianglePath.lineTo(width / 2f, 10f + triangleSize)
|
||||||
|
// Close the path to form a triangle
|
||||||
|
trianglePath.close()
|
||||||
|
|
||||||
|
canvas.drawPath(trianglePath, trianglePaint)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
data class RoulettePreview(
|
||||||
|
val can: Int,
|
||||||
|
val items: List<RoulettePreviewItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class RoulettePreviewItem(
|
||||||
|
val title: String,
|
||||||
|
val percent: String
|
||||||
|
)
|
|
@ -0,0 +1,106 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.WindowManager
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogRoulettePreviewBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||||
|
|
||||||
|
class RoulettePreviewDialog(
|
||||||
|
private val activity: FragmentActivity,
|
||||||
|
private val preview: RoulettePreview,
|
||||||
|
private val title: String = "",
|
||||||
|
private val onClickSpin: (() -> Unit)? = null,
|
||||||
|
layoutInflater: LayoutInflater
|
||||||
|
) {
|
||||||
|
private val alertDialog: AlertDialog
|
||||||
|
private val dialogView = DialogRoulettePreviewBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
|
dialogBuilder.setView(dialogView.root)
|
||||||
|
|
||||||
|
alertDialog = dialogBuilder.create()
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||||
|
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() {
|
||||||
|
alertDialog.show()
|
||||||
|
|
||||||
|
val lp = WindowManager.LayoutParams()
|
||||||
|
lp.copyFrom(alertDialog.window?.attributes)
|
||||||
|
lp.width = activity.resources.displayMetrics.widthPixels - (26.7f.dpToPx()).toInt()
|
||||||
|
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
alertDialog.window?.attributes = lp
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun setupView() {
|
||||||
|
dialogView.tvCancel.setOnClickListener { alertDialog.dismiss() }
|
||||||
|
|
||||||
|
dialogView.tvSpinRoulette.text = "${preview.can}캔으로 룰렛 돌리기"
|
||||||
|
dialogView.tvSpinRoulette.setOnClickListener {
|
||||||
|
if (onClickSpin != null) {
|
||||||
|
onClickSpin!!()
|
||||||
|
}
|
||||||
|
|
||||||
|
alertDialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.tvTitle.text = title.ifBlank { "룰렛" }
|
||||||
|
if (onClickSpin != null) {
|
||||||
|
dialogView.tvCan.visibility = View.VISIBLE
|
||||||
|
dialogView.tvCan.text = SharedPreferenceManager.can.moneyFormat()
|
||||||
|
dialogView.tvCan.setOnClickListener {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
|
||||||
|
val intent = Intent(activity, CanChargeActivity::class.java)
|
||||||
|
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dialogView.tvCan.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
preview.items.forEachIndexed { index, item ->
|
||||||
|
dialogView.llRouletteOptionContainer.addView(createOptionView(index, item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun createOptionView(index: Int, item: RoulettePreviewItem): View {
|
||||||
|
val itemView = LayoutInflater
|
||||||
|
.from(activity)
|
||||||
|
.inflate(
|
||||||
|
R.layout.layout_roulette_preview_item,
|
||||||
|
dialogView.llRouletteOptionContainer,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
val tvItemTitle = itemView.findViewById<TextView>(R.id.tv_roulette_item_title)
|
||||||
|
val tvOrder = itemView.findViewById<TextView>(R.id.tv_order)
|
||||||
|
|
||||||
|
tvItemTitle.text = "${item.title} (${item.percent})"
|
||||||
|
tvOrder.text = "${index + 1}"
|
||||||
|
|
||||||
|
return itemView
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.CreateOrUpdateRouletteRequest
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteApi
|
||||||
|
|
||||||
|
class RouletteRepository(private val api: RouletteApi) {
|
||||||
|
fun createOrUpdateRoulette(
|
||||||
|
request: CreateOrUpdateRouletteRequest,
|
||||||
|
token: String
|
||||||
|
) = api.createOrUpdateRoulette(
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getRoulette(creatorId: Long, token: String) = api.getRoulette(
|
||||||
|
creatorId = creatorId,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun spinRoulette(request: SpinRouletteRequest, token: String) = api.spinRoulette(
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun refundRouletteDonation(roomId: Long, token: String): Single<ApiResponse<Any>> {
|
||||||
|
return api.refundRouletteDonation(
|
||||||
|
id = roomId,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Window
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import kr.co.vividnext.sodalive.databinding.DialogRouletteSpinBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class RouletteSpinDialog(
|
||||||
|
private val activity: FragmentActivity,
|
||||||
|
private val items: List<RouletteItem>,
|
||||||
|
private val selectedItem: String,
|
||||||
|
layoutInflater: LayoutInflater,
|
||||||
|
private val complete: () -> Unit
|
||||||
|
) {
|
||||||
|
private val alertDialog: AlertDialog
|
||||||
|
private val dialogView = DialogRouletteSpinBinding.inflate(layoutInflater)
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
init {
|
||||||
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
|
dialogBuilder.setView(dialogView.root)
|
||||||
|
|
||||||
|
alertDialog = dialogBuilder.create()
|
||||||
|
alertDialog.setCancelable(false)
|
||||||
|
alertDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||||
|
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() {
|
||||||
|
alertDialog.show()
|
||||||
|
|
||||||
|
val lp = WindowManager.LayoutParams()
|
||||||
|
lp.copyFrom(alertDialog.window?.attributes)
|
||||||
|
lp.width = activity.resources.displayMetrics.widthPixels - (26.7f.dpToPx()).toInt()
|
||||||
|
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
|
||||||
|
|
||||||
|
alertDialog.window?.attributes = lp
|
||||||
|
rotateToOption()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupView() {
|
||||||
|
dialogView.roulette.items = items
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rotateToOption() {
|
||||||
|
dialogView.roulette.rotateToOption(selectedItem) {
|
||||||
|
handler.postDelayed({
|
||||||
|
alertDialog.dismiss()
|
||||||
|
complete()
|
||||||
|
}, 1500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Paint
|
||||||
|
import android.graphics.RectF
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.view.animation.Animation
|
||||||
|
import android.view.animation.RotateAnimation
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.min
|
||||||
|
import kotlin.math.sin
|
||||||
|
|
||||||
|
class RouletteView @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyleAttr: Int = 0
|
||||||
|
) : View(context, attrs, defStyleAttr) {
|
||||||
|
private var rect = RectF()
|
||||||
|
|
||||||
|
private val fillPaint = Paint()
|
||||||
|
private val textPaint = Paint()
|
||||||
|
private val strokePaint = Paint()
|
||||||
|
|
||||||
|
var items = listOf<RouletteItem>()
|
||||||
|
|
||||||
|
private val colors = listOf(
|
||||||
|
Color.parseColor("#D73535"),
|
||||||
|
Color.parseColor("#FF5151"),
|
||||||
|
Color.parseColor("#FF7C32"),
|
||||||
|
Color.parseColor("#FFAF13"),
|
||||||
|
Color.parseColor("#FFC658"),
|
||||||
|
Color.parseColor("#8BDA70"),
|
||||||
|
Color.parseColor("#06AB97"),
|
||||||
|
Color.parseColor("#12AAFF"),
|
||||||
|
Color.parseColor("#0052B3"),
|
||||||
|
Color.parseColor("#7444FF")
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
strokePaint.apply {
|
||||||
|
color = Color.WHITE
|
||||||
|
style = Paint.Style.STROKE
|
||||||
|
strokeWidth = 10f
|
||||||
|
isAntiAlias = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fillPaint.apply {
|
||||||
|
style = Paint.Style.FILL
|
||||||
|
isAntiAlias = true
|
||||||
|
}
|
||||||
|
|
||||||
|
textPaint.apply {
|
||||||
|
color = Color.WHITE
|
||||||
|
textSize = 30f
|
||||||
|
textAlign = Paint.Align.CENTER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
|
|
||||||
|
val diameter = min(width, height) - strokePaint.strokeWidth
|
||||||
|
rect.set(
|
||||||
|
0f + strokePaint.strokeWidth / 2,
|
||||||
|
0f + strokePaint.strokeWidth / 2,
|
||||||
|
diameter,
|
||||||
|
diameter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) {
|
||||||
|
super.onDraw(canvas)
|
||||||
|
|
||||||
|
val totalWeight = items.asSequence().map { it.weight }.sum()
|
||||||
|
var startAngle = -90f
|
||||||
|
|
||||||
|
val shuffledColors = colors.shuffled()
|
||||||
|
items.forEachIndexed { index, (option, weight) ->
|
||||||
|
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
||||||
|
fillPaint.color = shuffledColors[index]
|
||||||
|
canvas.drawArc(rect, startAngle, sweepAngle, true, fillPaint)
|
||||||
|
|
||||||
|
drawOptionText(canvas, option, startAngle, sweepAngle)
|
||||||
|
startAngle += sweepAngle
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.drawCircle(rect.centerX(), rect.centerY(), rect.width() / 2, strokePaint)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawOptionText(
|
||||||
|
canvas: Canvas,
|
||||||
|
option: String,
|
||||||
|
startAngle: Float,
|
||||||
|
sweepAngle: Float
|
||||||
|
) {
|
||||||
|
val textRadius = rect.width() / 4 // Increase radius to move text outside the circle
|
||||||
|
val angle = Math.toRadians((startAngle + sweepAngle / 2).toDouble()).toFloat()
|
||||||
|
|
||||||
|
// Calculate the text position
|
||||||
|
val x = rect.centerX() + textRadius * cos(angle) + 10
|
||||||
|
val y = rect.centerY() + textRadius * sin(angle)
|
||||||
|
|
||||||
|
// Save the canvas state
|
||||||
|
val saveCount = canvas.save()
|
||||||
|
|
||||||
|
// Rotate the canvas around the text position
|
||||||
|
canvas.rotate(startAngle + sweepAngle / 2, x, y)
|
||||||
|
|
||||||
|
// Draw the text aligned with the segment
|
||||||
|
canvas.drawText(option, x, y, textPaint)
|
||||||
|
|
||||||
|
// Restore the canvas to its previous state
|
||||||
|
canvas.restoreToCount(saveCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAngleForOption(option: String): Float {
|
||||||
|
val totalWeight = items.asSequence().map { it.weight }.sum()
|
||||||
|
var startAngle = 0f
|
||||||
|
|
||||||
|
items.forEach { (currentOption, weight) ->
|
||||||
|
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
||||||
|
if (currentOption == option) {
|
||||||
|
// Return the midpoint angle of the segment
|
||||||
|
return (startAngle + sweepAngle / 2)
|
||||||
|
}
|
||||||
|
startAngle += sweepAngle
|
||||||
|
}
|
||||||
|
return 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rotateToOption(option: String, complete: () -> Unit) {
|
||||||
|
val targetAngle = 0 - (getAngleForOption(option) + 360 * 10)
|
||||||
|
|
||||||
|
val rotateAnimation = RotateAnimation(
|
||||||
|
0f, targetAngle,
|
||||||
|
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
|
||||||
|
RotateAnimation.RELATIVE_TO_SELF, 0.5f
|
||||||
|
)
|
||||||
|
rotateAnimation.duration = 2000
|
||||||
|
rotateAnimation.fillAfter = true
|
||||||
|
rotateAnimation.setAnimationListener(object : Animation.AnimationListener {
|
||||||
|
override fun onAnimationStart(animation: Animation?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAnimationEnd(animation: Animation?) {
|
||||||
|
complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAnimationRepeat(animation: Animation?) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
startAnimation(rotateAnimation)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class SpinRouletteRequest(
|
||||||
|
@SerializedName("roomId") val roomId: Long,
|
||||||
|
@SerializedName("container") val container: String = "aos"
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteItem
|
||||||
|
|
||||||
|
data class CreateOrUpdateRouletteRequest(
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("isActive") val isActive: Boolean,
|
||||||
|
@SerializedName("items") val items: List<RouletteItem>
|
||||||
|
)
|
|
@ -0,0 +1,38 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
interface RouletteApi {
|
||||||
|
@POST("/roulette")
|
||||||
|
fun createOrUpdateRoulette(
|
||||||
|
@Body request: CreateOrUpdateRouletteRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@GET("/roulette")
|
||||||
|
fun getRoulette(
|
||||||
|
@Query("creatorId") creatorId: Long,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetRouletteResponse>>
|
||||||
|
|
||||||
|
@POST("/roulette/spin")
|
||||||
|
fun spinRoulette(
|
||||||
|
@Body request: SpinRouletteRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetRouletteResponse>>
|
||||||
|
|
||||||
|
@POST("/roulette/refund/{id}")
|
||||||
|
fun refundRouletteDonation(
|
||||||
|
@Path("id") id: Long,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityRouletteConfigBinding
|
||||||
|
|
||||||
|
class RouletteConfigActivity : BaseActivity<ActivityRouletteConfigBinding>(
|
||||||
|
ActivityRouletteConfigBinding::inflate
|
||||||
|
) {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
changeFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
binding.toolbar.tvBack.text = "룰렛설정"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeFragment(tag: String = "settings") {
|
||||||
|
val fragmentManager = supportFragmentManager
|
||||||
|
val fragmentTransaction = fragmentManager.beginTransaction()
|
||||||
|
|
||||||
|
val currentFragment = fragmentManager.primaryNavigationFragment
|
||||||
|
if (currentFragment != null) {
|
||||||
|
fragmentTransaction.hide(currentFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
val fragment = RouletteSettingsFragment()
|
||||||
|
fragmentTransaction.add(R.id.container, fragment, tag)
|
||||||
|
fragmentTransaction.setPrimaryNavigationFragment(fragment)
|
||||||
|
fragmentTransaction.setReorderingAllowed(true)
|
||||||
|
fragmentTransaction.commitNow()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
data class RouletteOption(var title: String, var weight: Int, var percentage: String = "50.00")
|
|
@ -0,0 +1,188 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.text.InputFilter
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.jakewharton.rxbinding4.widget.textChanges
|
||||||
|
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.BaseFragment
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
|
FragmentRouletteSettingsBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: RouletteSettingsViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var imm: InputMethodManager
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupView()
|
||||||
|
bindData()
|
||||||
|
viewModel.getRoulette()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||||
|
imm = requireActivity().getSystemService(
|
||||||
|
Service.INPUT_METHOD_SERVICE
|
||||||
|
) as InputMethodManager
|
||||||
|
|
||||||
|
binding.etSetPrice.filters = arrayOf(InputFilter { source, start, end, _, _, _ ->
|
||||||
|
// Only allow numeric input
|
||||||
|
for (i in start until end) {
|
||||||
|
if (!Character.isDigit(source[i])) {
|
||||||
|
return@InputFilter ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
null
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.ivRouletteIsActive.setOnClickListener { viewModel.toggleIsActive() }
|
||||||
|
binding.ivAddOption.setOnClickListener { addOption() }
|
||||||
|
|
||||||
|
binding.tvPreview.setOnClickListener {
|
||||||
|
handler.postDelayed({
|
||||||
|
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||||
|
}, 100)
|
||||||
|
viewModel.onClickPreview()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvSave.setOnClickListener { _ ->
|
||||||
|
handler.postDelayed({
|
||||||
|
imm.hideSoftInputFromWindow(view?.windowToken, 0)
|
||||||
|
}, 100)
|
||||||
|
viewModel.createOrUpdateRoulette {
|
||||||
|
val resultIntent = Intent().apply { putExtra(Constants.EXTRA_RESULT_ROULETTE, it) }
|
||||||
|
requireActivity().setResult(Activity.RESULT_OK, resultIntent)
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.isActiveLiveData.observe(viewLifecycleOwner) {
|
||||||
|
binding.ivRouletteIsActive.setImageResource(
|
||||||
|
if (it) R.drawable.btn_toggle_on_big else R.drawable.btn_toggle_off_big
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.optionsLiveData.observe(viewLifecycleOwner) { updateOptionUi(it) }
|
||||||
|
|
||||||
|
viewModel.toastLiveData.observe(viewLifecycleOwner) { it?.let { showToast(it) } }
|
||||||
|
|
||||||
|
viewModel.canLiveData.observe(viewLifecycleOwner) {
|
||||||
|
if (it > 0) {
|
||||||
|
binding.etSetPrice.setText("$it")
|
||||||
|
} else {
|
||||||
|
binding.etSetPrice.setText("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
|
||||||
|
RoulettePreviewDialog(
|
||||||
|
activity = requireActivity(),
|
||||||
|
preview = it,
|
||||||
|
title = "룰렛 미리보기",
|
||||||
|
layoutInflater = layoutInflater
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
binding.etSetPrice.textChanges().skip(1)
|
||||||
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.subscribe {
|
||||||
|
if (it.trim().isNotEmpty()) {
|
||||||
|
viewModel.can = it.toString().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addOption() {
|
||||||
|
val newOption = RouletteOption("", 1)
|
||||||
|
viewModel.addOption(newOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateOptionUi(options: List<RouletteOption>) {
|
||||||
|
binding.llRouletteOptionContainer.removeAllViews()
|
||||||
|
options.forEachIndexed { index, option ->
|
||||||
|
binding.llRouletteOptionContainer.addView(createOptionView(index, option))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun createOptionView(index: Int, option: RouletteOption): View {
|
||||||
|
val optionView = LayoutInflater
|
||||||
|
.from(context)
|
||||||
|
.inflate(
|
||||||
|
R.layout.layout_roulette_option,
|
||||||
|
binding.llRouletteOptionContainer,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
val etOption = optionView.findViewById<EditText>(R.id.et_option)
|
||||||
|
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
|
||||||
|
val tvPercentage = optionView.findViewById<TextView>(R.id.tv_option_percentage)
|
||||||
|
val ivMinus = optionView.findViewById<ImageView>(R.id.iv_minus)
|
||||||
|
val ivPlus = optionView.findViewById<ImageView>(R.id.iv_plus)
|
||||||
|
val tvDelete = optionView.findViewById<TextView>(R.id.tv_delete)
|
||||||
|
|
||||||
|
etOption.setText(option.title)
|
||||||
|
tvOptionTitle.text = "옵션 ${index + 1}"
|
||||||
|
tvPercentage.text = "${option.percentage}%"
|
||||||
|
ivMinus.setOnClickListener { viewModel.subtractWeight(index) }
|
||||||
|
ivPlus.setOnClickListener { viewModel.plusWeight(index) }
|
||||||
|
|
||||||
|
if (index == 0 || index == 1) {
|
||||||
|
tvDelete.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
tvDelete.visibility = View.VISIBLE
|
||||||
|
tvDelete.setOnClickListener { viewModel.deleteOption(index) }
|
||||||
|
}
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
etOption.textChanges().skip(1)
|
||||||
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.subscribe {
|
||||||
|
viewModel.inputOption(index, it.toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return optionView
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,234 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteItem
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
||||||
|
import kotlin.math.floor
|
||||||
|
|
||||||
|
class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private val _optionsLiveData = MutableLiveData<List<RouletteOption>>(listOf())
|
||||||
|
val optionsLiveData: LiveData<List<RouletteOption>>
|
||||||
|
get() = _optionsLiveData
|
||||||
|
|
||||||
|
private val _isActiveLiveData = MutableLiveData(false)
|
||||||
|
val isActiveLiveData: LiveData<Boolean>
|
||||||
|
get() = _isActiveLiveData
|
||||||
|
|
||||||
|
private val _canLiveData = MutableLiveData(0)
|
||||||
|
val canLiveData: LiveData<Int>
|
||||||
|
get() = _canLiveData
|
||||||
|
|
||||||
|
private val _roulettePreviewLiveData = MutableLiveData<RoulettePreview>()
|
||||||
|
val roulettePreviewLiveData: LiveData<RoulettePreview>
|
||||||
|
get() = _roulettePreviewLiveData
|
||||||
|
|
||||||
|
private val options = mutableListOf<RouletteOption>()
|
||||||
|
var can = 0
|
||||||
|
var isActive = false
|
||||||
|
|
||||||
|
fun plusWeight(optionIndex: Int) {
|
||||||
|
val currentOption = options[optionIndex]
|
||||||
|
options[optionIndex] = currentOption.copy(weight = currentOption.weight + 1)
|
||||||
|
recalculatePercentages(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun subtractWeight(optionIndex: Int) {
|
||||||
|
if (options[optionIndex].weight > 1) {
|
||||||
|
val currentOption = options[optionIndex]
|
||||||
|
options[optionIndex] = currentOption.copy(weight = currentOption.weight - 1)
|
||||||
|
recalculatePercentages(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addOption(newOption: RouletteOption) {
|
||||||
|
if (options.size >= 10) return
|
||||||
|
|
||||||
|
options.add(newOption)
|
||||||
|
recalculatePercentages(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteOption(index: Int) {
|
||||||
|
val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
|
||||||
|
removeAllAndAddOptions(updatedOptions)
|
||||||
|
recalculatePercentages(updatedOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun inputOption(optionIndex: Int, title: String) {
|
||||||
|
val currentOption = options[optionIndex]
|
||||||
|
options[optionIndex] = currentOption.copy(title = title)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun recalculatePercentages(options: List<RouletteOption>) {
|
||||||
|
val totalWeight = options.sumOf { it.weight }
|
||||||
|
val updatedOptions = options.asSequence().map { option ->
|
||||||
|
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
||||||
|
option.copy(percentage = String.format("%.2f", percent))
|
||||||
|
}.toList()
|
||||||
|
|
||||||
|
removeAllAndAddOptions(updatedOptions)
|
||||||
|
_optionsLiveData.value = updatedOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toggleIsActive() {
|
||||||
|
isActive = !isActive
|
||||||
|
_isActiveLiveData.postValue(isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onClickPreview() {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val items = mutableListOf<RoulettePreviewItem>()
|
||||||
|
for (option in options) {
|
||||||
|
if (option.title.trim().isEmpty()) {
|
||||||
|
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||||
|
_isLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
|
||||||
|
}
|
||||||
|
|
||||||
|
_roulettePreviewLiveData.postValue(RoulettePreview(can, items))
|
||||||
|
_isLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createOrUpdateRoulette(onSuccess: (Boolean) -> Unit) {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
val items = mutableListOf<RouletteItem>()
|
||||||
|
for (option in options) {
|
||||||
|
if (option.title.trim().isEmpty()) {
|
||||||
|
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||||
|
_isLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
items.add(RouletteItem(title = option.title, weight = option.weight))
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = CreateOrUpdateRouletteRequest(
|
||||||
|
can = can,
|
||||||
|
isActive = isActive,
|
||||||
|
items = items
|
||||||
|
)
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.createOrUpdateRoulette(
|
||||||
|
request = request,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success && it.data != null && it.data is Boolean) {
|
||||||
|
val message = if (it.data) {
|
||||||
|
"룰렛을 활성화 했습니다."
|
||||||
|
} else {
|
||||||
|
"룰렛을 비활성화 했습니다."
|
||||||
|
}
|
||||||
|
_toastLiveData.postValue(message)
|
||||||
|
onSuccess(it.data)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRoulette() {
|
||||||
|
if (!_isLoading.value!!) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getRoulette(
|
||||||
|
creatorId = SharedPreferenceManager.userId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success) {
|
||||||
|
val data = it.data
|
||||||
|
|
||||||
|
if (data != null && data.items.isNotEmpty()) {
|
||||||
|
_isActiveLiveData.value = data.isActive
|
||||||
|
_canLiveData.value = data.can
|
||||||
|
|
||||||
|
isActive = data.isActive
|
||||||
|
can = data.can
|
||||||
|
|
||||||
|
val options = data.items.asSequence().map { item ->
|
||||||
|
RouletteOption(title = item.title, weight = item.weight)
|
||||||
|
}.toList()
|
||||||
|
removeAllAndAddOptions(options = options)
|
||||||
|
recalculatePercentages(options)
|
||||||
|
} else {
|
||||||
|
_isActiveLiveData.value = false
|
||||||
|
_canLiveData.value = 0
|
||||||
|
|
||||||
|
isActive = false
|
||||||
|
can = 0
|
||||||
|
|
||||||
|
options.add(RouletteOption(title = "", weight = 1))
|
||||||
|
options.add(RouletteOption(title = "", weight = 1))
|
||||||
|
recalculatePercentages(options)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun removeAllAndAddOptions(options: List<RouletteOption>) {
|
||||||
|
this.options.clear()
|
||||||
|
this.options.addAll(options)
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,8 +19,6 @@ 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 kr.co.pointclick.sdk.offerwall.core.PointClickAd
|
|
||||||
import kr.co.pointclick.sdk.offerwall.core.events.PackageReceiver
|
|
||||||
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
|
||||||
|
@ -52,11 +50,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
private val audioContentReceiver = AudioContentReceiver()
|
private val audioContentReceiver = AudioContentReceiver()
|
||||||
|
|
||||||
private var packageReceiver: PackageReceiver? = null
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
executeDeeplink()
|
executeDeeplink(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -67,14 +63,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||||
getMemberInfo()
|
getMemberInfo()
|
||||||
getEventPopup()
|
getEventPopup()
|
||||||
|
|
||||||
initPointClick()
|
handler.postDelayed({ executeDeeplink(intent) }, 500)
|
||||||
handler.postDelayed({ executeDeeplink() }, 500)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
|
val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
|
||||||
registerReceiver(audioContentReceiver, intentFilter)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
registerReceiver(audioContentReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
|
||||||
|
} else {
|
||||||
|
registerReceiver(audioContentReceiver, intentFilter)
|
||||||
|
}
|
||||||
|
|
||||||
startService(
|
startService(
|
||||||
Intent(this, AudioContentPlayService::class.java).apply {
|
Intent(this, AudioContentPlayService::class.java).apply {
|
||||||
|
@ -88,13 +87,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||||
super.onPause()
|
super.onPause()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
if (packageReceiver != null) {
|
|
||||||
applicationContext.unregisterReceiver(packageReceiver)
|
|
||||||
}
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupView() {
|
override fun setupView() {
|
||||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
liveFragment = LiveFragment()
|
liveFragment = LiveFragment()
|
||||||
|
@ -113,7 +105,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||||
setupBottomTabLayout()
|
setupBottomTabLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun executeDeeplink() {
|
private fun executeDeeplink(intent: Intent) {
|
||||||
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
|
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -374,25 +366,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPointClick() {
|
|
||||||
try {
|
|
||||||
val intentFilter = IntentFilter()
|
|
||||||
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
|
|
||||||
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
|
||||||
intentFilter.addDataScheme("package");
|
|
||||||
|
|
||||||
packageReceiver = PackageReceiver()
|
|
||||||
applicationContext.registerReceiver(packageReceiver, intentFilter)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
PointClickAd.init(
|
|
||||||
"fc07cfb1-ef16-455c-bdad-22aa9e8fd78c",
|
|
||||||
SharedPreferenceManager.userId.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class AudioContentReceiver : BroadcastReceiver() {
|
inner class AudioContentReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
||||||
|
|
|
@ -187,36 +187,36 @@ class TextMessageFragment : BaseFragment<FragmentTextMessageBinding>(
|
||||||
when (it) {
|
when (it) {
|
||||||
MessageBox.SENT -> {
|
MessageBox.SENT -> {
|
||||||
binding.tvSent.setBackgroundResource(
|
binding.tvSent.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvSent.setTextColor(
|
binding.tvSent.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.RECEIVE -> {
|
MessageBox.RECEIVE -> {
|
||||||
binding.tvReceive.setBackgroundResource(
|
binding.tvReceive.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvReceive.setTextColor(
|
binding.tvReceive.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.KEEP -> {
|
MessageBox.KEEP -> {
|
||||||
binding.tvKeep.setBackgroundResource(
|
binding.tvKeep.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvKeep.setTextColor(
|
binding.tvKeep.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ class TextMessageWriteActivity : BaseActivity<ActivityTextMessageWriteBinding>(
|
||||||
private fun bindData() {
|
private fun bindData() {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
binding.etMessage.textChanges().skip(1)
|
binding.etMessage.textChanges().skip(1)
|
||||||
.debounce(500, TimeUnit.MILLISECONDS)
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe {
|
.subscribe {
|
||||||
|
|
|
@ -313,36 +313,36 @@ class VoiceMessageFragment : BaseFragment<FragmentVoiceMessageBinding>(
|
||||||
when (it) {
|
when (it) {
|
||||||
MessageBox.SENT -> {
|
MessageBox.SENT -> {
|
||||||
binding.tvSent.setBackgroundResource(
|
binding.tvSent.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvSent.setTextColor(
|
binding.tvSent.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.RECEIVE -> {
|
MessageBox.RECEIVE -> {
|
||||||
binding.tvReceive.setBackgroundResource(
|
binding.tvReceive.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvReceive.setTextColor(
|
binding.tvReceive.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBox.KEEP -> {
|
MessageBox.KEEP -> {
|
||||||
binding.tvKeep.setBackgroundResource(
|
binding.tvKeep.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvKeep.setTextColor(
|
binding.tvKeep.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue