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"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 10
|
||||
versionName "1.1.0"
|
||||
versionCode 19
|
||||
versionName "1.4.1"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
@ -138,7 +138,7 @@ dependencies {
|
|||
implementation "io.github.bootpay:android:4.3.4"
|
||||
|
||||
// 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'
|
||||
|
||||
// sound visualizer
|
||||
|
@ -149,7 +149,4 @@ dependencies {
|
|||
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.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"
|
||||
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.INTERNET" />
|
||||
<uses-permission
|
||||
|
@ -85,6 +86,7 @@
|
|||
<activity android:name=".mypage.can.status.CanStatusActivity" />
|
||||
<activity android:name=".mypage.can.charge.CanChargeActivity" />
|
||||
<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.update.LiveRoomEditActivity" />
|
||||
<activity android:name=".live.reservation.complete.LiveReservationCompleteActivity" />
|
||||
|
@ -94,8 +96,10 @@
|
|||
<activity android:name=".explorer.profile.UserProfileActivity" />
|
||||
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
|
||||
<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.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.TextMessageDetailActivity" />
|
||||
<activity android:name=".message.SelectMessageRecipientActivity" />
|
||||
|
@ -124,6 +128,7 @@
|
|||
<activity android:name=".audio_content.curation.AudioContentCurationActivity" />
|
||||
<activity android:name=".audio_content.all.AudioContentNewAllActivity" />
|
||||
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
||||
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
|
||||
|
||||
<activity
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
|
@ -134,9 +139,13 @@
|
|||
|
||||
<service
|
||||
android:name=".common.SodaLiveService"
|
||||
android:foregroundServiceType="microphone|mediaPlayback"
|
||||
android:stopWithTask="false" />
|
||||
|
||||
<service android:name=".audio_content.AudioContentPlayService" />
|
||||
<service
|
||||
android:name=".audio_content.AudioContentPlayService"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
android:stopWithTask="false" />
|
||||
|
||||
<!-- [START firebase_service] -->
|
||||
<service
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||
import com.orhanobut.logger.AndroidLogAdapter
|
||||
import com.orhanobut.logger.Logger
|
||||
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.di.AppDI
|
||||
|
||||
|
@ -26,6 +27,8 @@ class SodaLiveApp : Application() {
|
|||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
|
||||
SharedPreferenceManager.init(applicationContext)
|
||||
|
||||
ImageLoaderProvider.init(applicationContext)
|
||||
}
|
||||
|
||||
private fun isDebuggable(): Boolean {
|
||||
|
|
|
@ -43,6 +43,7 @@ class AudioContentActivity : BaseActivity<ActivityAudioContentBinding>(
|
|||
) {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
viewModel.page = 1
|
||||
viewModel.isLast = false
|
||||
viewModel.getAudioContentList(userId = userId) { finish() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.audio_content
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
|
@ -33,6 +34,12 @@ class AudioContentAdapter(
|
|||
binding.tvLikeCount.text = item.likeCount.moneyFormat()
|
||||
binding.tvCommentCount.text = item.commentCount.moneyFormat()
|
||||
|
||||
binding.tvScheduledToOpen.visibility = if (item.isScheduledToOpen) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
|
||||
if (item.price < 1) {
|
||||
binding.tvPrice.text = "무료"
|
||||
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.PutAudioContentLikeResponse
|
||||
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.GetAudioContentMainResponse
|
||||
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.OrderRequest
|
||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
|
||||
|
@ -125,11 +127,6 @@ interface AudioContentApi {
|
|||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/audio-content/main")
|
||||
fun getMain(
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<GetAudioContentMainResponse>>
|
||||
|
||||
@GET("/audio-content/main/new")
|
||||
fun getNewContentOfTheme(
|
||||
@Query("theme") theme: String,
|
||||
|
@ -182,4 +179,26 @@ interface AudioContentApi {
|
|||
@Query("sort-type") sortType: String,
|
||||
@Header("Authorization") authHeader: String
|
||||
): 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
|
||||
) = api.likeContent(request, authHeader = token)
|
||||
|
||||
fun getMain(token: String) = api.getMain(authHeader = token)
|
||||
|
||||
fun getNewContentOfTheme(theme: String, token: String) = api.getNewContentOfTheme(
|
||||
theme = theme,
|
||||
authHeader = token
|
||||
|
@ -177,4 +175,17 @@ class AudioContentRepository(
|
|||
sortType = sortType,
|
||||
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
|
||||
}
|
||||
|
||||
private var isLast = false
|
||||
var isLast = false
|
||||
var page = 1
|
||||
private val size = 10
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import androidx.recyclerview.widget.GridLayoutManager
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
|
|
|
@ -9,7 +9,7 @@ import android.widget.Toast
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||
|
|
|
@ -44,27 +44,27 @@ class AudioContentCommentAdapter(
|
|||
binding.tvDonationCan.text = can.moneyFormat()
|
||||
binding.llDonationCan.setBackgroundResource(
|
||||
when {
|
||||
can >= 100000 -> {
|
||||
can >= 10000 -> {
|
||||
R.drawable.bg_round_corner_10_7_973a3a
|
||||
}
|
||||
|
||||
can >= 50000 -> {
|
||||
can >= 5000 -> {
|
||||
R.drawable.bg_round_corner_10_7_d85e37
|
||||
}
|
||||
|
||||
can >= 10000 -> {
|
||||
can >= 1000 -> {
|
||||
R.drawable.bg_round_corner_10_7_d38c38
|
||||
}
|
||||
|
||||
can >= 5000 -> {
|
||||
can >= 500 -> {
|
||||
R.drawable.bg_round_corner_10_7_59548f
|
||||
}
|
||||
|
||||
can >= 1000 -> {
|
||||
can >= 100 -> {
|
||||
R.drawable.bg_round_corner_10_7_4d6aa4
|
||||
}
|
||||
|
||||
can >= 500 -> {
|
||||
can >= 50 -> {
|
||||
R.drawable.bg_round_corner_10_7_2d7390
|
||||
}
|
||||
|
||||
|
|
|
@ -124,27 +124,27 @@ class AudioContentCommentReplyHeaderViewHolder(
|
|||
binding.tvDonationCan.text = can.moneyFormat()
|
||||
binding.llDonationCan.setBackgroundResource(
|
||||
when {
|
||||
can >= 100000 -> {
|
||||
can >= 10000 -> {
|
||||
R.drawable.bg_round_corner_10_7_973a3a
|
||||
}
|
||||
|
||||
can >= 50000 -> {
|
||||
can >= 5000 -> {
|
||||
R.drawable.bg_round_corner_10_7_d85e37
|
||||
}
|
||||
|
||||
can >= 10000 -> {
|
||||
can >= 1000 -> {
|
||||
R.drawable.bg_round_corner_10_7_d38c38
|
||||
}
|
||||
|
||||
can >= 5000 -> {
|
||||
can >= 500 -> {
|
||||
R.drawable.bg_round_corner_10_7_59548f
|
||||
}
|
||||
|
||||
can >= 1000 -> {
|
||||
can >= 100 -> {
|
||||
R.drawable.bg_round_corner_10_7_4d6aa4
|
||||
}
|
||||
|
||||
can >= 500 -> {
|
||||
can >= 50 -> {
|
||||
R.drawable.bg_round_corner_10_7_2d7390
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import android.widget.RelativeLayout
|
|||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
|
@ -60,10 +61,6 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
private var creatorId: Long = 0
|
||||
|
||||
private var refresh = false
|
||||
set(value) {
|
||||
field = value
|
||||
setResult(RESULT_OK)
|
||||
}
|
||||
private var title = ""
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
@ -97,7 +94,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
val intentFilter = IntentFilter(Constants.ACTION_AUDIO_CONTENT_RECEIVER)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(audioContentReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(audioContentReceiver, intentFilter)
|
||||
}
|
||||
|
||||
if (refresh) {
|
||||
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
||||
|
@ -283,6 +284,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
when (it.itemId) {
|
||||
R.id.menu_modify -> {
|
||||
refresh = true
|
||||
setResult(RESULT_OK)
|
||||
startActivity(
|
||||
Intent(applicationContext, AudioContentModifyActivity::class.java)
|
||||
.apply {
|
||||
|
@ -496,14 +498,30 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
}
|
||||
|
||||
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.existOrdered &&
|
||||
response.orderType == null &&
|
||||
response.creator.creatorId != SharedPreferenceManager.userId
|
||||
) {
|
||||
binding.tvReleaseDate.visibility = View.GONE
|
||||
binding.llPurchase.visibility = View.VISIBLE
|
||||
binding.llPurchasePrice.visibility = View.VISIBLE
|
||||
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) {
|
||||
" 대여하기"
|
||||
|
@ -529,15 +547,26 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
.apply(RequestOptions().override((screenWidth - 13.3f.dpToPx()).toInt()))
|
||||
.into(binding.ivCover)
|
||||
|
||||
if (
|
||||
response.releaseDate == null ||
|
||||
response.creator.creatorId == SharedPreferenceManager.userId
|
||||
) {
|
||||
binding.ivPlayOrPause.visibility = View.VISIBLE
|
||||
binding.ivPlayOrPause.setOnClickListener {
|
||||
startService(
|
||||
Intent(this, AudioContentPlayService::class.java).apply {
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL, response.coverImageUrl)
|
||||
putExtra(
|
||||
Constants.EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL,
|
||||
response.coverImageUrl
|
||||
)
|
||||
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_CREATOR_ID,
|
||||
response.creator.creatorId
|
||||
)
|
||||
putExtra(Constants.EXTRA_AUDIO_CONTENT_FREE, response.price <= 0)
|
||||
putExtra(
|
||||
Constants.EXTRA_AUDIO_CONTENT_PREVIEW,
|
||||
|
@ -546,12 +575,20 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
binding.ivPlayOrPause.visibility = View.GONE
|
||||
}
|
||||
|
||||
binding.tvTotalDuration.text = " / ${response.duration}"
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setupInfoArea(response: GetAudioContentDetailResponse) {
|
||||
binding.tvScheduledToOpen.visibility = if (response.releaseDate != null) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
binding.tvTheme.text = response.themeStr
|
||||
binding.tv19.visibility = if (response.isAdult) {
|
||||
View.VISIBLE
|
||||
|
|
|
@ -14,6 +14,7 @@ data class GetAudioContentDetailResponse(
|
|||
@SerializedName("tag") val tag: String,
|
||||
@SerializedName("price") val price: Int,
|
||||
@SerializedName("duration") val duration: String,
|
||||
@SerializedName("releaseDate") val releaseDate: String?,
|
||||
@SerializedName("isAdult") val isAdult: Boolean,
|
||||
@SerializedName("isMosaic") val isMosaic: Boolean,
|
||||
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
||||
|
|
|
@ -17,17 +17,26 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.zhpan.bannerview.BaseBannerAdapter
|
||||
import com.zhpan.indicator.enums.IndicatorSlideMode
|
||||
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.audio_content.all.AudioContentNewAllActivity
|
||||
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.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.upload.AudioContentUploadActivity
|
||||
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.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
|
@ -40,32 +49,37 @@ import kotlin.math.roundToInt
|
|||
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||
FragmentAudioContentMainBinding::inflate
|
||||
) {
|
||||
private val viewModel: AudioContentMainViewModel by inject()
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var imm: InputMethodManager
|
||||
|
||||
private val newContentCreatorViewModel: AudioContentMainNewContentCreatorViewModel by inject()
|
||||
private lateinit var newContentCreatorAdapter: AudioContentMainNewContentCreatorAdapter
|
||||
|
||||
private val bannerViewModel: AudioContentMainBannerViewModel by inject()
|
||||
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
||||
|
||||
private val orderListViewModel: AudioContentMainOrderListViewModel by inject()
|
||||
private lateinit var orderListAdapter: AudioContentMainContentAdapter
|
||||
|
||||
private val newContentViewModel: AudioContentMainNewContentViewModel by inject()
|
||||
private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter
|
||||
private lateinit var newContentAdapter: AudioContentMainContentAdapter
|
||||
|
||||
private val contentRankingViewModel: AudioContentMainRankingViewModel by inject()
|
||||
private lateinit var contentRankingSortAdapter: AudioContentMainNewContentThemeAdapter
|
||||
private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter
|
||||
|
||||
private val curationViewModel: AudioContentMainCurationViewModel by inject()
|
||||
private lateinit var curationAdapter: AudioContentMainCurationAdapter
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
loadingDialog = LoadingDialog(requireActivity(), layoutInflater)
|
||||
imm = requireContext().getSystemService(
|
||||
Service.INPUT_METHOD_SERVICE
|
||||
) as InputMethodManager
|
||||
|
||||
setupView()
|
||||
bindData()
|
||||
|
||||
viewModel.getMain()
|
||||
curationViewModel.getCurationList()
|
||||
bannerViewModel.getMainBannerList()
|
||||
newContentViewModel.getThemeList()
|
||||
newContentViewModel.getNewContentOfTheme("전체")
|
||||
contentRankingViewModel.getContentRanking()
|
||||
contentRankingViewModel.getContentRankingSortType()
|
||||
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
|
@ -94,11 +108,13 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
|
||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
viewModel.getMain()
|
||||
}
|
||||
|
||||
binding.ivCanFree.setOnClickListener {
|
||||
PointClickAd.showOfferwall(requireActivity(), "무료충전")
|
||||
curationViewModel.refresh()
|
||||
bannerViewModel.getMainBannerList()
|
||||
newContentViewModel.getThemeList()
|
||||
newContentViewModel.getNewContentOfTheme("전체")
|
||||
contentRankingViewModel.getContentRanking()
|
||||
contentRankingViewModel.getContentRankingSortType()
|
||||
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,6 +160,21 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
})
|
||||
|
||||
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() {
|
||||
|
@ -208,6 +239,21 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
)
|
||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.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() {
|
||||
|
@ -266,11 +312,26 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
binding.tvMyStashViewAll.setOnClickListener {
|
||||
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() {
|
||||
newContentThemeAdapter = AudioContentMainNewContentThemeAdapter {
|
||||
viewModel.getNewContentOfTheme(theme = it)
|
||||
newContentViewModel.getNewContentOfTheme(theme = it)
|
||||
}
|
||||
|
||||
binding.rvNewContentTheme.layoutManager = LinearLayoutManager(
|
||||
|
@ -308,6 +369,11 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
})
|
||||
|
||||
binding.rvNewContentTheme.adapter = newContentThemeAdapter
|
||||
|
||||
newContentViewModel.themeListLiveData.observe(viewLifecycleOwner) {
|
||||
binding.llNewContent.visibility = View.VISIBLE
|
||||
newContentThemeAdapter.addItems(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNewContent() {
|
||||
|
@ -367,11 +433,27 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
})
|
||||
|
||||
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() {
|
||||
contentRankingSortAdapter = AudioContentMainNewContentThemeAdapter {
|
||||
viewModel.getContentRanking(sort = it)
|
||||
contentRankingViewModel.getContentRanking(sort = it)
|
||||
}
|
||||
|
||||
binding.rvContentRankingSort.layoutManager = LinearLayoutManager(
|
||||
|
@ -409,8 +491,14 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
})
|
||||
|
||||
binding.rvContentRankingSort.adapter = contentRankingSortAdapter
|
||||
|
||||
contentRankingViewModel.contentRankingSortListLiveData.observe(viewLifecycleOwner) {
|
||||
binding.llContentRanking.visibility = View.VISIBLE
|
||||
contentRankingSortAdapter.addItems(it)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setupContentRanking() {
|
||||
binding.ivContentRankingAll.setOnClickListener {
|
||||
startActivity(Intent(requireContext(), AudioContentRankingAllActivity::class.java))
|
||||
|
@ -449,6 +537,16 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
})
|
||||
|
||||
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() {
|
||||
|
@ -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
|
||||
|
||||
curationViewModel.curationListLiveData.observe(viewLifecycleOwner) {
|
||||
if (curationViewModel.page == 2) {
|
||||
curationAdapter.clear()
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
viewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
curationAdapter.addItems(it)
|
||||
|
||||
binding.rvCuration.visibility = if (curationAdapter.itemCount <= 0 && it.isEmpty()) {
|
||||
View.GONE
|
||||
} else {
|
||||
loadingDialog.dismiss()
|
||||
View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
curationViewModel.isLoading.observe(viewLifecycleOwner) {
|
||||
binding.pbCuration.visibility = if (it) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
curationViewModel.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)
|
||||
binding.rvCuration.visibility = if (
|
||||
curationAdapter.itemCount <= 0 && it.isEmpty()
|
||||
) {
|
||||
View.GONE
|
||||
} else {
|
||||
View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.contentRankingSortListLiveData.observe(viewLifecycleOwner) {
|
||||
binding.llContentRanking.visibility = View.VISIBLE
|
||||
contentRankingSortAdapter.addItems(it)
|
||||
}
|
||||
|
||||
viewModel.contentRankingLiveData.observe(viewLifecycleOwner) {
|
||||
binding.llContentRanking.visibility = View.VISIBLE
|
||||
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 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(
|
||||
@SerializedName("creatorId") val creatorId: Long,
|
||||
@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.graphics.Bitmap
|
||||
|
@ -11,6 +11,7 @@ import com.bumptech.glide.request.transition.Transition
|
|||
import com.zhpan.bannerview.BaseBannerAdapter
|
||||
import com.zhpan.bannerview.BaseViewHolder
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentBannerResponse
|
||||
|
||||
class AudioContentMainBannerAdapter(
|
||||
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.content.Context
|
||||
|
@ -8,6 +8,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.extensions.dpToPx
|
||||
|
||||
|
@ -89,8 +92,11 @@ class AudioContentMainCurationAdapter(
|
|||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun addItems(items: List<GetAudioContentCurationResponse>) {
|
||||
this.items.clear()
|
||||
this.items.addAll(items)
|
||||
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.content.Context
|
||||
|
@ -28,9 +28,9 @@ class AudioContentMainNewContentThemeAdapter(
|
|||
(selectedTheme == "" && theme == "매출")
|
||||
) {
|
||||
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 {
|
||||
binding.tvTheme.setBackgroundResource(
|
||||
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.view.LayoutInflater
|
||||
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetNewContentUploadCreator
|
||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainNewContentCreatorBinding
|
||||
|
||||
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.view.LayoutInflater
|
||||
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
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.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.annotation.SuppressLint
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
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.databinding.ActivityAudioContentUploadBinding
|
||||
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 org.koin.android.ext.android.inject
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBinding>(
|
||||
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?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
checkPermissions()
|
||||
|
@ -173,6 +201,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
binding.llOnlyRental.setOnClickListener { viewModel.setIsOnlyRental(true) }
|
||||
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
|
||||
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
|
||||
binding.llActiveNow.setOnClickListener { viewModel.setActiveReservation(false) }
|
||||
binding.llActiveReservation.setOnClickListener { viewModel.setActiveReservation(true) }
|
||||
|
||||
binding.tvCancel.setOnClickListener { finish() }
|
||||
binding.tvUpload.setOnClickListener {
|
||||
|
@ -189,6 +219,71 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
).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() {
|
||||
|
@ -323,17 +418,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
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.tvCommentNo.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
binding.llCommentNo.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
||||
R.drawable.bg_round_corner_6_7_13181b
|
||||
)
|
||||
} else {
|
||||
binding.ivCommentNo.visibility = View.VISIBLE
|
||||
|
@ -343,17 +438,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
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.tvCommentYes.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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) {
|
||||
if (it) {
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
|
@ -387,16 +482,16 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
)
|
||||
} else {
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
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() {
|
||||
|
@ -422,17 +580,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
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.tvPricePaid.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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
|
||||
|
@ -450,17 +608,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
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.tvPriceFree.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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
|
||||
}
|
||||
|
@ -474,17 +632,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
|
|||
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.tvOnlyRental.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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
|
||||
)
|
||||
)
|
||||
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.tvRentalAndKeep.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
|
||||
class AudioContentUploadViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
|
@ -49,12 +50,26 @@ class AudioContentUploadViewModel(
|
|||
val isPriceFreeLiveData: LiveData<Boolean>
|
||||
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?
|
||||
|
||||
var title = ""
|
||||
var detail = ""
|
||||
var tags = ""
|
||||
var price = 0
|
||||
var releaseDate = ""
|
||||
var releaseTime = ""
|
||||
var theme: GetAudioContentThemeResponse? = null
|
||||
var coverImageUri: Uri? = null
|
||||
var contentUri: Uri? = null
|
||||
|
@ -81,6 +96,10 @@ class AudioContentUploadViewModel(
|
|||
_isOnlyRentalLiveData.postValue(isOnlyRental)
|
||||
}
|
||||
|
||||
fun setActiveReservation(isActiveReservation: Boolean) {
|
||||
_isActiveReservationLiveData.postValue(isActiveReservation)
|
||||
}
|
||||
|
||||
fun uploadAudioContent(onSuccess: () -> Unit) {
|
||||
if (!_isLoading.value!! && validateData()) {
|
||||
_isLoading.postValue(true)
|
||||
|
@ -90,6 +109,12 @@ class AudioContentUploadViewModel(
|
|||
detail = detail,
|
||||
tags = tags,
|
||||
price = price,
|
||||
releaseDate = if (_isActiveReservationLiveData.value!!) {
|
||||
"$releaseDate $releaseTime"
|
||||
} else {
|
||||
null
|
||||
},
|
||||
timezone = TimeZone.getDefault().id,
|
||||
themeId = theme!!.id,
|
||||
isAdult = _isAdultLiveData.value!!,
|
||||
isOnlyRental = _isOnlyRentalLiveData.value!!,
|
||||
|
@ -281,6 +306,14 @@ class AudioContentUploadViewModel(
|
|||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
_isActiveReservationLiveData.value!! &&
|
||||
(releaseDate.isBlank() || releaseTime.isBlank())
|
||||
) {
|
||||
_toastLiveData.postValue("예약날짜와 시간을 선택해주세요.")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -307,4 +340,12 @@ class AudioContentUploadViewModel(
|
|||
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("tags") val tags: String,
|
||||
@SerializedName("price") val price: Int,
|
||||
@SerializedName("releaseDate") val releaseDate: String?,
|
||||
@SerializedName("timezone") val timezone: String,
|
||||
@SerializedName("themeId") val themeId: Long,
|
||||
@SerializedName("isAdult") val isAdult: Boolean,
|
||||
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
|
||||
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
|
||||
@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_TEXT_MESSAGE = "extra_text_message"
|
||||
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_SELECT_RECIPIENT = "extra_select_recipient"
|
||||
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 ACTION_AUDIO_CONTENT_RECEIVER = "soda_live_action_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.curation.AudioContentCurationViewModel
|
||||
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.order.AudioContentOrderListViewModel
|
||||
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.ExplorerViewModel
|
||||
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.fantalk.UserProfileFantalkAllViewModel
|
||||
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.LiveTagViewModel
|
||||
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.message.MessageApi
|
||||
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.CanRepository
|
||||
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.status.CanStatusViewModel
|
||||
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(), FaqApi::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 {
|
||||
|
@ -153,7 +170,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { TermsViewModel(get()) }
|
||||
viewModel { FindPasswordViewModel(get()) }
|
||||
viewModel { MainViewModel(get(), get(), get(), get()) }
|
||||
viewModel { LiveViewModel(get(), get(), get()) }
|
||||
viewModel { LiveViewModel(get(), get(), get(), get()) }
|
||||
viewModel { MyPageViewModel(get(), get()) }
|
||||
viewModel { CanStatusViewModel(get()) }
|
||||
viewModel { CanChargeViewModel(get()) }
|
||||
|
@ -162,7 +179,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { LiveRoomCreateViewModel(get()) }
|
||||
viewModel { LiveTagViewModel(get()) }
|
||||
viewModel { LiveRoomEditViewModel(get()) }
|
||||
viewModel { LiveRoomViewModel(get(), get(), get()) }
|
||||
viewModel { LiveRoomViewModel(get(), get(), get(), get()) }
|
||||
viewModel { LiveRoomDonationMessageViewModel(get()) }
|
||||
viewModel { ExplorerViewModel(get()) }
|
||||
viewModel { UserProfileViewModel(get(), get(), get()) }
|
||||
|
@ -179,7 +196,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { SettingsViewModel(get()) }
|
||||
viewModel { TextMessageDetailViewModel(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 { AudioContentOrderListViewModel(get()) }
|
||||
viewModel { AudioContentUploadViewModel(get()) }
|
||||
|
@ -197,6 +219,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { AudioContentCurationViewModel(get()) }
|
||||
viewModel { AudioContentNewAllViewModel(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 {
|
||||
|
@ -219,6 +247,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
factory { FaqRepository(get()) }
|
||||
factory { MemberTagRepository(get()) }
|
||||
factory { UserProfileFantalkAllViewModel(get(), get()) }
|
||||
factory { RouletteRepository(get()) }
|
||||
factory { CreatorCommunityRepository(get()) }
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||
|
||||
data class GetCreatorProfileResponse(
|
||||
@SerializedName("creator")
|
||||
val creator: CreatorResponse,
|
||||
@SerializedName("userDonationRanking")
|
||||
val userDonationRanking: List<UserDonationRankingResponse>,
|
||||
@SerializedName("similarCreatorList")
|
||||
val similarCreatorList: List<SimilarCreatorResponse>,
|
||||
@SerializedName("liveRoomList")
|
||||
val liveRoomList: List<LiveRoomResponse>,
|
||||
@SerializedName("contentList")
|
||||
val contentList: List<GetAudioContentListItem>,
|
||||
@SerializedName("notice")
|
||||
val notice: String,
|
||||
@SerializedName("communityPostList")
|
||||
val communityPostList: List<GetCommunityPostListResponse>,
|
||||
@SerializedName("cheers")
|
||||
val cheers: GetCheersResponse,
|
||||
@SerializedName("activitySummary")
|
||||
|
@ -45,13 +46,6 @@ data class UserDonationRankingResponse(
|
|||
@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(
|
||||
@SerializedName("roomId") val roomId: Long,
|
||||
@SerializedName("title") val title: String,
|
||||
|
@ -82,7 +76,8 @@ data class GetAudioContentListItem(
|
|||
@SerializedName("duration") val duration: String?,
|
||||
@SerializedName("likeCount") val likeCount: Int,
|
||||
@SerializedName("commentCount") val commentCount: Int,
|
||||
@SerializedName("isAdult") val isAdult: Boolean
|
||||
@SerializedName("isAdult") val isAdult: Boolean,
|
||||
@SerializedName("isScheduledToOpen") val isScheduledToOpen: Boolean
|
||||
)
|
||||
|
||||
data class GetCreatorActivitySummary(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package kr.co.vividnext.sodalive.explorer.profile
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
|
@ -11,17 +10,18 @@ import android.net.Uri
|
|||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.webkit.URLUtil
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
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.audio_content.AudioContentActivity
|
||||
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.SharedPreferenceManager
|
||||
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.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.UserProfileDonationAllViewActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
||||
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.live.LiveViewModel
|
||||
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.UserReportDialog
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||
ActivityUserProfileBinding::inflate
|
||||
|
@ -63,11 +71,8 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
private lateinit var liveAdapter: UserProfileLiveAdapter
|
||||
private lateinit var audioContentAdapter: AudioContentAdapter
|
||||
private lateinit var donationAdapter: UserProfileDonationAdapter
|
||||
private lateinit var similarCreatorAdapter: UserProfileSimilarCreatorAdapter
|
||||
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
||||
|
||||
private lateinit var noticeWriteLauncher: ActivityResultLauncher<Intent>
|
||||
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private var userId: Long = 0
|
||||
|
||||
|
@ -76,17 +81,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
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) {
|
||||
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||
finish()
|
||||
|
@ -122,9 +116,9 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
|
||||
setupLiveView()
|
||||
setupDonationView()
|
||||
setupSimilarCreatorView()
|
||||
setupFanTalkView()
|
||||
setupAudioContentListView()
|
||||
setupCreatorCommunityView()
|
||||
}
|
||||
|
||||
private fun hideKeyboard(onAfterExecute: () -> Unit) {
|
||||
|
@ -310,51 +304,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
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() {
|
||||
binding.layoutUserProfileFanTalk.tvAll.setOnClickListener {
|
||||
val intent = Intent(
|
||||
|
@ -528,6 +477,19 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
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() {
|
||||
liveViewModel.toastLiveData.observe(this) {
|
||||
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||
|
@ -556,20 +518,11 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
viewModel.creatorProfileLiveData.observe(this) {
|
||||
setCheers(it.cheers)
|
||||
setCreatorProfile(it.creator)
|
||||
setCreatorNotice(it.notice, it.creator.creatorId)
|
||||
setAudioContentList(it.contentList)
|
||||
setLiveRoomList(it.liveRoomList)
|
||||
setSimilarCreatorList(it.similarCreatorList)
|
||||
setUserDonationRanking(it.userDonationRanking)
|
||||
setActivitySummary(it.activitySummary)
|
||||
}
|
||||
|
||||
viewModel.isExpandNotice.observe(this) {
|
||||
if (it) {
|
||||
binding.tvNotice.maxLines = Int.MAX_VALUE
|
||||
} else {
|
||||
binding.tvNotice.maxLines = 1
|
||||
}
|
||||
setCommunityPostList(it.communityPostList)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,28 +637,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
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")
|
||||
private fun setAudioContentList(audioContentList: List<GetAudioContentListItem>) {
|
||||
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")
|
||||
private fun setUserDonationRanking(userDonationRanking: List<UserDonationRankingResponse>) {
|
||||
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) {
|
||||
liveViewModel.getRoomDetail(roomId) {
|
||||
if (it.manager.id == SharedPreferenceManager.userId) {
|
||||
|
@ -850,6 +851,15 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
}
|
||||
} 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) {
|
||||
LiveRoomPasswordDialog(
|
||||
activity = this,
|
||||
|
@ -867,8 +877,23 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
LivePaymentDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "${it.price.moneyFormat()}캔으로 입장",
|
||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
||||
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 = "결제 후 입장",
|
||||
confirmButtonClick = {
|
||||
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.explorer.ExplorerRepository
|
||||
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.ReportRequest
|
||||
import kr.co.vividnext.sodalive.report.ReportType
|
||||
|
@ -38,10 +39,6 @@ class UserProfileViewModel(
|
|||
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
|
||||
get() = _creatorProfileLiveData
|
||||
|
||||
private val _isExpandNotice = MutableLiveData(false)
|
||||
val isExpandNotice: LiveData<Boolean>
|
||||
get() = _isExpandNotice
|
||||
|
||||
private var creatorNickname = ""
|
||||
|
||||
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) {
|
||||
if (cheersContent.isBlank()) {
|
||||
_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("tags") val tags: List<String>,
|
||||
@SerializedName("channelName") val channelName: String?,
|
||||
@SerializedName("creatorProfileImage") val creatorProfileImage: String,
|
||||
@SerializedName("creatorNickname") val creatorNickname: String,
|
||||
@SerializedName("creatorId") val creatorId: Long,
|
||||
@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.databinding.FragmentLiveBinding
|
||||
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.moneyFormat
|
||||
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.notification.MemberRole
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::inflate) {
|
||||
|
@ -56,6 +61,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
|
||||
private lateinit var liveNowAdapter: LiveNowAdapter
|
||||
private lateinit var liveReservationAdapter: LiveReservationAdapter
|
||||
private lateinit var creatorCommunityAdapter: CreatorCommunityAdapter
|
||||
private lateinit var liveRecommendChannelAdapter: LiveRecommendChannelAdapter
|
||||
|
||||
private lateinit var loadingDialog: LoadingDialog
|
||||
|
@ -91,6 +97,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
setupLiveNow()
|
||||
setupLiveReservation()
|
||||
setupEvent()
|
||||
setupCommunityPost()
|
||||
|
||||
message = "라이브를 불러오고 있습니다."
|
||||
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) {
|
||||
val onEnterRoomSuccess = {
|
||||
viewModel.getSummary()
|
||||
|
@ -629,6 +698,15 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
}, 300)
|
||||
}
|
||||
} 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) {
|
||||
LiveRoomPasswordDialog(
|
||||
activity = requireActivity(),
|
||||
|
@ -648,8 +726,23 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
LivePaymentDialog(
|
||||
activity = requireActivity(),
|
||||
layoutInflater = layoutInflater,
|
||||
title = "${it.price.moneyFormat()}캔으로 입장",
|
||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
||||
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 = "결제 후 입장",
|
||||
confirmButtonClick = {
|
||||
handler.postDelayed({
|
||||
|
|
|
@ -8,6 +8,8 @@ import io.reactivex.rxjava3.core.Flowable
|
|||
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.live.recommend.GetRecommendLiveResponse
|
||||
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
|
||||
import kr.co.vividnext.sodalive.live.recommend_channel.GetRecommendChannelResponse
|
||||
|
@ -24,7 +26,8 @@ import kr.co.vividnext.sodalive.settings.event.EventRepository
|
|||
class LiveViewModel(
|
||||
private val repository: LiveRepository,
|
||||
private val eventRepository: EventRepository,
|
||||
private val liveRecommendRepository: LiveRecommendRepository
|
||||
private val liveRecommendRepository: LiveRecommendRepository,
|
||||
private val creatorCommunityRepository: CreatorCommunityRepository
|
||||
) : BaseViewModel() {
|
||||
private var _isLoading = MutableLiveData(false)
|
||||
val isLoading: LiveData<Boolean>
|
||||
|
@ -60,6 +63,10 @@ class LiveViewModel(
|
|||
val eventLiveData: LiveData<List<EventItem>>
|
||||
get() = _eventLiveData
|
||||
|
||||
private val _communityPostItemLiveData = MutableLiveData<List<GetCommunityPostListResponse>>()
|
||||
val communityPostItemLiveData: LiveData<List<GetCommunityPostListResponse>>
|
||||
get() = _communityPostItemLiveData
|
||||
|
||||
var page = 1
|
||||
var isLast = false
|
||||
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() {
|
||||
if (!_isLoading.value!!) {
|
||||
if (_isFollowedCreatorLive.value!!) {
|
||||
|
@ -142,6 +179,7 @@ class LiveViewModel(
|
|||
} else {
|
||||
getRecommendChannelList()
|
||||
}
|
||||
getLatestPostListFromCreatorsYouFollow()
|
||||
|
||||
val liveNow = repository.roomList(
|
||||
status = LiveRoomStatus.NOW,
|
||||
|
|
|
@ -5,11 +5,12 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.databinding.ItemLiveNowBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import kr.co.vividnext.sodalive.live.GetRoomListResponse
|
||||
|
||||
class LiveNowAdapter(
|
||||
|
@ -23,13 +24,11 @@ class LiveNowAdapter(
|
|||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: GetRoomListResponse) {
|
||||
binding.ivCover.load(item.coverImageUrl) {
|
||||
binding.ivCover.loadUrl(item.coverImageUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
|
||||
}
|
||||
binding.tvManager.text = item.creatorNickname
|
||||
binding.tvNumberOfMembers.text = "${item.numberOfParticipate}"
|
||||
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
|
@ -44,6 +43,21 @@ class LiveNowAdapter(
|
|||
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) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.LiveRoomPasswordDialog
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
||||
ActivityLiveNowAllBinding::inflate
|
||||
|
@ -157,6 +160,15 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
|||
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
}
|
||||
} 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) {
|
||||
LiveRoomPasswordDialog(
|
||||
activity = this,
|
||||
|
@ -174,8 +186,23 @@ class LiveNowAllActivity : BaseActivity<ActivityLiveNowAllBinding>(
|
|||
LivePaymentDialog(
|
||||
activity = this,
|
||||
layoutInflater = layoutInflater,
|
||||
title = "${it.price.moneyFormat()} 캔으로 입장",
|
||||
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
|
||||
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 = "결제 후 입장",
|
||||
confirmButtonClick = {
|
||||
viewModel.enterRoom(roomId, onEnterRoomSuccess)
|
||||
|
|
|
@ -34,8 +34,6 @@ class LiveNowAllAdapter(
|
|||
}
|
||||
binding.tvNickname.text = item.creatorNickname
|
||||
binding.tvTitle.text = item.title
|
||||
binding.tvTotal.text = "/${item.numberOfPeople}"
|
||||
binding.tvNumberOfParticipants.text = item.numberOfParticipate.toString()
|
||||
binding.ivLock.visibility = if (item.isPrivateRoom) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
|
@ -47,7 +45,7 @@ class LiveNowAllAdapter(
|
|||
binding.tvAvailableParticipate.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -26,8 +26,8 @@ import android.widget.Toast
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.dialog.LiveDialog
|
||||
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.live.room.chat.LiveRoomChatAdapter
|
||||
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.LiveRoomJoinChat
|
||||
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.LiveRoomDonationMessageDialog
|
||||
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.LiveRoomUserProfileDialog
|
||||
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.ReportType
|
||||
import kr.co.vividnext.sodalive.report.UserReportDialog
|
||||
|
@ -106,7 +111,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
private var isSpeakerMute = false
|
||||
private var isMicrophoneMute = false
|
||||
private var isSpeaker = false
|
||||
private var isSpeakerFold = false
|
||||
|
||||
private var isNoChatting = false
|
||||
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?) {
|
||||
agora = Agora(
|
||||
context = this,
|
||||
|
@ -328,8 +353,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
isStaff = {
|
||||
viewModel.isEqualToManagerId(it.toInt())
|
||||
},
|
||||
onClickSendMessage = { userId, nickname ->
|
||||
},
|
||||
onClickSetManager = {
|
||||
setManagerMessageToPeer(userId = it)
|
||||
viewModel.setManager(roomId = roomId, userId = it) {
|
||||
|
@ -430,33 +453,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
|
||||
dialog.show(screenWidth)
|
||||
}
|
||||
binding.ivNotification.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.tvNotification.setOnClickListener { viewModel.toggleShowNotice() }
|
||||
|
||||
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
||||
binding.llDonation.setOnClickListener {
|
||||
|
@ -551,9 +548,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
dialog.setPositiveButton("차단") { _, _ ->
|
||||
roomUserProfileDialog.dismiss()
|
||||
viewModel.memberBlock(userId) {
|
||||
if (viewModel.roomInfoResponse.creatorId == SharedPreferenceManager.userId) {
|
||||
kickOut(userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.setNegativeButton("취소") { _, _ -> }
|
||||
dialog.show()
|
||||
}
|
||||
|
@ -596,11 +595,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
binding.tvBgSwitch.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
binding.tvBgSwitch
|
||||
.setBackgroundResource(R.drawable.bg_round_corner_13_3_transparent_9970ff)
|
||||
.setBackgroundResource(R.drawable.bg_round_corner_5_3_transparent_3bb9f1)
|
||||
} else {
|
||||
binding.ivCover.visibility = View.GONE
|
||||
binding.tvBgSwitch.text = "배경 OFF"
|
||||
|
@ -611,7 +610,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
)
|
||||
)
|
||||
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.ivCover.load(response.coverImageUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
}
|
||||
|
||||
binding.flDonation.visibility =
|
||||
if (response.creatorId != SharedPreferenceManager.userId) {
|
||||
|
@ -693,7 +688,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
}
|
||||
|
||||
speakerListAdapter.managerId = response.creatorId
|
||||
speakerListAdapter.updateList(response.speakerList)
|
||||
speakerListAdapter.updateList(
|
||||
response.speakerList.filter {
|
||||
it.id != response.creatorId
|
||||
}
|
||||
)
|
||||
|
||||
if (response.creatorId == SharedPreferenceManager.userId) {
|
||||
binding.ivEdit.setOnClickListener {
|
||||
|
@ -710,10 +709,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
setNoticeAndClickableUrl(binding.tvNotice, newContent)
|
||||
|
||||
if (newCoverImageUri != null) {
|
||||
binding.ivCover.load(newCoverImageUri) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
}
|
||||
binding.ivCover.load(newCoverImageUri)
|
||||
}
|
||||
|
||||
agora.sendRawMessageToGroup(
|
||||
|
@ -770,7 +766,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
setNoticeAndClickableUrl(binding.tvNotice, response.notice)
|
||||
|
||||
binding.tvCreatorNickname.text = response.creatorNickname
|
||||
binding.ivCreatorProfile.load(response.creatorProfileUrl) {
|
||||
binding.ivCreatorProfile.loadUrl(response.creatorProfileUrl) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(CircleCropTransformation())
|
||||
|
@ -785,7 +781,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
if (response.creatorId != SharedPreferenceManager.userId) {
|
||||
binding.ivCreatorFollow.visibility = View.VISIBLE
|
||||
if (response.isFollowing) {
|
||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_following)
|
||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_select_checked)
|
||||
binding.ivCreatorFollow.setOnClickListener {
|
||||
viewModel.creatorUnFollow(
|
||||
creatorId = response.creatorId,
|
||||
|
@ -793,7 +789,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
)
|
||||
}
|
||||
} else {
|
||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_follow)
|
||||
binding.ivCreatorFollow.setImageResource(R.drawable.btn_plus_round)
|
||||
binding.ivCreatorFollow.setOnClickListener {
|
||||
viewModel.creatorFollow(
|
||||
creatorId = response.creatorId,
|
||||
|
@ -805,6 +801,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
binding.ivCreatorFollow.visibility = View.GONE
|
||||
}
|
||||
|
||||
initRouletteSettingButton(isHost = response.creatorId == SharedPreferenceManager.userId)
|
||||
activatingRouletteButton(
|
||||
isHost = response.creatorId == SharedPreferenceManager.userId,
|
||||
isActiveRoulette = response.isActiveRoulette
|
||||
)
|
||||
|
||||
if (agora.rtmChannelIsNull()) {
|
||||
joinChannel(response)
|
||||
}
|
||||
|
@ -812,25 +814,74 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
|
||||
viewModel.isShowNotice.observe(this) {
|
||||
if (it) {
|
||||
binding.ivNotification.setImageResource(R.drawable.ic_notice_selected)
|
||||
binding.rlNotice.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.ivNotification.setImageResource(R.drawable.ic_notice_normal)
|
||||
binding.rlNotice.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
binding.tvNotification.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
binding.tvNotification.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_5_3_transparent_3bb9f1
|
||||
)
|
||||
|
||||
viewModel.isExpandNotice.observe(this) {
|
||||
binding.tvNotice.maxLines = if (it) {
|
||||
Int.MAX_VALUE
|
||||
binding.llNotice.visibility = View.VISIBLE
|
||||
} 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) {
|
||||
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) {
|
||||
|
@ -937,7 +988,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
val rvSpeakers = binding.rvSpeakers
|
||||
speakerListAdapter = LiveRoomProfileListAdapter()
|
||||
|
||||
rvSpeakers.layoutManager = GridLayoutManager(applicationContext, 5)
|
||||
rvSpeakers.layoutManager = LinearLayoutManager(
|
||||
applicationContext,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
rvSpeakers.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
|
@ -947,8 +1002,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
) {
|
||||
super.getItemOffsets(outRect, view, parent, state)
|
||||
|
||||
outRect.top = 5f.dpToPx().toInt()
|
||||
outRect.bottom = 5f.dpToPx().toInt()
|
||||
outRect.left = 4f.dpToPx().toInt()
|
||||
outRect.right = 4f.dpToPx().toInt()
|
||||
}
|
||||
})
|
||||
rvSpeakers.adapter = speakerListAdapter
|
||||
|
@ -1090,12 +1145,16 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
isMicrophoneMute = !isMicrophoneMute
|
||||
agora.muteLocalAudioStream(isMicrophoneMute)
|
||||
|
||||
if (SharedPreferenceManager.userId == viewModel.roomInfoResponse.creatorId) {
|
||||
setMuteSpeakerCreator(isMicrophoneMute)
|
||||
} else {
|
||||
if (isMicrophoneMute) {
|
||||
speakerListAdapter.muteSpeakers.add(SharedPreferenceManager.userId.toInt())
|
||||
} else {
|
||||
speakerListAdapter.muteSpeakers.remove(SharedPreferenceManager.userId.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun speakerMute() {
|
||||
isSpeakerMute = !isSpeakerMute
|
||||
|
@ -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) {
|
||||
loadingDialog.show(width = screenWidth, message = "라이브에 입장하고 있습니다.")
|
||||
|
||||
|
@ -1261,6 +1360,31 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
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 {
|
||||
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() {
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onAudioVolumeIndication(
|
||||
|
@ -1345,6 +1477,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
totalVolume: Int
|
||||
) {
|
||||
super.onAudioVolumeIndication(speakers, totalVolume)
|
||||
|
||||
Logger.e("onAudioVolumeIndication - $speakers")
|
||||
|
||||
val activeSpeakerIds = speakers
|
||||
.asSequence()
|
||||
.filter { it.volume > 0 }
|
||||
|
@ -1353,13 +1488,17 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
|
||||
Logger.e("onAudioVolumeIndication - $activeSpeakerIds")
|
||||
handler.post {
|
||||
if (!activeSpeakerIds.contains(0)) {
|
||||
speakerListAdapter.activeSpeakers.clear()
|
||||
speakerListAdapter.activeSpeakers.addAll(activeSpeakerIds)
|
||||
|
||||
if (activeSpeakerIds.contains(0) && !isMicrophoneMute) {
|
||||
speakerListAdapter.activeSpeakers.add(SharedPreferenceManager.userId.toInt())
|
||||
}
|
||||
speakerListAdapter.notifyDataSetChanged()
|
||||
|
||||
if (activeSpeakerIds.contains(viewModel.roomInfoResponse.creatorId.toInt())) {
|
||||
binding.ivCreatorProfileBg.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.ivCreatorProfileBg.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1389,6 +1528,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
override fun onUserMuteAudio(uid: Int, muted: Boolean) {
|
||||
super.onUserMuteAudio(uid, muted)
|
||||
handler.post {
|
||||
if (uid == viewModel.roomInfoResponse.creatorId.toInt()) {
|
||||
setMuteSpeakerCreator(muted)
|
||||
} else {
|
||||
if (muted) {
|
||||
speakerListAdapter.muteSpeakers.add(uid)
|
||||
} else {
|
||||
|
@ -1396,6 +1538,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
}
|
||||
speakerListAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
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.profile.GetLiveRoomUserProfileResponse
|
||||
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.ReportRequest
|
||||
import kr.co.vividnext.sodalive.report.ReportType
|
||||
|
@ -29,11 +34,13 @@ import okhttp3.MultipartBody
|
|||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
import kotlin.math.floor
|
||||
|
||||
class LiveRoomViewModel(
|
||||
private val repository: LiveRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val reportRepository: ReportRepository
|
||||
private val reportRepository: ReportRepository,
|
||||
private val rouletteRepository: RouletteRepository
|
||||
) : BaseViewModel() {
|
||||
private val _roomInfoLiveData = MutableLiveData<GetRoomInfoResponse>()
|
||||
val roomInfoLiveData: LiveData<GetRoomInfoResponse>
|
||||
|
@ -43,14 +50,10 @@ class LiveRoomViewModel(
|
|||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private val _isShowNotice = MutableLiveData(true)
|
||||
private val _isShowNotice = MutableLiveData(false)
|
||||
val isShowNotice: LiveData<Boolean>
|
||||
get() = _isShowNotice
|
||||
|
||||
private val _isExpandNotice = MutableLiveData(false)
|
||||
val isExpandNotice: LiveData<Boolean>
|
||||
get() = _isExpandNotice
|
||||
|
||||
private val _totalDonationCan = MutableLiveData(0)
|
||||
val totalDonationCan: LiveData<Int>
|
||||
get() = _totalDonationCan
|
||||
|
@ -59,6 +62,10 @@ class LiveRoomViewModel(
|
|||
val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>
|
||||
get() = _userProfileLiveData
|
||||
|
||||
private val _coverImageUrlLiveData = MutableLiveData("")
|
||||
val coverImageUrlLiveData: LiveData<String>
|
||||
get() = _coverImageUrlLiveData
|
||||
|
||||
lateinit var roomInfoResponse: GetRoomInfoResponse
|
||||
|
||||
fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized
|
||||
|
@ -188,6 +195,10 @@ class LiveRoomViewModel(
|
|||
Logger.e("data: ${it.data}")
|
||||
_roomInfoLiveData.postValue(roomInfoResponse)
|
||||
|
||||
if (_coverImageUrlLiveData.value!! != roomInfoResponse.coverImageUrl) {
|
||||
_coverImageUrlLiveData.value = roomInfoResponse.coverImageUrl
|
||||
}
|
||||
|
||||
getTotalDonationCan(roomId = roomId)
|
||||
|
||||
if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) {
|
||||
|
@ -346,11 +357,6 @@ class LiveRoomViewModel(
|
|||
|
||||
fun toggleShowNotice() {
|
||||
_isShowNotice.value = !isShowNotice.value!!
|
||||
_isExpandNotice.value = false
|
||||
}
|
||||
|
||||
fun toggleExpandNotice() {
|
||||
_isExpandNotice.value = !isExpandNotice.value!!
|
||||
}
|
||||
|
||||
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.content.Context
|
||||
import android.graphics.Typeface
|
||||
import android.text.SpannableString
|
||||
import android.text.Spanned
|
||||
import android.text.TextUtils
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
|
@ -65,12 +67,7 @@ data class LiveRoomJoinChat(
|
|||
)
|
||||
|
||||
spStr.setSpan(
|
||||
CustomTypefaceSpan(
|
||||
ResourcesCompat.getFont(
|
||||
context,
|
||||
R.font.gmarket_sans_bold
|
||||
)
|
||||
),
|
||||
StyleSpan(Typeface.BOLD),
|
||||
str.indexOf("'"),
|
||||
str.indexOf("'님"),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
|
@ -174,6 +171,7 @@ data class LiveRoomNormalChat(
|
|||
itemBinding.tvNickname.text = nickname
|
||||
|
||||
itemBinding.ivBg.visibility = View.VISIBLE
|
||||
itemBinding.ivRoulette.visibility = View.GONE
|
||||
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
||||
|
||||
when (rank + 1) {
|
||||
|
@ -190,7 +188,7 @@ data class LiveRoomNormalChat(
|
|||
}
|
||||
|
||||
-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.visibility = View.VISIBLE
|
||||
}
|
||||
|
@ -229,7 +227,7 @@ data class LiveRoomNormalChat(
|
|||
)
|
||||
|
||||
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 {
|
||||
itemBinding.llMessageBg.setBackgroundResource(R.drawable.bg_round_corner_3_3_99000000)
|
||||
}
|
||||
|
@ -288,6 +286,7 @@ data class LiveRoomDonationChat(
|
|||
itemBinding.ivCan.visibility = View.VISIBLE
|
||||
itemBinding.ivBg.visibility = View.GONE
|
||||
itemBinding.ivCrown.visibility = View.GONE
|
||||
itemBinding.ivRoulette.visibility = View.GONE
|
||||
itemBinding.tvCreatorOrManager.visibility = View.GONE
|
||||
|
||||
if (donationMessage.isNotBlank()) {
|
||||
|
@ -302,35 +301,89 @@ data class LiveRoomDonationChat(
|
|||
|
||||
itemBinding.root.setBackgroundResource(
|
||||
when {
|
||||
can >= 100000 -> {
|
||||
R.drawable.bg_round_corner_6_7_c25264
|
||||
}
|
||||
|
||||
can >= 50000 -> {
|
||||
R.drawable.bg_round_corner_6_7_e6d85e37
|
||||
}
|
||||
|
||||
can >= 10000 -> {
|
||||
R.drawable.bg_round_corner_6_7_e6d38c38
|
||||
R.drawable.bg_round_corner_6_7_ccc25264
|
||||
}
|
||||
|
||||
can >= 5000 -> {
|
||||
R.drawable.bg_round_corner_6_7_e659548f
|
||||
R.drawable.bg_round_corner_6_7_ccd85e37
|
||||
}
|
||||
|
||||
can >= 1000 -> {
|
||||
R.drawable.bg_round_corner_6_7_e64d6aa4
|
||||
R.drawable.bg_round_corner_6_7_ccd38c38
|
||||
}
|
||||
|
||||
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 -> {
|
||||
R.drawable.bg_round_corner_6_7_e6548f7d
|
||||
R.drawable.bg_round_corner_6_7_cc548f7d
|
||||
}
|
||||
}
|
||||
)
|
||||
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("message") val message: String,
|
||||
@SerializedName("can") val can: Int,
|
||||
@SerializedName("donationMessage") val donationMessage: String?
|
||||
@SerializedName("donationMessage") val donationMessage: String?,
|
||||
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null
|
||||
)
|
||||
|
||||
enum class LiveRoomChatRawMessageType {
|
||||
@SerializedName("DONATION") DONATION,
|
||||
@SerializedName("SET_MANAGER") SET_MANAGER,
|
||||
@SerializedName("EDIT_ROOM_INFO") EDIT_ROOM_INFO,
|
||||
@SerializedName("DONATION_STATUS") DONATION_STATUS
|
||||
@SerializedName("DONATION")
|
||||
DONATION,
|
||||
@SerializedName("SET_MANAGER")
|
||||
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.ivTimeReservation.visibility = View.GONE
|
||||
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(
|
||||
R.drawable.bg_round_corner_6_7_1f1734
|
||||
R.drawable.bg_round_corner_6_7_13181b
|
||||
)
|
||||
binding.tvTimeNow.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
|
@ -379,22 +379,22 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
binding.tvTimeReservation.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.llReservationDatetime.visibility = View.VISIBLE
|
||||
binding.ivTimeReservation.visibility = View.VISIBLE
|
||||
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(
|
||||
R.drawable.bg_round_corner_6_7_9970ff
|
||||
R.drawable.bg_round_corner_6_7_3bb9f1
|
||||
)
|
||||
|
||||
binding.tvTimeNow.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -413,8 +413,8 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
binding.ivPrivate.visibility = View.VISIBLE
|
||||
binding.ivOpen.visibility = View.GONE
|
||||
|
||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||
|
||||
binding.tvPrivate.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
|
@ -426,7 +426,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
binding.tvOpen.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -437,13 +437,13 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
binding.ivOpen.visibility = View.VISIBLE
|
||||
binding.ivPrivate.visibility = View.GONE
|
||||
|
||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
||||
binding.llOpen.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
binding.llPrivate.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||
|
||||
binding.tvPrivate.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -501,16 +501,16 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
viewModel.isAdultLiveData.observe(this) {
|
||||
if (it) {
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
|
@ -519,16 +519,16 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
)
|
||||
} else {
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
|
||||
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(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
|
@ -605,7 +605,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
priceView.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
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.databinding.FragmentLiveRoomDetailBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
import kr.co.vividnext.sodalive.extensions.convertDateFormat
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.Locale
|
||||
|
||||
class LiveRoomDetailFragment(
|
||||
private val roomId: Long,
|
||||
|
@ -90,7 +92,11 @@ class LiveRoomDetailFragment(
|
|||
}
|
||||
|
||||
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) {
|
||||
binding.tvCan.text = response.price.toString()
|
||||
|
|
|
@ -1,32 +1,87 @@
|
|||
package kr.co.vividnext.sodalive.live.room.dialog
|
||||
|
||||
import android.app.Activity
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import kr.co.vividnext.sodalive.dialog.LiveDialog
|
||||
import android.view.View
|
||||
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(
|
||||
activity: Activity,
|
||||
layoutInflater: LayoutInflater,
|
||||
title: String,
|
||||
desc: String,
|
||||
desc2: String? = null,
|
||||
startDateTime: String? = null,
|
||||
nowDateTime: String? = null,
|
||||
confirmButtonTitle: String,
|
||||
confirmButtonClick: () -> Unit,
|
||||
cancelButtonTitle: String = "",
|
||||
cancelButtonClick: (() -> Unit)? = null,
|
||||
) : LiveDialog(
|
||||
activity,
|
||||
layoutInflater,
|
||||
title,
|
||||
desc,
|
||||
confirmButtonTitle,
|
||||
confirmButtonClick,
|
||||
cancelButtonTitle,
|
||||
cancelButtonClick
|
||||
) {
|
||||
private val alertDialog: AlertDialog
|
||||
private val dialogView = DialogLivePaymentBinding.inflate(layoutInflater)
|
||||
|
||||
init {
|
||||
val lp = dialogView.tvConfirm.layoutParams as LinearLayout.LayoutParams
|
||||
lp.weight = 2F
|
||||
dialogView.tvConfirm.layoutParams = lp
|
||||
val dialogBuilder = AlertDialog.Builder(activity)
|
||||
dialogBuilder.setView(dialogView.root)
|
||||
|
||||
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("managerList") val managerList: List<LiveRoomMember>,
|
||||
@SerializedName("donationRankingTop3UserIds") val donationRankingTop3UserIds: List<Long>,
|
||||
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean,
|
||||
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean,
|
||||
@SerializedName("password") val password: String? = null
|
||||
)
|
||||
|
|
|
@ -5,11 +5,11 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.load
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import coil.transform.CircleCropTransformation
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomProfileBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||
import kr.co.vividnext.sodalive.live.room.info.LiveRoomMember
|
||||
|
||||
class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapter.ViewHolder>() {
|
||||
|
@ -17,10 +17,10 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
|
|||
private val binding: ItemLiveRoomProfileBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(item: LiveRoomMember) {
|
||||
binding.ivProfile.load(item.profileImage) {
|
||||
binding.ivProfile.loadUrl(item.profileImage) {
|
||||
crossfade(true)
|
||||
placeholder(R.drawable.ic_place_holder)
|
||||
transformations(RoundedCornersTransformation(23.3f.dpToPx()))
|
||||
transformations(CircleCropTransformation())
|
||||
|
||||
if (activeSpeakers.contains(item.id.toInt())) {
|
||||
binding.ivBg.visibility = View.VISIBLE
|
||||
|
@ -35,15 +35,9 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
|
|||
}
|
||||
|
||||
val ivMuteLp = binding.ivMute.layoutParams
|
||||
ivMuteLp.width = 51.7f.dpToPx().toInt()
|
||||
ivMuteLp.height = 51.7f.dpToPx().toInt()
|
||||
ivMuteLp.width = 30f.dpToPx().toInt()
|
||||
ivMuteLp.height = 30f.dpToPx().toInt()
|
||||
binding.ivMute.layoutParams = ivMuteLp
|
||||
|
||||
if (managerId == item.id) {
|
||||
binding.ivCrown.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.ivCrown.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
binding.tvNickname.text = item.nickname
|
||||
|
|
|
@ -20,7 +20,6 @@ class LiveRoomUserProfileDialog(
|
|||
private val userProfileLiveData: LiveData<GetLiveRoomUserProfileResponse>,
|
||||
layoutInflater: LayoutInflater,
|
||||
private val isStaff: (Long) -> Boolean,
|
||||
private val onClickSendMessage: (Long, String) -> Unit,
|
||||
private val onClickSetManager: (Long) -> Unit,
|
||||
private val onClickReleaseManager: (Long) -> Unit,
|
||||
private val onClickFollow: (Long) -> Unit,
|
||||
|
@ -84,18 +83,8 @@ class LiveRoomUserProfileDialog(
|
|||
}
|
||||
|
||||
dialogView.tvNickname.text = userProfile.nickname
|
||||
dialogView.tvTags.text = userProfile.tags
|
||||
dialogView.tvGender.text = userProfile.gender
|
||||
dialogView.tvIntroduce.text = userProfile.introduce
|
||||
|
||||
dialogView.ivClose.setOnClickListener { alertDialog.dismiss() }
|
||||
dialogView.llSendMessage.setOnClickListener {
|
||||
onClickSendMessage(
|
||||
userProfile.userId,
|
||||
userProfile.nickname
|
||||
)
|
||||
}
|
||||
|
||||
dialogView.tvIntroduce.setOnClickListener {
|
||||
isIntroduceFold = !isIntroduceFold
|
||||
|
||||
|
@ -169,25 +158,33 @@ class LiveRoomUserProfileDialog(
|
|||
}
|
||||
|
||||
if (userProfile.isFollowing != null) {
|
||||
dialogView.llFollow.visibility = View.VISIBLE
|
||||
dialogView.ivFollow.visibility = View.VISIBLE
|
||||
|
||||
if (userProfile.isFollowing) {
|
||||
dialogView.tvFollow.text = "팔로잉"
|
||||
dialogView.ivFollow.setImageResource(R.drawable.ic_alarm_selected)
|
||||
dialogView.llFollow.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_23_3_3e1b93_9970ff
|
||||
)
|
||||
dialogView.tvFollow.setOnClickListener { onClickUnFollow(userProfile.userId) }
|
||||
dialogView.ivFollow.setImageResource(R.drawable.btn_following)
|
||||
dialogView.ivFollow.setOnClickListener { onClickUnFollow(userProfile.userId) }
|
||||
} else {
|
||||
dialogView.tvFollow.text = "팔로우"
|
||||
dialogView.ivFollow.setImageResource(R.drawable.ic_alarm)
|
||||
dialogView.llFollow.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_23_3_transparent_9970ff
|
||||
)
|
||||
dialogView.tvFollow.setOnClickListener { onClickFollow(userProfile.userId) }
|
||||
dialogView.ivFollow.setImageResource(R.drawable.btn_follow)
|
||||
dialogView.ivFollow.setOnClickListener { onClickFollow(userProfile.userId) }
|
||||
}
|
||||
|
||||
if (userProfile.tags.isNotBlank()) {
|
||||
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 {
|
||||
dialogView.llFollow.visibility = View.GONE
|
||||
dialogView.tvTags.visibility = View.GONE
|
||||
dialogView.ivFollow.visibility = View.GONE
|
||||
dialogView.tvIntroduce.visibility = View.GONE
|
||||
}
|
||||
|
||||
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.normal.TedPermission
|
||||
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.audio_content.AudioContentPlayService
|
||||
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 audioContentReceiver = AudioContentReceiver()
|
||||
|
||||
private var packageReceiver: PackageReceiver? = null
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
executeDeeplink()
|
||||
executeDeeplink(intent)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -67,14 +63,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
getMemberInfo()
|
||||
getEventPopup()
|
||||
|
||||
initPointClick()
|
||||
handler.postDelayed({ executeDeeplink() }, 500)
|
||||
handler.postDelayed({ executeDeeplink(intent) }, 500)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val intentFilter = IntentFilter(Constants.ACTION_MAIN_AUDIO_CONTENT_RECEIVER)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(audioContentReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(audioContentReceiver, intentFilter)
|
||||
}
|
||||
|
||||
startService(
|
||||
Intent(this, AudioContentPlayService::class.java).apply {
|
||||
|
@ -88,13 +87,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
if (packageReceiver != null) {
|
||||
applicationContext.unregisterReceiver(packageReceiver)
|
||||
}
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||
liveFragment = LiveFragment()
|
||||
|
@ -113,7 +105,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
|
|||
setupBottomTabLayout()
|
||||
}
|
||||
|
||||
private fun executeDeeplink() {
|
||||
private fun executeDeeplink(intent: Intent) {
|
||||
val bundle = intent.getBundleExtra(Constants.EXTRA_DATA)
|
||||
if (bundle != null) {
|
||||
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() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)
|
||||
|
|
|
@ -187,36 +187,36 @@ class TextMessageFragment : BaseFragment<FragmentTextMessageBinding>(
|
|||
when (it) {
|
||||
MessageBox.SENT -> {
|
||||
binding.tvSent.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvSent.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
MessageBox.RECEIVE -> {
|
||||
binding.tvReceive.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvReceive.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
MessageBox.KEEP -> {
|
||||
binding.tvKeep.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvKeep.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ class TextMessageWriteActivity : BaseActivity<ActivityTextMessageWriteBinding>(
|
|||
private fun bindData() {
|
||||
compositeDisposable.add(
|
||||
binding.etMessage.textChanges().skip(1)
|
||||
.debounce(500, TimeUnit.MILLISECONDS)
|
||||
.debounce(100, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe {
|
||||
|
|
|
@ -313,36 +313,36 @@ class VoiceMessageFragment : BaseFragment<FragmentVoiceMessageBinding>(
|
|||
when (it) {
|
||||
MessageBox.SENT -> {
|
||||
binding.tvSent.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvSent.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
MessageBox.RECEIVE -> {
|
||||
binding.tvReceive.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvReceive.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_9970ff
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
MessageBox.KEEP -> {
|
||||
binding.tvKeep.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_16_7_transparent_9970ff
|
||||
R.drawable.bg_round_corner_16_7_transparent_3bb9f1
|
||||
)
|
||||
binding.tvKeep.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
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