Compare commits
60 Commits
e52075a692
...
b876695adc
Author | SHA1 | Date |
---|---|---|
|
b876695adc | |
|
b220b8bce4 | |
|
ba4d707d45 | |
|
2920d2a7ae | |
|
b8abef6aeb | |
|
75fc34cbe3 | |
|
206fc398c6 | |
|
b95b77bcb9 | |
|
62c269cac2 | |
|
4b3474ff42 | |
|
d6e9b929e9 | |
|
13efce42a0 | |
|
85ccc18485 | |
|
9df08cdf24 | |
|
7892eed443 | |
|
eca68c06c3 | |
|
3c82ff1c4e | |
|
8c6aff1623 | |
|
254a1e3381 | |
|
dff4c833f1 | |
|
5fa3a591d4 | |
|
845578a1dd | |
|
84ac72b391 | |
|
db364d9bf7 | |
|
3fe01f8def | |
|
02c815077e | |
|
108eb759ec | |
|
fef49a0d6a | |
|
87241fa8bd | |
|
29d5192fff | |
|
c86e55719e | |
|
839a8a780c | |
|
346334a0ba | |
|
7cd4d180c2 | |
|
320ef4fbc7 | |
|
b4623141f3 | |
|
30d3ed14d7 | |
|
ae617d5154 | |
|
9dd3c568d8 | |
|
f31fc7691e | |
|
27df922383 | |
|
d5956c024d | |
|
29aca74651 | |
|
f41790b302 | |
|
0b999a874c | |
|
2778638dc9 | |
|
cc5fe445fc | |
|
c310f9c57e | |
|
cd607425a0 | |
|
a5df8a1110 | |
|
2bd30aa346 | |
|
a6ce994fd0 | |
|
7bffd1c3c7 | |
|
dfd92d6db6 | |
|
5529872bd5 | |
|
364a530956 | |
|
0556d5a067 | |
|
be46893555 | |
|
f7f789892d | |
|
de0d327168 |
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="deploymentTargetSelector">
|
||||||
|
<selectionStates>
|
||||||
|
<SelectionState runConfigName="app">
|
||||||
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
</SelectionState>
|
||||||
|
</selectionStates>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -40,8 +40,8 @@ android {
|
||||||
applicationId "kr.co.vividnext.sodalive"
|
applicationId "kr.co.vividnext.sodalive"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 46
|
versionCode 74
|
||||||
versionName "1.8.21"
|
versionName "1.11.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
android:name=".mypage.can.charge.CanChargeActivity"
|
android:name=".mypage.can.charge.CanChargeActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||||
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
||||||
|
<activity android:name=".mypage.can.payment.CanPaymentTempActivity" />
|
||||||
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
||||||
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
||||||
<activity android:name=".live.room.update.LiveRoomEditActivity" />
|
<activity android:name=".live.room.update.LiveRoomEditActivity" />
|
||||||
|
@ -133,6 +134,9 @@
|
||||||
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
||||||
<activity android:name=".audio_content.all.by_theme.AudioContentAllByThemeActivity" />
|
<activity android:name=".audio_content.all.by_theme.AudioContentAllByThemeActivity" />
|
||||||
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
|
<activity android:name=".live.roulette.config.RouletteConfigActivity" />
|
||||||
|
<activity android:name=".audio_content.series.SeriesListAllActivity" />
|
||||||
|
<activity android:name=".audio_content.series.detail.SeriesDetailActivity" />
|
||||||
|
<activity android:name=".audio_content.series.content.SeriesContentAllActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
|
import android.media.AudioManager
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
@ -367,6 +368,7 @@ class AudioContentPlayService :
|
||||||
mediaPlayer.setOnCompletionListener(this)
|
mediaPlayer.setOnCompletionListener(this)
|
||||||
mediaPlayer.setAudioAttributes(
|
mediaPlayer.setAudioAttributes(
|
||||||
AudioAttributes.Builder()
|
AudioAttributes.Builder()
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.detail
|
package kr.co.vividnext.sodalive.audio_content.detail
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
@ -13,6 +14,8 @@ import android.view.View
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
import android.widget.SeekBar
|
import android.widget.SeekBar
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -37,13 +40,16 @@ import kr.co.vividnext.sodalive.common.Utils
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
||||||
import kr.co.vividnext.sodalive.mypage.auth.Auth
|
import kr.co.vividnext.sodalive.mypage.auth.Auth
|
||||||
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
||||||
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempActivity
|
||||||
import kr.co.vividnext.sodalive.report.ReportType
|
import kr.co.vividnext.sodalive.report.ReportType
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBinding>(
|
class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBinding>(
|
||||||
ActivityAudioContentDetailBinding::inflate
|
ActivityAudioContentDetailBinding::inflate
|
||||||
|
@ -63,6 +69,10 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
private var refresh = false
|
private var refresh = false
|
||||||
private var title = ""
|
private var title = ""
|
||||||
|
|
||||||
|
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
||||||
|
private lateinit var audioContent: GetAudioContentDetailResponse
|
||||||
|
private lateinit var orderType: OrderType
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onNewIntent(intent: Intent) {
|
override fun onNewIntent(intent: Intent) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
|
@ -87,6 +97,14 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activityResultLauncher = registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) {
|
||||||
|
if (it.resultCode == Activity.RESULT_OK) {
|
||||||
|
contentOrder(audioContent, orderType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bindData()
|
bindData()
|
||||||
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
||||||
}
|
}
|
||||||
|
@ -433,7 +451,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupCommentArea(response: GetAudioContentDetailResponse) {
|
private fun setupCommentArea(response: GetAudioContentDetailResponse) {
|
||||||
if (response.isCommentAvailable) {
|
if (
|
||||||
|
response.isCommentAvailable &&
|
||||||
|
response.contentUrl.isNotBlank() &&
|
||||||
|
response.releaseDate == null
|
||||||
|
) {
|
||||||
binding.llDonation.visibility = View.VISIBLE
|
binding.llDonation.visibility = View.VISIBLE
|
||||||
binding.llComment.visibility = View.VISIBLE
|
binding.llComment.visibility = View.VISIBLE
|
||||||
binding.tvCommentCount.text = "${response.commentCount}"
|
binding.tvCommentCount.text = "${response.commentCount}"
|
||||||
|
@ -512,12 +534,29 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
binding.tvReleaseDate.visibility = View.GONE
|
binding.tvReleaseDate.visibility = View.GONE
|
||||||
binding.llPurchase.visibility = View.VISIBLE
|
binding.llPurchase.visibility = View.VISIBLE
|
||||||
binding.llPurchasePrice.visibility = View.VISIBLE
|
binding.llPurchasePrice.visibility = View.VISIBLE
|
||||||
binding.tvPrice.text = response.price.toString()
|
|
||||||
binding.llPurchase.background = ContextCompat.getDrawable(
|
binding.llPurchase.background = ContextCompat.getDrawable(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.drawable.bg_round_corner_5_3_3bb9f1
|
R.drawable.bg_round_corner_5_3_3bb9f1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
binding.ivCan.visibility = if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
View.GONE
|
||||||
|
} else {
|
||||||
|
View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPrice.text = if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
(response.price * 110).moneyFormat()
|
||||||
|
} else {
|
||||||
|
response.price.moneyFormat()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvUnit.text = if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
"원으로"
|
||||||
|
} else {
|
||||||
|
"캔으로"
|
||||||
|
}
|
||||||
|
|
||||||
binding.tvStrPurchaseOrRental.text = if (response.isOnlyRental) {
|
binding.tvStrPurchaseOrRental.text = if (response.isOnlyRental) {
|
||||||
" 대여하기"
|
" 대여하기"
|
||||||
} else {
|
} else {
|
||||||
|
@ -657,45 +696,54 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
binding.tvTag.visibility = View.GONE
|
binding.tvTag.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ivLike.setImageResource(
|
if (response.contentUrl.isNotBlank() && response.releaseDate == null) {
|
||||||
if (response.isLike) {
|
binding.svActionButtons.visibility = View.VISIBLE
|
||||||
R.drawable.ic_audio_content_heart_pressed
|
binding.llLike.visibility = View.VISIBLE
|
||||||
} else {
|
binding.ivLike.setImageResource(
|
||||||
R.drawable.ic_audio_content_heart_normal
|
if (response.isLike) {
|
||||||
}
|
R.drawable.ic_audio_content_heart_pressed
|
||||||
)
|
|
||||||
|
|
||||||
binding.tvLike.text = "${response.likeCount}"
|
|
||||||
binding.llLike.setOnClickListener {
|
|
||||||
viewModel.likeContent(contentId = audioContentId) {
|
|
||||||
val likeCount = binding.tvLike.text.toString().toInt()
|
|
||||||
if (it) {
|
|
||||||
binding.tvLike.text = "${likeCount + 1}"
|
|
||||||
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_pressed)
|
|
||||||
} else {
|
} else {
|
||||||
binding.tvLike.text = if (likeCount - 1 < 0) {
|
R.drawable.ic_audio_content_heart_normal
|
||||||
"0"
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.tvLike.text = "${response.likeCount}"
|
||||||
|
binding.llLike.setOnClickListener {
|
||||||
|
viewModel.likeContent(contentId = audioContentId) {
|
||||||
|
val likeCount = binding.tvLike.text.toString().toInt()
|
||||||
|
if (it) {
|
||||||
|
binding.tvLike.text = "${likeCount + 1}"
|
||||||
|
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_pressed)
|
||||||
} else {
|
} else {
|
||||||
"${likeCount - 1}"
|
binding.tvLike.text = if (likeCount - 1 < 0) {
|
||||||
|
"0"
|
||||||
|
} else {
|
||||||
|
"${likeCount - 1}"
|
||||||
|
}
|
||||||
|
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_normal)
|
||||||
}
|
}
|
||||||
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_normal)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
binding.tvShare.setOnClickListener {
|
binding.tvShare.visibility = View.VISIBLE
|
||||||
viewModel.shareAudioContent(
|
binding.tvShare.setOnClickListener {
|
||||||
audioContentId = audioContentId,
|
viewModel.shareAudioContent(
|
||||||
contentImage = response.coverImageUrl,
|
audioContentId = audioContentId,
|
||||||
contentTitle = "${response.title} - ${response.creator.nickname}"
|
contentImage = response.coverImageUrl,
|
||||||
) {
|
contentTitle = "${response.title} - ${response.creator.nickname}"
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
) {
|
||||||
intent.type = "text/plain"
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, it)
|
intent.type = "text/plain"
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, it)
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(intent, "오디오콘텐츠 공유")
|
val shareIntent = Intent.createChooser(intent, "오디오콘텐츠 공유")
|
||||||
startActivity(shareIntent)
|
startActivity(shareIntent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
binding.svActionButtons.visibility = View.GONE
|
||||||
|
binding.llLike.visibility = View.GONE
|
||||||
|
binding.tvShare.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.totalContentCount != null && response.remainingContentCount != null) {
|
if (response.totalContentCount != null && response.remainingContentCount != null) {
|
||||||
|
@ -834,18 +882,43 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
||||||
|
|
||||||
binding.rlPreviewAlert.visibility = View.GONE
|
binding.rlPreviewAlert.visibility = View.GONE
|
||||||
|
|
||||||
viewModel.order(
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
contentId = audioContent.contentId,
|
this@AudioContentDetailActivity.audioContent = audioContent
|
||||||
orderType = orderType
|
this@AudioContentDetailActivity.orderType = orderType
|
||||||
) {
|
activityResultLauncher.launch(
|
||||||
val intent = Intent(applicationContext, CanChargeActivity::class.java)
|
Intent(applicationContext, CanPaymentTempActivity::class.java).apply {
|
||||||
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
putExtra("title", audioContent.title)
|
||||||
startActivity(intent)
|
putExtra(
|
||||||
|
"can",
|
||||||
|
if (orderType == OrderType.RENTAL) {
|
||||||
|
ceil(audioContent.price * 0.6).toInt()
|
||||||
|
} else {
|
||||||
|
audioContent.price
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
contentOrder(audioContent, orderType)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
).show(screenWidth)
|
).show(screenWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun contentOrder(
|
||||||
|
audioContent: GetAudioContentDetailResponse,
|
||||||
|
orderType: OrderType
|
||||||
|
) {
|
||||||
|
viewModel.order(
|
||||||
|
contentId = audioContent.contentId,
|
||||||
|
orderType = orderType
|
||||||
|
) {
|
||||||
|
val intent = Intent(applicationContext, CanChargeActivity::class.java)
|
||||||
|
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inner class AudioContentReceiver : BroadcastReceiver() {
|
inner class AudioContentReceiver : BroadcastReceiver() {
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main
|
package kr.co.vividnext.sodalive.audio_content.main
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Service
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.inputmethod.InputMethodManager
|
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
@ -29,18 +27,19 @@ import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCura
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCurationViewModel
|
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.AudioContentMainNewContentThemeAdapter
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
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.order.AudioContentMainOrderListViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingAdapter
|
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.main.ranking.AudioContentMainRankingViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity
|
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.series.UserProfileSeriesListAdapter
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
import kr.co.vividnext.sodalive.settings.event.EventDetailActivity
|
||||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
|
@ -50,8 +49,8 @@ import kotlin.math.roundToInt
|
||||||
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
FragmentAudioContentMainBinding::inflate
|
FragmentAudioContentMainBinding::inflate
|
||||||
) {
|
) {
|
||||||
private val newContentCreatorViewModel: AudioContentMainNewContentCreatorViewModel by inject()
|
private val recommendSeriesViewModel: AudioContentMainRecommendSeriesViewModel by inject()
|
||||||
private lateinit var newContentCreatorAdapter: AudioContentMainNewContentCreatorAdapter
|
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
||||||
|
|
||||||
private val bannerViewModel: AudioContentMainBannerViewModel by inject()
|
private val bannerViewModel: AudioContentMainBannerViewModel by inject()
|
||||||
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
||||||
|
@ -80,7 +79,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
newContentViewModel.getNewContentOfTheme("전체")
|
newContentViewModel.getNewContentOfTheme("전체")
|
||||||
contentRankingViewModel.getContentRanking()
|
contentRankingViewModel.getContentRanking()
|
||||||
contentRankingViewModel.getContentRankingSortType()
|
contentRankingViewModel.getContentRankingSortType()
|
||||||
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
recommendSeriesViewModel.getRecommendSeriesList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
|
@ -98,7 +97,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
binding.llUploadContent.visibility = View.GONE
|
binding.llUploadContent.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
setupNewContentCreator()
|
setupRecommendSeries()
|
||||||
setupBanner()
|
setupBanner()
|
||||||
setupOrderList()
|
setupOrderList()
|
||||||
setupNewContentTheme()
|
setupNewContentTheme()
|
||||||
|
@ -107,17 +106,6 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
setupContentRanking()
|
setupContentRanking()
|
||||||
setupCuration()
|
setupCuration()
|
||||||
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
|
||||||
curationViewModel.refresh()
|
|
||||||
bannerViewModel.getMainBannerList()
|
|
||||||
newContentViewModel.getThemeList()
|
|
||||||
newContentViewModel.getNewContentOfTheme("전체")
|
|
||||||
contentRankingViewModel.getContentRanking()
|
|
||||||
contentRankingViewModel.getContentRankingSortType()
|
|
||||||
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.llShortPlay.setOnClickListener {
|
binding.llShortPlay.setOnClickListener {
|
||||||
startActivity(
|
startActivity(
|
||||||
Intent(requireContext(), AudioContentAllByThemeActivity::class.java).apply {
|
Intent(requireContext(), AudioContentAllByThemeActivity::class.java).apply {
|
||||||
|
@ -135,20 +123,33 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupNewContentCreator() {
|
private fun setupRecommendSeries() {
|
||||||
newContentCreatorAdapter = AudioContentMainNewContentCreatorAdapter {
|
seriesAdapter = UserProfileSeriesListAdapter(
|
||||||
val intent = Intent(requireContext(), UserProfileActivity::class.java)
|
onClickItem = {
|
||||||
intent.putExtra(Constants.EXTRA_USER_ID, it)
|
startActivity(
|
||||||
startActivity(intent)
|
Intent(requireContext(), SeriesDetailActivity::class.java).apply {
|
||||||
}
|
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickCreator = {
|
||||||
|
startActivity(
|
||||||
|
Intent(requireContext(), UserProfileActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_USER_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
isVisibleCreator = true
|
||||||
|
)
|
||||||
|
|
||||||
binding.rvNewContentCreator.layoutManager = LinearLayoutManager(
|
val recyclerView = binding.rvRecommendSeries
|
||||||
context,
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
requireContext(),
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.rvNewContentCreator.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
override fun getItemOffsets(
|
override fun getItemOffsets(
|
||||||
outRect: Rect,
|
outRect: Rect,
|
||||||
view: View,
|
view: View,
|
||||||
|
@ -160,28 +161,28 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
when (parent.getChildAdapterPosition(view)) {
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
0 -> {
|
0 -> {
|
||||||
outRect.left = 0
|
outRect.left = 0
|
||||||
outRect.right = 10.7f.dpToPx().toInt()
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
newContentCreatorAdapter.itemCount - 1 -> {
|
seriesAdapter.itemCount - 1 -> {
|
||||||
outRect.left = 10.7f.dpToPx().toInt()
|
|
||||||
outRect.right = 0
|
outRect.right = 0
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
outRect.left = 10.7f.dpToPx().toInt()
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
outRect.right = 10.7f.dpToPx().toInt()
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.rvNewContentCreator.adapter = newContentCreatorAdapter
|
recyclerView.adapter = seriesAdapter
|
||||||
|
|
||||||
newContentCreatorViewModel.newContentUploadCreatorListLiveData.observe(viewLifecycleOwner) {
|
recommendSeriesViewModel.seriesListLiveData.observe(viewLifecycleOwner) {
|
||||||
newContentCreatorAdapter.addItems(it)
|
seriesAdapter.addItems(it)
|
||||||
binding.rvNewContentCreator.visibility = if (
|
binding.llRecommendSeries.visibility = if (
|
||||||
newContentCreatorAdapter.itemCount <= 0 && it.isEmpty()
|
seriesAdapter.itemCount <= 0 && it.isEmpty()
|
||||||
) {
|
) {
|
||||||
View.GONE
|
View.GONE
|
||||||
} else {
|
} else {
|
||||||
|
@ -189,9 +190,14 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newContentCreatorViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
recommendSeriesViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||||
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.llRecommendSeriesRefresh.setOnClickListener {
|
||||||
|
seriesAdapter.clear()
|
||||||
|
recommendSeriesViewModel.getRecommendSeriesList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupBanner() {
|
private fun setupBanner() {
|
||||||
|
|
|
@ -61,6 +61,7 @@ class AudioContentMainNewContentViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNewContentOfTheme(theme: String) {
|
fun getNewContentOfTheme(theme: String) {
|
||||||
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
repository.getNewContentOfTheme(
|
repository.getNewContentOfTheme(
|
||||||
theme = if (theme == "전체") {
|
theme = if (theme == "전체") {
|
||||||
|
@ -85,10 +86,13 @@ class AudioContentMainNewContentViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
it.message?.let { message -> Logger.e(message) }
|
it.message?.let { message -> Logger.e(message) }
|
||||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
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.audio_content.main.GetNewContentUploadCreator
|
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainNewContentCreatorBinding
|
|
||||||
|
|
||||||
class AudioContentMainNewContentCreatorAdapter(
|
|
||||||
private val onClickItem: (Long) -> Unit
|
|
||||||
) : RecyclerView.Adapter<AudioContentMainNewContentCreatorAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
private val items = mutableListOf<GetNewContentUploadCreator>()
|
|
||||||
|
|
||||||
inner class ViewHolder(
|
|
||||||
private val binding: ItemAudioContentMainNewContentCreatorBinding
|
|
||||||
) : RecyclerView.ViewHolder(binding.root) {
|
|
||||||
fun bind(item: GetNewContentUploadCreator) {
|
|
||||||
binding.tvNewContentCreator.text = item.creatorNickname
|
|
||||||
binding.ivNewContentCreator.load(item.creatorProfileImageUrl) {
|
|
||||||
crossfade(true)
|
|
||||||
placeholder(R.drawable.ic_place_holder)
|
|
||||||
transformations(CircleCropTransformation())
|
|
||||||
}
|
|
||||||
binding.root.setOnClickListener { onClickItem(item.creatorId) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
|
||||||
ItemAudioContentMainNewContentCreatorBinding.inflate(
|
|
||||||
LayoutInflater.from(parent.context),
|
|
||||||
parent,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
holder.bind(items[position])
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
|
||||||
fun addItems(items: List<GetNewContentUploadCreator>) {
|
|
||||||
this.items.clear()
|
|
||||||
this.items.addAll(items)
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +1,42 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator
|
package kr.co.vividnext.sodalive.audio_content.main.recommend_series
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.GetNewContentUploadCreator
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
class AudioContentMainNewContentCreatorViewModel(
|
class AudioContentMainRecommendSeriesViewModel(
|
||||||
private val repository: AudioContentRepository
|
private val repository: SeriesRepository
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
private val _toastLiveData = MutableLiveData<String?>()
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
val toastLiveData: LiveData<String?>
|
val toastLiveData: LiveData<String?>
|
||||||
get() = _toastLiveData
|
get() = _toastLiveData
|
||||||
|
|
||||||
private var _newContentUploadCreatorListLiveData =
|
private var _seriesListLiveData = MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||||
MutableLiveData<List<GetNewContentUploadCreator>>()
|
val seriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||||
val newContentUploadCreatorListLiveData: LiveData<List<GetNewContentUploadCreator>>
|
get() = _seriesListLiveData
|
||||||
get() = _newContentUploadCreatorListLiveData
|
|
||||||
|
|
||||||
fun getNewContentUploadCreatorList() {
|
fun getRecommendSeriesList() {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
repository.getNewContentUploadCreatorList(
|
repository
|
||||||
token = "Bearer ${SharedPreferenceManager.token}"
|
.getRecommendSeriesList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||||
)
|
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{
|
{
|
||||||
if (it.success && it.data != null) {
|
if (it.success && it.data != null) {
|
||||||
_newContentUploadCreatorListLiveData.postValue(it.data!!)
|
_seriesListLiveData.value = it.data!!
|
||||||
} else {
|
} else {
|
||||||
if (it.message != null) {
|
if (it.message != null) {
|
||||||
_toastLiveData.postValue(it.message)
|
_toastLiveData.postValue(it.message)
|
||||||
} else {
|
} else {
|
||||||
_toastLiveData.postValue(
|
_toastLiveData.postValue(
|
||||||
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
"추천 시리즈를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -47,7 +45,7 @@ class AudioContentMainNewContentCreatorViewModel(
|
||||||
{
|
{
|
||||||
it.message?.let { message -> Logger.e(message) }
|
it.message?.let { message -> Logger.e(message) }
|
||||||
_toastLiveData.postValue(
|
_toastLiveData.postValue(
|
||||||
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
"추천 시리즈를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||||
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -173,17 +173,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivCommentNo.visibility = View.GONE
|
binding.ivCommentNo.visibility = View.GONE
|
||||||
binding.tvCommentNo.setTextColor(
|
binding.tvCommentNo.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentNo.setBackgroundResource(
|
binding.llCommentNo.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
R.drawable.bg_round_corner_6_7_13181b_3bb9f1
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.ivCommentNo.visibility = View.VISIBLE
|
binding.ivCommentNo.visibility = View.VISIBLE
|
||||||
|
@ -193,17 +193,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||||
R.color.color_eeeeee
|
R.color.color_eeeeee
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
|
||||||
binding.ivCommentYes.visibility = View.GONE
|
binding.ivCommentYes.visibility = View.GONE
|
||||||
binding.tvCommentYes.setTextColor(
|
binding.tvCommentYes.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
binding.llCommentYes
|
binding.llCommentYes
|
||||||
.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734_9970ff)
|
.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b_3bb9f1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,17 +223,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||||
if (it) {
|
if (it) {
|
||||||
binding.ivAgeAll.visibility = View.GONE
|
binding.ivAgeAll.visibility = View.GONE
|
||||||
binding.llAgeAll.setBackgroundResource(
|
binding.llAgeAll.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_1f1734
|
R.drawable.bg_round_corner_6_7_13181b
|
||||||
)
|
)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAge19.visibility = View.VISIBLE
|
binding.ivAge19.visibility = View.VISIBLE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
|
@ -242,17 +242,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
binding.ivAge19.visibility = View.GONE
|
binding.ivAge19.visibility = View.GONE
|
||||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
binding.tvAge19.setTextColor(
|
binding.tvAge19.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.ivAgeAll.visibility = View.VISIBLE
|
binding.ivAgeAll.visibility = View.VISIBLE
|
||||||
binding.llAgeAll.setBackgroundResource(
|
binding.llAgeAll.setBackgroundResource(
|
||||||
R.drawable.bg_round_corner_6_7_9970ff
|
R.drawable.bg_round_corner_6_7_3bb9f1
|
||||||
)
|
)
|
||||||
binding.tvAgeAll.setTextColor(
|
binding.tvAgeAll.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
|
|
|
@ -4,14 +4,17 @@ import android.app.Activity
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import coil.load
|
import coil.load
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import coil.transform.RoundedCornersTransformation
|
import coil.transform.RoundedCornersTransformation
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.DialogAudioContentOrderConfirmBinding
|
import kr.co.vividnext.sodalive.databinding.DialogAudioContentOrderConfirmBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class AudioContentOrderConfirmDialog(
|
class AudioContentOrderConfirmDialog(
|
||||||
|
@ -58,16 +61,35 @@ class AudioContentOrderConfirmDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.tvDuration.text = duration
|
dialogView.tvDuration.text = duration
|
||||||
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
|
|
||||||
"${ceil(price * 0.6).toInt()}"
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
dialogView.ivCan.visibility = View.GONE
|
||||||
|
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
|
||||||
|
"${(ceil(price * 0.6).toInt() * 110).moneyFormat()}원"
|
||||||
|
} else {
|
||||||
|
"${(price * 110).moneyFormat()}원"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"$price"
|
dialogView.ivCan.visibility = View.VISIBLE
|
||||||
|
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
|
||||||
|
ceil(price * 0.6).toInt().moneyFormat()
|
||||||
|
} else {
|
||||||
|
price.moneyFormat()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
"콘텐츠를 대여하시겠습니까?\n아래 캔이 차감됩니다."
|
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||||
|
"콘텐츠를 대여하시겠습니까?"
|
||||||
|
} else {
|
||||||
|
"콘텐츠를 소장하시겠습니까?"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
"콘텐츠를 소장하시겠습니까?\n아래 캔이 차감됩니다."
|
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||||
|
"콘텐츠를 대여하시겠습니까?\n아래 캔이 차감됩니다."
|
||||||
|
} else {
|
||||||
|
"콘텐츠를 소장하시겠습니까?\n아래 캔이 차감됩니다."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.tvCancel.setOnClickListener {
|
dialogView.tvCancel.setOnClickListener {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package kr.co.vividnext.sodalive.audio_content.order
|
package kr.co.vividnext.sodalive.audio_content.order
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentOrderBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentOrderBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
|
|
||||||
class AudioContentOrderFragment(
|
class AudioContentOrderFragment(
|
||||||
|
@ -26,15 +29,33 @@ class AudioContentOrderFragment(
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
binding.ivKeepCan.visibility = View.GONE
|
||||||
|
binding.ivRentalCan.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.ivKeepCan.visibility = View.VISIBLE
|
||||||
|
binding.ivRentalCan.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
if (isOnlyRental) {
|
if (isOnlyRental) {
|
||||||
binding.tvRental.text = "$price"
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
|
binding.tvRental.text = "${(price * 110).moneyFormat()}원"
|
||||||
|
} else {
|
||||||
|
binding.tvRental.text = price.moneyFormat()
|
||||||
|
}
|
||||||
binding.rlKeep.visibility = View.GONE
|
binding.rlKeep.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
binding.tvKeep.text = "$price"
|
if (SharedPreferenceManager.userId == 17958L) {
|
||||||
binding.tvRental.text = "${ceil(price * 0.6).toInt()}"
|
binding.tvKeep.text = "${(price * 110).moneyFormat()}원"
|
||||||
|
binding.tvRental.text = "${(ceil(price * 0.6).toInt() * 110).moneyFormat()}원"
|
||||||
|
} else {
|
||||||
|
binding.tvKeep.text = price.moneyFormat()
|
||||||
|
binding.tvRental.text = ceil(price * 0.6).toInt().moneyFormat()
|
||||||
|
}
|
||||||
|
|
||||||
binding.rlKeep.visibility = View.VISIBLE
|
binding.rlKeep.visibility = View.VISIBLE
|
||||||
binding.llKeep.setOnClickListener {
|
binding.llKeep.setOnClickListener {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class GetSeriesListResponse(
|
||||||
|
@SerializedName("totalCount") val totalCount: Int,
|
||||||
|
@SerializedName("items") val items: List<SeriesListItem>
|
||||||
|
) {
|
||||||
|
data class SeriesListItem(
|
||||||
|
@SerializedName("seriesId") val seriesId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("coverImage") val coverImage: String,
|
||||||
|
@SerializedName("publishedDaysOfWeek") val publishedDaysOfWeek: String,
|
||||||
|
@SerializedName("isComplete") val isComplete: Boolean,
|
||||||
|
@SerializedName("creator") val creator: SeriesListItemCreator,
|
||||||
|
@SerializedName("numberOfContent") val numberOfContent: Int,
|
||||||
|
@SerializedName("isNew") val isNew: Boolean,
|
||||||
|
@SerializedName("isPopular") val isPopular: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class SeriesListItemCreator(
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileImage") val profileImage: String
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListResponse
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesDetailResponse
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
interface SeriesApi {
|
||||||
|
@GET("/audio-content/series")
|
||||||
|
fun getSeriesList(
|
||||||
|
@Query("creatorId") creatorId: Long,
|
||||||
|
@Query("sortType") sortType: SeriesListAllViewModel.SeriesSortType,
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetSeriesListResponse>>
|
||||||
|
|
||||||
|
@GET("/audio-content/series/{id}")
|
||||||
|
fun getSeriesDetail(
|
||||||
|
@Path("id") seriesId: Long,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetSeriesDetailResponse>>
|
||||||
|
|
||||||
|
@GET("/audio-content/series/{id}/content")
|
||||||
|
fun getSeriesContentList(
|
||||||
|
@Path("id") seriesId: Long,
|
||||||
|
@Query("page") page: Int,
|
||||||
|
@Query("size") size: Int,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetSeriesContentListResponse>>
|
||||||
|
|
||||||
|
@GET("/audio-content/series/recommend")
|
||||||
|
fun getRecommendSeriesList(
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<List<GetSeriesListResponse.SeriesListItem>>>
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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.ItemSeriesListBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class SeriesListAdapter(
|
||||||
|
private val itemWidth: Int,
|
||||||
|
private val onClickItem: (Long) -> Unit,
|
||||||
|
private val onClickCreator: (Long) -> Unit,
|
||||||
|
private val isVisibleCreator: Boolean
|
||||||
|
) : RecyclerView.Adapter<SeriesListAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetSeriesListResponse.SeriesListItem>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemSeriesListBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
fun bind(item: GetSeriesListResponse.SeriesListItem) {
|
||||||
|
val lp = binding.ivCover.layoutParams as ConstraintLayout.LayoutParams
|
||||||
|
lp.width = itemWidth
|
||||||
|
lp.height = itemWidth * 432 / 306
|
||||||
|
binding.ivCover.layoutParams = lp
|
||||||
|
|
||||||
|
binding.ivCover.load(item.coverImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(RoundedCornersTransformation(5f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvTitle.text = item.title
|
||||||
|
binding.tvSeriesContentCount.text = "총 ${item.numberOfContent}화"
|
||||||
|
binding.tvPublishedDaysOfWeek.text = item.publishedDaysOfWeek
|
||||||
|
|
||||||
|
binding.tvNew.visibility = if (item.isNew) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPopular.visibility = if (item.isPopular) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isComplete) {
|
||||||
|
binding.tvNew.visibility = View.GONE
|
||||||
|
binding.tvComplete.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.tvComplete.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVisibleCreator) {
|
||||||
|
binding.llCreator.visibility = View.VISIBLE
|
||||||
|
binding.tvCreator.text = item.creator.nickname
|
||||||
|
binding.ivCreator.load(item.creator.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
binding.llCreator.setOnClickListener { onClickCreator(item.creator.creatorId) }
|
||||||
|
} else {
|
||||||
|
binding.llCreator.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.root.setOnClickListener { onClickItem(item.seriesId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemSeriesListBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.count()
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun addItems(items: List<GetSeriesListResponse.SeriesListItem>) {
|
||||||
|
this.items.addAll(items)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
this.items.clear()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.DifferentSpacingItemDecoration
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivitySeriesListAllBinding
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
class SeriesListAllActivity : BaseActivity<ActivitySeriesListAllBinding>(
|
||||||
|
ActivitySeriesListAllBinding::inflate
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val viewModel: SeriesListAllViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var seriesAdapter: SeriesListAdapter
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val creatorId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
|
||||||
|
if (creatorId <= 0) {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
|
||||||
|
viewModel.creatorId = creatorId
|
||||||
|
viewModel.getSeriesList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
binding.toolbar.tvBack.text = "시리즈 전체보기"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
seriesAdapter = SeriesListAdapter(
|
||||||
|
itemWidth = ((screenWidth - (13.3 * 3)) / 3).roundToInt(),
|
||||||
|
onClickItem = {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickCreator = {},
|
||||||
|
isVisibleCreator = false
|
||||||
|
)
|
||||||
|
|
||||||
|
val spanCount = 3
|
||||||
|
val horizontalSpacing = 20
|
||||||
|
val verticalSpacing = 100
|
||||||
|
val recyclerView = binding.rvSeriesAll
|
||||||
|
recyclerView.layoutManager = GridLayoutManager(this, spanCount)
|
||||||
|
|
||||||
|
recyclerView.addItemDecoration(
|
||||||
|
DifferentSpacingItemDecoration(
|
||||||
|
spanCount = spanCount,
|
||||||
|
horizontalSpacing = horizontalSpacing,
|
||||||
|
verticalSpacing = verticalSpacing,
|
||||||
|
includeEdge = true
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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.getSeriesList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.adapter = seriesAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
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.seriesListLiveData.observe(this) {
|
||||||
|
if (viewModel.page - 1 == 1) {
|
||||||
|
seriesAdapter.clear()
|
||||||
|
binding.rvSeriesAll.scrollToPosition(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesAdapter.addItems(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
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
|
||||||
|
|
||||||
|
class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseViewModel() {
|
||||||
|
|
||||||
|
enum class SeriesSortType {
|
||||||
|
@SerializedName("NEWEST") NEWEST,
|
||||||
|
@SerializedName("POPULAR") POPULAR
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private var _seriesListLiveData = MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||||
|
val seriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||||
|
get() = _seriesListLiveData
|
||||||
|
|
||||||
|
var creatorId = 0L
|
||||||
|
var isLast = false
|
||||||
|
var page = 1
|
||||||
|
private val size = 10
|
||||||
|
|
||||||
|
fun getSeriesList() {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getSeriesList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
sortType = SeriesSortType.NEWEST,
|
||||||
|
page = page,
|
||||||
|
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()) {
|
||||||
|
_seriesListLiveData.value = it.data.items
|
||||||
|
} else {
|
||||||
|
isLast = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.value = it.message
|
||||||
|
} else {
|
||||||
|
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series
|
||||||
|
|
||||||
|
class SeriesRepository(private val api: SeriesApi) {
|
||||||
|
fun getSeriesList(
|
||||||
|
creatorId: Long,
|
||||||
|
sortType: SeriesListAllViewModel.SeriesSortType,
|
||||||
|
page: Int,
|
||||||
|
size: Int,
|
||||||
|
token: String
|
||||||
|
) = api.getSeriesList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
sortType = sortType,
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getSeriesDetail(seriesId: Long, token: String) = api.getSeriesDetail(
|
||||||
|
seriesId = seriesId,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getSeriesContentList(
|
||||||
|
seriesId: Long,
|
||||||
|
page: Int,
|
||||||
|
size: Int,
|
||||||
|
token: String
|
||||||
|
) = api.getSeriesContentList(
|
||||||
|
seriesId = seriesId,
|
||||||
|
page = page - 1,
|
||||||
|
size = size,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getRecommendSeriesList(token: String) = api.getRecommendSeriesList(authHeader = token)
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.content
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
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.series.detail.GetSeriesContentListItem
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemSeriesContentBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class SeriesContentAdapter(
|
||||||
|
private val onClickItem: (Long) -> Unit
|
||||||
|
) : RecyclerView.Adapter<SeriesContentAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetSeriesContentListItem>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemSeriesContentBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: GetSeriesContentListItem) {
|
||||||
|
binding.ivCover.load(item.coverImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(RoundedCornersTransformation(5.3f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvTitle.text = item.title
|
||||||
|
binding.tvDuration.text = item.duration
|
||||||
|
|
||||||
|
binding.tvPrice.visibility = View.GONE
|
||||||
|
binding.tvOwned.visibility = View.GONE
|
||||||
|
binding.tvRented.visibility = View.GONE
|
||||||
|
binding.tvPriceFree.visibility = View.GONE
|
||||||
|
|
||||||
|
if (item.isOwned) {
|
||||||
|
binding.tvOwned.visibility = View.VISIBLE
|
||||||
|
} else if (item.isRented) {
|
||||||
|
binding.tvRented.visibility = View.VISIBLE
|
||||||
|
} else if (item.price > 0) {
|
||||||
|
binding.tvPrice.text = "${item.price}"
|
||||||
|
binding.tvPrice.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.tvPriceFree.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.root.setOnClickListener { onClickItem(item.contentId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemSeriesContentBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun addItems(items: List<GetSeriesContentListItem>) {
|
||||||
|
this.items.addAll(items)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
this.items.clear()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.content
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
|
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.databinding.ActivitySeriesContentAllBinding
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class SeriesContentAllActivity : BaseActivity<ActivitySeriesContentAllBinding>(
|
||||||
|
ActivitySeriesContentAllBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: SeriesContentAllViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var adapter: SeriesContentAdapter
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val seriesId = intent.getLongExtra(Constants.EXTRA_SERIES_ID, 0)
|
||||||
|
if (seriesId <= 0) {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
|
||||||
|
viewModel.seriesId = seriesId
|
||||||
|
viewModel.getSeriesContentList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
|
||||||
|
val seriesTitle = intent.getStringExtra(Constants.EXTRA_SERIES_TITLE) ?: ""
|
||||||
|
binding.toolbar.tvBack.text = if (seriesTitle.isNotBlank()) {
|
||||||
|
"$seriesTitle - 전체회차 듣기"
|
||||||
|
} else {
|
||||||
|
" 전체회차 듣기"
|
||||||
|
}
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
adapter = SeriesContentAdapter {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.rvSeriesContentAll.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.rvSeriesContentAll.addItemDecoration(
|
||||||
|
DividerItemDecoration(
|
||||||
|
applicationContext,
|
||||||
|
DividerItemDecoration.VERTICAL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.rvSeriesContentAll.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.getSeriesContentList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
binding.rvSeriesContentAll.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
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.seriesContentListLiveData.observe(this) {
|
||||||
|
adapter.addItems(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.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.series.SeriesRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.GetSeriesContentListItem
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
|
||||||
|
class SeriesContentAllViewModel(private val repository: SeriesRepository) : 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 _seriesContentListLiveData = MutableLiveData<List<GetSeriesContentListItem>>()
|
||||||
|
val seriesContentListLiveData: LiveData<List<GetSeriesContentListItem>>
|
||||||
|
get() = _seriesContentListLiveData
|
||||||
|
|
||||||
|
var seriesId = 0L
|
||||||
|
|
||||||
|
var page = 1
|
||||||
|
private var pageSize = 10
|
||||||
|
private var isLast = false
|
||||||
|
|
||||||
|
fun getSeriesContentList() {
|
||||||
|
if (!_isLoading.value!! && !isLast) {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getSeriesContentList(
|
||||||
|
seriesId = seriesId,
|
||||||
|
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.items.isNotEmpty()) {
|
||||||
|
_seriesContentListLiveData.value = it.data.items
|
||||||
|
} else {
|
||||||
|
isLast = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.value = it.message
|
||||||
|
} else {
|
||||||
|
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
data class GetSeriesContentListResponse(
|
||||||
|
@SerializedName("totalCount") val totalCount: Int,
|
||||||
|
@SerializedName("items") val items: List<GetSeriesContentListItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class GetSeriesContentListItem(
|
||||||
|
@SerializedName("contentId") val contentId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("coverImage") val coverImage: String,
|
||||||
|
@SerializedName("releaseDate") val releaseDate: String,
|
||||||
|
@SerializedName("duration") val duration: String,
|
||||||
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("isRented") var isRented: Boolean,
|
||||||
|
@SerializedName("isOwned") var isOwned: Boolean
|
||||||
|
) : Parcelable
|
|
@ -0,0 +1,36 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class GetSeriesDetailResponse(
|
||||||
|
@SerializedName("seriesId") val seriesId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("coverImage") val coverImage: String,
|
||||||
|
@SerializedName("introduction") val introduction: String,
|
||||||
|
@SerializedName("genre") val genre: String,
|
||||||
|
@SerializedName("isAdult") val isAdult: Boolean,
|
||||||
|
@SerializedName("writer") val writer: String?,
|
||||||
|
@SerializedName("studio") val studio: String?,
|
||||||
|
@SerializedName("publishedDate") val publishedDate: String,
|
||||||
|
@SerializedName("creator") val creator: GetSeriesDetailCreator,
|
||||||
|
@SerializedName("rentalMinPrice") var rentalMinPrice: Int,
|
||||||
|
@SerializedName("rentalMaxPrice") var rentalMaxPrice: Int,
|
||||||
|
@SerializedName("rentalPeriod") val rentalPeriod: Int,
|
||||||
|
@SerializedName("minPrice") var minPrice: Int,
|
||||||
|
@SerializedName("maxPrice") var maxPrice: Int,
|
||||||
|
@SerializedName("keywordList") var keywordList: List<String>,
|
||||||
|
@SerializedName("publishedDaysOfWeek") var publishedDaysOfWeek: String,
|
||||||
|
@SerializedName("contentList") val contentList: List<GetSeriesContentListItem>,
|
||||||
|
@SerializedName("contentCount") val contentCount: Int
|
||||||
|
) : Parcelable {
|
||||||
|
@Parcelize
|
||||||
|
data class GetSeriesDetailCreator(
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileImage") val profileImage: String,
|
||||||
|
@SerializedName("isFollow") var isFollow: Boolean
|
||||||
|
) : Parcelable
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import coil.load
|
||||||
|
import coil.size.Scale
|
||||||
|
import coil.transform.BlurTransformation
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import coil.transform.RoundedCornersTransformation
|
||||||
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.shape.ShapeAppearanceModel
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
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.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivitySeriesDetailBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
|
||||||
|
ActivitySeriesDetailBinding::inflate
|
||||||
|
) {
|
||||||
|
private val viewModel: SeriesDetailViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val seriesId = intent.getLongExtra(Constants.EXTRA_SERIES_ID, 0)
|
||||||
|
if (seriesId <= 0) {
|
||||||
|
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
bindData()
|
||||||
|
|
||||||
|
viewModel.seriesId = seriesId
|
||||||
|
viewModel.getSeriesDetail()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
binding.ivBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
setupTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupTab() {
|
||||||
|
val tabs = binding.tabs
|
||||||
|
tabs.addTab(tabs.newTab().setText("홈").setTag("home"))
|
||||||
|
tabs.addTab(tabs.newTab().setText("작품소개").setTag("introduction"))
|
||||||
|
|
||||||
|
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||||
|
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||||
|
val tag = tab.tag as String
|
||||||
|
changeFragment(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTabUnselected(tab: TabLayout.Tab) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTabReselected(tab: TabLayout.Tab) {
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeFragment(tag: String) {
|
||||||
|
val fragmentManager = supportFragmentManager
|
||||||
|
val fragmentTransaction = fragmentManager.beginTransaction()
|
||||||
|
|
||||||
|
val fragment = when (tag) {
|
||||||
|
"introduction" -> SeriesDetailIntroductionFragment()
|
||||||
|
else -> SeriesDetailHomeFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putParcelable(Constants.EXTRA_SERIES, viewModel.seriesDetailResponse)
|
||||||
|
fragment.arguments = bundle
|
||||||
|
|
||||||
|
fragmentTransaction.replace(R.id.container, fragment, tag)
|
||||||
|
fragmentTransaction.setPrimaryNavigationFragment(fragment)
|
||||||
|
fragmentTransaction.setReorderingAllowed(true)
|
||||||
|
fragmentTransaction.commitNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
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.seriesDetailLiveData.observe(this) {
|
||||||
|
setSeriesBg(it.coverImage)
|
||||||
|
setSeriesInfo(it)
|
||||||
|
setSeriesCreator(it.creator)
|
||||||
|
setSeriesKeywordChipList(it.keywordList)
|
||||||
|
|
||||||
|
changeFragment("home")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesKeywordChipList(keywordList: List<String>) {
|
||||||
|
binding.chipGroup.isSingleLine = true
|
||||||
|
binding.chipGroup.isHorizontalScrollBarEnabled = false
|
||||||
|
|
||||||
|
for (keyword in keywordList) {
|
||||||
|
val chip = Chip(this)
|
||||||
|
chip.text = keyword
|
||||||
|
chip.isClickable = false
|
||||||
|
chip.isCheckable = false
|
||||||
|
chip.textSize = 12f
|
||||||
|
chip.chipStrokeWidth = 0f
|
||||||
|
chip.setChipBackgroundColorResource(R.color.color_222222)
|
||||||
|
|
||||||
|
val shapeAppearanceModel = ShapeAppearanceModel.Builder()
|
||||||
|
.setAllCornerSizes(26.7f.dpToPx())
|
||||||
|
.build()
|
||||||
|
chip.shapeAppearanceModel = shapeAppearanceModel
|
||||||
|
|
||||||
|
chip.setPadding(0, 0, 0, 0)
|
||||||
|
chip.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_d2d2d2))
|
||||||
|
chip.typeface = ResourcesCompat.getFont(applicationContext, R.font.gmarket_sans_medium)
|
||||||
|
binding.chipGroup.addView(chip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun setSeriesInfo(seriesDetail: GetSeriesDetailResponse) {
|
||||||
|
binding.ivCover.load(seriesDetail.coverImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(RoundedCornersTransformation(5f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvTitle.text = seriesDetail.title
|
||||||
|
binding.tvGenre.text = seriesDetail.genre
|
||||||
|
binding.tvPublishedDaysOfWeek.text = "${seriesDetail.publishedDaysOfWeek} 연재"
|
||||||
|
|
||||||
|
if (seriesDetail.isAdult) {
|
||||||
|
binding.tvAge19.visibility = View.VISIBLE
|
||||||
|
binding.tvAgeAll.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.tvAge19.visibility = View.GONE
|
||||||
|
binding.tvAgeAll.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesCreator(creator: GetSeriesDetailResponse.GetSeriesDetailCreator) {
|
||||||
|
binding.tvNickname.text = creator.nickname
|
||||||
|
binding.ivProfile.load(creator.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SharedPreferenceManager.userId != creator.creatorId) {
|
||||||
|
binding.ivFollow.visibility = View.VISIBLE
|
||||||
|
binding.ivFollow.setImageResource(
|
||||||
|
if (creator.isFollow) {
|
||||||
|
R.drawable.btn_following_big
|
||||||
|
} else {
|
||||||
|
R.drawable.btn_follow_big
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivFollow.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.ivFollow.setOnClickListener {
|
||||||
|
if (creator.isFollow) {
|
||||||
|
viewModel.unFollow(creator.creatorId) {
|
||||||
|
creator.isFollow = false
|
||||||
|
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viewModel.follow(creator.creatorId) {
|
||||||
|
creator.isFollow = true
|
||||||
|
binding.ivFollow.setImageResource(R.drawable.btn_following_big)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesBg(coverImage: String) {
|
||||||
|
binding.ivBg.load(coverImage) {
|
||||||
|
transformations(
|
||||||
|
BlurTransformation(
|
||||||
|
this@SeriesDetailActivity,
|
||||||
|
25f,
|
||||||
|
2.5f
|
||||||
|
)
|
||||||
|
)
|
||||||
|
scale(Scale.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAllActivity
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.databinding.FragmentSeriesDetailHomeBinding
|
||||||
|
|
||||||
|
class SeriesDetailHomeFragment : BaseFragment<FragmentSeriesDetailHomeBinding>(
|
||||||
|
FragmentSeriesDetailHomeBinding::inflate
|
||||||
|
) {
|
||||||
|
private var seriesDetailResponse: GetSeriesDetailResponse? = null
|
||||||
|
|
||||||
|
private lateinit var adapter: SeriesContentAdapter
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (arguments != null) {
|
||||||
|
seriesDetailResponse = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
requireArguments().getParcelable(
|
||||||
|
Constants.EXTRA_SERIES,
|
||||||
|
GetSeriesDetailResponse::class.java
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
requireArguments().getParcelable(Constants.EXTRA_SERIES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
if (seriesDetailResponse != null) {
|
||||||
|
setContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun setContent() {
|
||||||
|
binding.tvTotalCount.text = "(${seriesDetailResponse!!.contentCount})"
|
||||||
|
binding.llContentAll.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(requireActivity(), SeriesContentAllActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_SERIES_ID, seriesDetailResponse!!.seriesId)
|
||||||
|
putExtra(Constants.EXTRA_SERIES_TITLE, seriesDetailResponse!!.title)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter = SeriesContentAdapter {
|
||||||
|
startActivity(
|
||||||
|
Intent(requireActivity(), AudioContentDetailActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.rvContent.layoutManager = LinearLayoutManager(
|
||||||
|
requireContext(),
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.rvContent.addItemDecoration(
|
||||||
|
DividerItemDecoration(
|
||||||
|
requireContext(),
|
||||||
|
DividerItemDecoration.VERTICAL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.rvContent.adapter = adapter
|
||||||
|
adapter.addItems(seriesDetailResponse!!.contentList)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.chip.ChipGroup
|
||||||
|
import com.google.android.material.shape.ShapeAppearanceModel
|
||||||
|
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.databinding.FragmentSeriesDetailIntroductionBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class SeriesDetailIntroductionFragment : BaseFragment<FragmentSeriesDetailIntroductionBinding>(
|
||||||
|
FragmentSeriesDetailIntroductionBinding::inflate
|
||||||
|
) {
|
||||||
|
private var seriesDetailResponse: GetSeriesDetailResponse? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (arguments != null) {
|
||||||
|
seriesDetailResponse = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
requireArguments().getParcelable(
|
||||||
|
Constants.EXTRA_SERIES,
|
||||||
|
GetSeriesDetailResponse::class.java
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
requireArguments().getParcelable(Constants.EXTRA_SERIES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
if (seriesDetailResponse != null) {
|
||||||
|
setSeriesKeywordChipList(seriesDetailResponse!!.keywordList)
|
||||||
|
setSeriesIntroduction(seriesDetailResponse!!.introduction)
|
||||||
|
setSeriesPrice()
|
||||||
|
setSeriesInfo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesPrice() {
|
||||||
|
val rentalMinPrice = seriesDetailResponse!!.rentalMinPrice
|
||||||
|
val rentalMaxPrice = seriesDetailResponse!!.rentalMaxPrice
|
||||||
|
val minPrice = seriesDetailResponse!!.minPrice
|
||||||
|
val maxPrice = seriesDetailResponse!!.maxPrice
|
||||||
|
|
||||||
|
binding.tvRentalPrice.text = if (rentalMinPrice == rentalMaxPrice) {
|
||||||
|
if (rentalMaxPrice == 0) {
|
||||||
|
"무료(15일)"
|
||||||
|
} else {
|
||||||
|
"$rentalMaxPrice(15일)"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"${if (rentalMinPrice == 0) "무료" else rentalMinPrice} ~ ${rentalMaxPrice}캔 (15일)"
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPrice.text = if (minPrice == maxPrice) {
|
||||||
|
if (maxPrice == 0) {
|
||||||
|
"무료"
|
||||||
|
} else {
|
||||||
|
"$maxPrice"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"${if (minPrice == 0) "무료" else minPrice} ~ ${maxPrice}캔"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun setSeriesInfo() {
|
||||||
|
binding.tvGenre.text = seriesDetailResponse!!.genre
|
||||||
|
binding.tvIsAdult.text = if (seriesDetailResponse!!.isAdult) {
|
||||||
|
"19세 이상"
|
||||||
|
} else {
|
||||||
|
"전체연령가"
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPublishedDate.text = seriesDetailResponse!!.publishedDate
|
||||||
|
binding.tvPublishedDaysOfWeek.text =
|
||||||
|
if (seriesDetailResponse!!.publishedDaysOfWeek == "랜덤") {
|
||||||
|
seriesDetailResponse!!.publishedDaysOfWeek
|
||||||
|
} else {
|
||||||
|
"${seriesDetailResponse!!.publishedDaysOfWeek}요일"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seriesDetailResponse!!.writer != null) {
|
||||||
|
binding.tvWriter.visibility = View.VISIBLE
|
||||||
|
binding.tvWriterLabel.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
binding.tvWriter.text = seriesDetailResponse!!.writer
|
||||||
|
} else {
|
||||||
|
binding.tvWriter.visibility = View.GONE
|
||||||
|
binding.tvWriterLabel.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seriesDetailResponse!!.studio != null) {
|
||||||
|
binding.tvStudio.visibility = View.VISIBLE
|
||||||
|
binding.tvStudioLabel.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
binding.tvStudio.text = seriesDetailResponse!!.studio
|
||||||
|
} else {
|
||||||
|
binding.tvStudio.visibility = View.GONE
|
||||||
|
binding.tvStudioLabel.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesIntroduction(introduction: String) {
|
||||||
|
binding.tvIntroduce.text = introduction
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSeriesKeywordChipList(keywordList: List<String>) {
|
||||||
|
binding.chipGroup.isHorizontalScrollBarEnabled = false
|
||||||
|
|
||||||
|
for (keyword in keywordList) {
|
||||||
|
val chip = Chip(requireActivity())
|
||||||
|
chip.text = keyword
|
||||||
|
chip.isClickable = false
|
||||||
|
chip.isCheckable = false
|
||||||
|
chip.textSize = 12f
|
||||||
|
chip.chipStrokeWidth = 0f
|
||||||
|
chip.setChipBackgroundColorResource(R.color.color_222222)
|
||||||
|
|
||||||
|
val shapeAppearanceModel = ShapeAppearanceModel.Builder()
|
||||||
|
.setAllCornerSizes(26.7f.dpToPx())
|
||||||
|
.build()
|
||||||
|
chip.shapeAppearanceModel = shapeAppearanceModel
|
||||||
|
|
||||||
|
chip.setEnsureMinTouchTargetSize(false)
|
||||||
|
chip.setPadding(0, 0, 0, 0)
|
||||||
|
chip.setTextColor(ContextCompat.getColor(requireContext(), R.color.color_d2d2d2))
|
||||||
|
chip.typeface = ResourcesCompat.getFont(requireContext(), R.font.gmarket_sans_medium)
|
||||||
|
binding.chipGroup.addView(chip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
package kr.co.vividnext.sodalive.audio_content.series.detail
|
||||||
|
|
||||||
|
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.series.SeriesRepository
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.user.UserRepository
|
||||||
|
|
||||||
|
class SeriesDetailViewModel(
|
||||||
|
private val repository: SeriesRepository,
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) : 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 _seriesDetailLiveData = MutableLiveData<GetSeriesDetailResponse>()
|
||||||
|
val seriesDetailLiveData: LiveData<GetSeriesDetailResponse>
|
||||||
|
get() = _seriesDetailLiveData
|
||||||
|
|
||||||
|
var seriesId = 0L
|
||||||
|
|
||||||
|
lateinit var seriesDetailResponse: GetSeriesDetailResponse
|
||||||
|
|
||||||
|
fun getSeriesDetail() {
|
||||||
|
_isLoading.value = true
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getSeriesDetail(
|
||||||
|
seriesId = seriesId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
seriesDetailResponse = it.data
|
||||||
|
_seriesDetailLiveData.value = seriesDetailResponse
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.value = it.message
|
||||||
|
} else {
|
||||||
|
_toastLiveData.value = "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isLoading.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun follow(creatorId: Long, onSuccess: () -> Unit) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
userRepository.creatorFollow(
|
||||||
|
creatorId,
|
||||||
|
"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.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unFollow(creatorId: Long, onSuccess: () -> Unit) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
userRepository.creatorUnFollow(
|
||||||
|
creatorId,
|
||||||
|
"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.value = false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,14 +20,17 @@ object Constants {
|
||||||
const val EXTRA_DATA = "extra_data"
|
const val EXTRA_DATA = "extra_data"
|
||||||
const val EXTRA_TERMS = "extra_terms"
|
const val EXTRA_TERMS = "extra_terms"
|
||||||
const val EXTRA_EVENT = "extra_event"
|
const val EXTRA_EVENT = "extra_event"
|
||||||
|
const val EXTRA_SERIES = "extra_series"
|
||||||
const val EXTRA_NOTICE = "extra_notice"
|
const val EXTRA_NOTICE = "extra_notice"
|
||||||
const val EXTRA_ROOM_ID = "extra_room_id"
|
const val EXTRA_ROOM_ID = "extra_room_id"
|
||||||
const val EXTRA_USER_ID = "extra_user_id"
|
const val EXTRA_USER_ID = "extra_user_id"
|
||||||
const val EXTRA_THEME_ID = "extra_theme_id"
|
const val EXTRA_THEME_ID = "extra_theme_id"
|
||||||
|
const val EXTRA_SERIES_ID = "extra_series_id"
|
||||||
const val EXTRA_NICKNAME = "extra_nickname"
|
const val EXTRA_NICKNAME = "extra_nickname"
|
||||||
const val EXTRA_MESSAGE_ID = "extra_message_id"
|
const val EXTRA_MESSAGE_ID = "extra_message_id"
|
||||||
const val EXTRA_ROOM_DETAIL = "extra_room_detail"
|
const val EXTRA_ROOM_DETAIL = "extra_room_detail"
|
||||||
const val EXTRA_MESSAGE_BOX = "extra_message_box"
|
const val EXTRA_MESSAGE_BOX = "extra_message_box"
|
||||||
|
const val EXTRA_SERIES_TITLE = "extra_series_title"
|
||||||
const val EXTRA_TEXT_MESSAGE = "extra_text_message"
|
const val EXTRA_TEXT_MESSAGE = "extra_text_message"
|
||||||
const val EXTRA_LIVE_TIME_NOW = "extra_live_time_now"
|
const val EXTRA_LIVE_TIME_NOW = "extra_live_time_now"
|
||||||
const val EXTRA_RESULT_ROULETTE = "extra_result_roulette"
|
const val EXTRA_RESULT_ROULETTE = "extra_result_roulette"
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package kr.co.vividnext.sodalive.common
|
||||||
|
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
|
class DifferentSpacingItemDecoration(
|
||||||
|
private val spanCount: Int,
|
||||||
|
private val horizontalSpacing: Int,
|
||||||
|
private val verticalSpacing: Int,
|
||||||
|
private val includeEdge: Boolean
|
||||||
|
) : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
val position = parent.getChildAdapterPosition(view) // 아이템의 위치
|
||||||
|
val column = position % spanCount // 아이템의 열 위치
|
||||||
|
|
||||||
|
if (includeEdge) {
|
||||||
|
outRect.left = horizontalSpacing - column * horizontalSpacing / spanCount
|
||||||
|
outRect.right = (column + 1) * horizontalSpacing / spanCount
|
||||||
|
|
||||||
|
if (position < spanCount) {
|
||||||
|
outRect.top = verticalSpacing
|
||||||
|
}
|
||||||
|
outRect.bottom = verticalSpacing
|
||||||
|
} else {
|
||||||
|
outRect.left = column * horizontalSpacing / spanCount
|
||||||
|
outRect.right = horizontalSpacing - (column + 1) * horizontalSpacing / spanCount
|
||||||
|
|
||||||
|
if (position >= spanCount) {
|
||||||
|
outRect.top = verticalSpacing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,11 +19,16 @@ import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerViewModel
|
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.curation.AudioContentMainCurationViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
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.order.AudioContentMainOrderListViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
|
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
|
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesApi
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAllViewModel
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
|
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeViewModel
|
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeViewModel
|
||||||
import kr.co.vividnext.sodalive.common.ApiBuilder
|
import kr.co.vividnext.sodalive.common.ApiBuilder
|
||||||
|
@ -77,7 +82,10 @@ import kr.co.vividnext.sodalive.mypage.can.CanRepository
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel
|
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgViewModel
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponViewModel
|
import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponViewModel
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempRepository
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.payment.CanTempApi
|
||||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
||||||
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
|
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
|
||||||
|
@ -116,6 +124,7 @@ import org.koin.dsl.module
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
|
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class AppDI(private val context: Context, isDebugMode: Boolean) {
|
class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
private val baseUrl = BuildConfig.BASE_URL
|
private val baseUrl = BuildConfig.BASE_URL
|
||||||
|
@ -138,6 +147,9 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
OkHttpClient().newBuilder()
|
OkHttpClient().newBuilder()
|
||||||
.addInterceptor(logging)
|
.addInterceptor(logging)
|
||||||
.authenticator(TokenAuthenticator(get()))
|
.authenticator(TokenAuthenticator(get()))
|
||||||
|
.connectTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +163,14 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
}
|
}
|
||||||
|
|
||||||
single { ApiBuilder().build(get(), CanApi::class.java) }
|
single { ApiBuilder().build(get(), CanApi::class.java) }
|
||||||
|
single { ApiBuilder().build(get(), CanTempApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), AuthApi::class.java) }
|
single { ApiBuilder().build(get(), AuthApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), UserApi::class.java) }
|
single { ApiBuilder().build(get(), UserApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), MenuApi::class.java) }
|
single { ApiBuilder().build(get(), MenuApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), LiveApi::class.java) }
|
single { ApiBuilder().build(get(), LiveApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), TermsApi::class.java) }
|
single { ApiBuilder().build(get(), TermsApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), EventApi::class.java) }
|
single { ApiBuilder().build(get(), EventApi::class.java) }
|
||||||
|
single { ApiBuilder().build(get(), SeriesApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), ReportApi::class.java) }
|
single { ApiBuilder().build(get(), ReportApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), LiveRecommendApi::class.java) }
|
single { ApiBuilder().build(get(), LiveRecommendApi::class.java) }
|
||||||
single { ApiBuilder().build(get(), ExplorerApi::class.java) }
|
single { ApiBuilder().build(get(), ExplorerApi::class.java) }
|
||||||
|
@ -181,6 +195,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { CanStatusViewModel(get()) }
|
viewModel { CanStatusViewModel(get()) }
|
||||||
viewModel { CanChargePgViewModel(get()) }
|
viewModel { CanChargePgViewModel(get()) }
|
||||||
viewModel { CanPaymentViewModel(get()) }
|
viewModel { CanPaymentViewModel(get()) }
|
||||||
|
viewModel { CanPaymentTempViewModel(get()) }
|
||||||
viewModel { LiveRoomDetailViewModel(get()) }
|
viewModel { LiveRoomDetailViewModel(get()) }
|
||||||
viewModel { LiveRoomCreateViewModel(get()) }
|
viewModel { LiveRoomCreateViewModel(get()) }
|
||||||
viewModel { LiveTagViewModel(get()) }
|
viewModel { LiveTagViewModel(get()) }
|
||||||
|
@ -195,11 +210,14 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { VoiceMessageViewModel(get()) }
|
viewModel { VoiceMessageViewModel(get()) }
|
||||||
viewModel { VoiceMessageWriteViewModel(get()) }
|
viewModel { VoiceMessageWriteViewModel(get()) }
|
||||||
viewModel { SelectMessageRecipientViewModel(get(), get()) }
|
viewModel { SelectMessageRecipientViewModel(get(), get()) }
|
||||||
viewModel { SignOutViewModel(get()) }
|
|
||||||
viewModel { NoticeViewModel(get()) }
|
viewModel { NoticeViewModel(get()) }
|
||||||
viewModel { EventViewModel(get()) }
|
viewModel { EventViewModel(get()) }
|
||||||
viewModel { NotificationSettingsViewModel(get()) }
|
viewModel { NotificationSettingsViewModel(get()) }
|
||||||
viewModel { SettingsViewModel(get()) }
|
viewModel { SettingsViewModel(get()) }
|
||||||
|
viewModel { SeriesDetailViewModel(get(), get()) }
|
||||||
|
viewModel { SeriesListAllViewModel(get()) }
|
||||||
|
viewModel { SeriesContentAllViewModel(get()) }
|
||||||
|
viewModel { SignOutViewModel(get()) }
|
||||||
viewModel { TextMessageDetailViewModel(get()) }
|
viewModel { TextMessageDetailViewModel(get()) }
|
||||||
viewModel { LiveReservationStatusViewModel(get()) }
|
viewModel { LiveReservationStatusViewModel(get()) }
|
||||||
viewModel { AudioContentMainBannerViewModel(get()) }
|
viewModel { AudioContentMainBannerViewModel(get()) }
|
||||||
|
@ -207,7 +225,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
viewModel { AudioContentMainCurationViewModel(get()) }
|
viewModel { AudioContentMainCurationViewModel(get()) }
|
||||||
viewModel { AudioContentMainOrderListViewModel(get()) }
|
viewModel { AudioContentMainOrderListViewModel(get()) }
|
||||||
viewModel { AudioContentMainNewContentViewModel(get()) }
|
viewModel { AudioContentMainNewContentViewModel(get()) }
|
||||||
viewModel { AudioContentMainNewContentCreatorViewModel(get()) }
|
viewModel { AudioContentMainRecommendSeriesViewModel(get()) }
|
||||||
viewModel { AudioContentViewModel(get()) }
|
viewModel { AudioContentViewModel(get()) }
|
||||||
viewModel { AudioContentOrderListViewModel(get()) }
|
viewModel { AudioContentOrderListViewModel(get()) }
|
||||||
viewModel { AudioContentUploadViewModel(get()) }
|
viewModel { AudioContentUploadViewModel(get()) }
|
||||||
|
@ -238,11 +256,13 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||||
private val repositoryModule = module {
|
private val repositoryModule = module {
|
||||||
factory { UserRepository(get()) }
|
factory { UserRepository(get()) }
|
||||||
factory { TermsRepository(get()) }
|
factory { TermsRepository(get()) }
|
||||||
|
factory { SeriesRepository(get()) }
|
||||||
factory { LiveRepository(get(), get(), get()) }
|
factory { LiveRepository(get(), get(), get()) }
|
||||||
factory { EventRepository(get()) }
|
factory { EventRepository(get()) }
|
||||||
factory { LiveRecommendRepository(get()) }
|
factory { LiveRecommendRepository(get()) }
|
||||||
factory { AuthRepository(get()) }
|
factory { AuthRepository(get()) }
|
||||||
factory { CanRepository(get()) }
|
factory { CanRepository(get()) }
|
||||||
|
factory { CanPaymentTempRepository(get()) }
|
||||||
factory { LiveTagRepository(get()) }
|
factory { LiveTagRepository(get()) }
|
||||||
factory { ReportRepository(get()) }
|
factory { ReportRepository(get()) }
|
||||||
factory { ExplorerRepository(get()) }
|
factory { ExplorerRepository(get()) }
|
||||||
|
|
|
@ -121,7 +121,11 @@ class ExplorerAdapter(
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
holder.bind(items[position])
|
val item = items[position]
|
||||||
|
|
||||||
|
if (item.creators.isNotEmpty()) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount() = items.size
|
override fun getItemCount() = items.size
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package kr.co.vividnext.sodalive.explorer.profile
|
package kr.co.vividnext.sodalive.explorer.profile
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
|
||||||
data class GetCreatorProfileResponse(
|
data class GetCreatorProfileResponse(
|
||||||
|
@ -20,6 +21,8 @@ data class GetCreatorProfileResponse(
|
||||||
val cheers: GetCheersResponse,
|
val cheers: GetCheersResponse,
|
||||||
@SerializedName("activitySummary")
|
@SerializedName("activitySummary")
|
||||||
val activitySummary: GetCreatorActivitySummary,
|
val activitySummary: GetCreatorActivitySummary,
|
||||||
|
@SerializedName("seriesList")
|
||||||
|
val seriesList: List<GetSeriesListResponse.SeriesListItem>,
|
||||||
@SerializedName("isBlock")
|
@SerializedName("isBlock")
|
||||||
val isBlock: Boolean
|
val isBlock: Boolean
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,6 +26,10 @@ import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
|
import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
|
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
|
||||||
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAdapter
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllActivity
|
||||||
|
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
|
||||||
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
import kr.co.vividnext.sodalive.base.SodaDialog
|
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||||
|
@ -42,6 +46,7 @@ import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAda
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.series.UserProfileSeriesListAdapter
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.loadUrl
|
import kr.co.vividnext.sodalive.extensions.loadUrl
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
|
@ -70,6 +75,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
private lateinit var loadingDialog: LoadingDialog
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
private lateinit var liveAdapter: UserProfileLiveAdapter
|
private lateinit var liveAdapter: UserProfileLiveAdapter
|
||||||
private lateinit var audioContentAdapter: AudioContentAdapter
|
private lateinit var audioContentAdapter: AudioContentAdapter
|
||||||
|
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
||||||
private lateinit var donationAdapter: UserProfileDonationAdapter
|
private lateinit var donationAdapter: UserProfileDonationAdapter
|
||||||
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
||||||
|
|
||||||
|
@ -117,6 +123,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
setupLiveView()
|
setupLiveView()
|
||||||
setupDonationView()
|
setupDonationView()
|
||||||
setupFanTalkView()
|
setupFanTalkView()
|
||||||
|
setupSeriesListView()
|
||||||
setupAudioContentListView()
|
setupAudioContentListView()
|
||||||
setupCreatorCommunityView()
|
setupCreatorCommunityView()
|
||||||
}
|
}
|
||||||
|
@ -415,6 +422,65 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
rvCheers.adapter = cheersAdapter
|
rvCheers.adapter = cheersAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupSeriesListView() {
|
||||||
|
binding.layoutCreatorChannelSeries.tvAll.setOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, SeriesListAllActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_USER_ID, userId)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val recyclerView = binding.layoutCreatorChannelSeries.rvSeries
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.HORIZONTAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
seriesAdapter = UserProfileSeriesListAdapter(
|
||||||
|
onClickItem = {
|
||||||
|
startActivity(
|
||||||
|
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
|
||||||
|
putExtra(Constants.EXTRA_SERIES_ID, it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onClickCreator = {},
|
||||||
|
isVisibleCreator = 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 = 0
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesAdapter.itemCount - 1 -> {
|
||||||
|
outRect.right = 0
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
recyclerView.adapter = seriesAdapter
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupAudioContentListView() {
|
private fun setupAudioContentListView() {
|
||||||
binding.layoutUserProfileAudioContent.tvAll.setOnClickListener {
|
binding.layoutUserProfileAudioContent.tvAll.setOnClickListener {
|
||||||
val intent = Intent(applicationContext, AudioContentActivity::class.java)
|
val intent = Intent(applicationContext, AudioContentActivity::class.java)
|
||||||
|
@ -517,6 +583,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
|
|
||||||
viewModel.creatorProfileLiveData.observe(this) {
|
viewModel.creatorProfileLiveData.observe(this) {
|
||||||
setCheers(it.cheers)
|
setCheers(it.cheers)
|
||||||
|
setSeriesList(it.seriesList)
|
||||||
setCreatorProfile(it.creator)
|
setCreatorProfile(it.creator)
|
||||||
setAudioContentList(it.contentList)
|
setAudioContentList(it.contentList)
|
||||||
setLiveRoomList(it.liveRoomList)
|
setLiveRoomList(it.liveRoomList)
|
||||||
|
@ -550,6 +617,19 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun setSeriesList(seriesList: List<GetSeriesListResponse.SeriesListItem>) {
|
||||||
|
if (seriesList.isNotEmpty()) {
|
||||||
|
binding.layoutCreatorChannelSeries.root.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.layoutCreatorChannelSeries.root.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesAdapter.items.clear()
|
||||||
|
seriesAdapter.items.addAll(seriesList)
|
||||||
|
seriesAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun setCreatorProfile(creator: CreatorResponse) {
|
private fun setCreatorProfile(creator: CreatorResponse) {
|
||||||
val layoutUserProfile = binding.layoutUserProfile
|
val layoutUserProfile = binding.layoutUserProfile
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.series
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
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.audio_content.series.GetSeriesListResponse
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemSeriesListBigBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
|
||||||
|
class UserProfileSeriesListAdapter(
|
||||||
|
private val onClickItem: (Long) -> Unit,
|
||||||
|
private val onClickCreator: (Long) -> Unit,
|
||||||
|
private val isVisibleCreator: Boolean
|
||||||
|
) : RecyclerView.Adapter<UserProfileSeriesListAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetSeriesListResponse.SeriesListItem>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemSeriesListBigBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
fun bind(item: GetSeriesListResponse.SeriesListItem) {
|
||||||
|
binding.ivCover.load(item.coverImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.bg_placeholder)
|
||||||
|
transformations(RoundedCornersTransformation(5f.dpToPx()))
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvTitle.text = item.title
|
||||||
|
binding.tvSeriesContentCount.text = "총 ${item.numberOfContent}화"
|
||||||
|
binding.tvPublishedDaysOfWeek.text = item.publishedDaysOfWeek
|
||||||
|
|
||||||
|
binding.tvNew.visibility = if (item.isNew) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPopular.visibility = if (item.isPopular) {
|
||||||
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isComplete) {
|
||||||
|
binding.tvNew.visibility = View.GONE
|
||||||
|
binding.tvComplete.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.tvComplete.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVisibleCreator) {
|
||||||
|
binding.llCreator.visibility = View.VISIBLE
|
||||||
|
binding.tvCreator.text = item.creator.nickname
|
||||||
|
binding.ivCreator.load(item.creator.profileImage) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
binding.llCreator.setOnClickListener { onClickCreator(item.creator.creatorId) }
|
||||||
|
} else {
|
||||||
|
binding.llCreator.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.root.setOnClickListener { onClickItem(item.seriesId) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
|
||||||
|
ItemSeriesListBigBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.count()
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun addItems(items: List<GetSeriesListResponse.SeriesListItem>) {
|
||||||
|
this.items.addAll(items)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
this.items.clear()
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationStatusResp
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationTotalResponse
|
import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationTotalResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessage
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessage
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest
|
import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
||||||
|
@ -156,11 +157,11 @@ interface LiveApi {
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<Any>>
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
@POST("/live/room/donation")
|
@POST("/live/room/donation/v2")
|
||||||
fun donation(
|
fun donation(
|
||||||
@Body request: LiveRoomDonationRequest,
|
@Body request: LiveRoomDonationRequest,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<String>>
|
): Single<ApiResponse<LiveRoomDonationResponse>>
|
||||||
|
|
||||||
@POST("/live/room/donation/refund/{id}")
|
@POST("/live/room/donation/refund/{id}")
|
||||||
fun refundDonation(
|
fun refundDonation(
|
||||||
|
|
|
@ -129,8 +129,6 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
val intent = Intent(requireContext(), LiveRoomCreateActivity::class.java)
|
val intent = Intent(requireContext(), LiveRoomCreateActivity::class.java)
|
||||||
activityResultLauncher.launch(intent)
|
activityResultLauncher.launch(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener { refreshSummary() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshSummary() {
|
private fun refreshSummary() {
|
||||||
|
@ -140,8 +138,6 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
|
|
||||||
message = "라이브를 불러오고 있습니다."
|
message = "라이브를 불러오고 있습니다."
|
||||||
viewModel.getSummary()
|
viewModel.getSummary()
|
||||||
|
|
||||||
binding.swipeRefreshLayout.isRefreshing = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
@ -184,7 +180,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
.setIndicatorVisibility(View.GONE)
|
.setIndicatorVisibility(View.GONE)
|
||||||
.setIndicatorSliderColor(
|
.setIndicatorSliderColor(
|
||||||
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
||||||
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
|
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
|
||||||
)
|
)
|
||||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||||
.setIndicatorHeight(4f.dpToPx().toInt())
|
.setIndicatorHeight(4f.dpToPx().toInt())
|
||||||
|
@ -287,6 +283,11 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
startActivity(Intent(requireContext(), LiveNowAllActivity::class.java))
|
startActivity(Intent(requireContext(), LiveNowAllActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding
|
||||||
|
.layoutLiveNow
|
||||||
|
.llRefresh
|
||||||
|
.setOnClickListener { refreshSummary() }
|
||||||
|
|
||||||
val recyclerView = binding
|
val recyclerView = binding
|
||||||
.layoutLiveNow
|
.layoutLiveNow
|
||||||
.rvSudaNow
|
.rvSudaNow
|
||||||
|
@ -486,7 +487,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
||||||
.setIndicatorVisibility(View.GONE)
|
.setIndicatorVisibility(View.GONE)
|
||||||
.setIndicatorSliderColor(
|
.setIndicatorSliderColor(
|
||||||
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
||||||
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
|
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
|
||||||
)
|
)
|
||||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||||
.setIndicatorHeight(4f.dpToPx().toInt())
|
.setIndicatorHeight(4f.dpToPx().toInt())
|
||||||
|
|
|
@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.live.room.create.CreateLiveRoomResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
|
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.DeleteLiveRoomDonationMessage
|
import kr.co.vividnext.sodalive.live.room.donation.DeleteLiveRoomDonationMessage
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest
|
import kr.co.vividnext.sodalive.live.room.kick_out.LiveRoomKickOutRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.menu.MenuApi
|
import kr.co.vividnext.sodalive.live.room.menu.MenuApi
|
||||||
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
|
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
|
||||||
|
@ -163,7 +164,7 @@ class LiveRepository(
|
||||||
can: Int,
|
can: Int,
|
||||||
message: String,
|
message: String,
|
||||||
token: String
|
token: String
|
||||||
): Single<ApiResponse<String>> {
|
): Single<ApiResponse<LiveRoomDonationResponse>> {
|
||||||
return api.donation(
|
return api.donation(
|
||||||
request = LiveRoomDonationRequest(
|
request = LiveRoomDonationRequest(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
|
@ -68,6 +68,7 @@ import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageDialog
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRankingDialog
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRankingDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileDialog
|
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileListAdapter
|
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileListAdapter
|
||||||
|
@ -124,6 +125,16 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val signatureList = mutableListOf<LiveRoomDonationResponse>()
|
||||||
|
private var signature: LiveRoomDonationResponse? = null
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
|
||||||
|
if (field != null) {
|
||||||
|
showSignatureImage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var isShowSignatureImage = false
|
private var isShowSignatureImage = false
|
||||||
|
|
||||||
private val countDownTimer = object : CountDownTimer(remainingNoChattingTime * 1000, 1000) {
|
private val countDownTimer = object : CountDownTimer(remainingNoChattingTime * 1000, 1000) {
|
||||||
|
@ -468,6 +479,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
binding.tvMenuPan.setOnClickListener { viewModel.toggleShowMenuPan() }
|
binding.tvMenuPan.setOnClickListener { viewModel.toggleShowMenuPan() }
|
||||||
|
|
||||||
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
||||||
|
binding.tvSignatureSwitch.setOnClickListener { viewModel.toggleSignatureImage() }
|
||||||
binding.llDonation.setOnClickListener {
|
binding.llDonation.setOnClickListener {
|
||||||
LiveRoomDonationRankingDialog(
|
LiveRoomDonationRankingDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
|
@ -626,6 +638,31 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.isSignatureOn.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.tvSignatureSwitch.text = "시그 ON"
|
||||||
|
binding.tvSignatureSwitch.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.tvSignatureSwitch
|
||||||
|
.setBackgroundResource(R.drawable.bg_round_corner_5_3_transparent_3bb9f1)
|
||||||
|
} else {
|
||||||
|
binding.tvSignatureSwitch.text = "시그 OFF"
|
||||||
|
binding.tvSignatureSwitch.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_eeeeee
|
||||||
|
)
|
||||||
|
)
|
||||||
|
binding.tvSignatureSwitch
|
||||||
|
.setBackgroundResource(R.drawable.bg_round_corner_5_3_transparent_bbbbbb)
|
||||||
|
binding.ivSignature.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.isLoading.observe(this) {
|
viewModel.isLoading.observe(this) {
|
||||||
if (it) {
|
if (it) {
|
||||||
loadingDialog.show(screenWidth)
|
loadingDialog.show(screenWidth)
|
||||||
|
@ -691,7 +728,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
copyMessage = {
|
copyMessage = {
|
||||||
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
clipboard.setPrimaryClip(ClipData.newPlainText(it, it))
|
clipboard.setPrimaryClip(ClipData.newPlainText(it, it))
|
||||||
showToast("후원 메시지가 복사되었습니다.")
|
showToast("후원 히스토리가 복사되었습니다.")
|
||||||
}
|
}
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
@ -759,21 +796,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
binding.ivEdit.visibility = View.GONE
|
binding.ivEdit.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.ivShare.setOnClickListener {
|
|
||||||
viewModel.shareRoomLink(
|
|
||||||
response.roomId,
|
|
||||||
response.isPrivateRoom,
|
|
||||||
response.password
|
|
||||||
) {
|
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
|
||||||
intent.type = "text/plain"
|
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, it)
|
|
||||||
|
|
||||||
val shareIntent = Intent.createChooser(intent, "라이브 공유")
|
|
||||||
startActivity(shareIntent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.creatorId == SharedPreferenceManager.userId) {
|
if (response.creatorId == SharedPreferenceManager.userId) {
|
||||||
binding.llViewUsers.visibility = View.VISIBLE
|
binding.llViewUsers.visibility = View.VISIBLE
|
||||||
binding.llViewUsers.setOnClickListener { roomProfileDialog.show() }
|
binding.llViewUsers.setOnClickListener { roomProfileDialog.show() }
|
||||||
|
@ -928,8 +950,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
viewModel.showRoulette {
|
viewModel.showRoulette {
|
||||||
RoulettePreviewDialog(
|
RoulettePreviewDialog(
|
||||||
activity = this,
|
activity = this,
|
||||||
preview = it,
|
previewList = it,
|
||||||
onClickSpin = { spinRoulette() },
|
onClickSpin = { rouletteId ->
|
||||||
|
spinRoulette(rouletteId = rouletteId)
|
||||||
|
},
|
||||||
layoutInflater = layoutInflater
|
layoutInflater = layoutInflater
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
@ -1270,13 +1294,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
private fun donation(can: Int, message: String) {
|
private fun donation(can: Int, message: String) {
|
||||||
val rawMessage = "${can}캔을 후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99"
|
val rawMessage = "${can}캔을 후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99"
|
||||||
|
|
||||||
viewModel.donation(roomId, can, message) { signatureImage ->
|
viewModel.donation(roomId, can, message) { signature ->
|
||||||
val donationRawMessage = Gson().toJson(
|
val donationRawMessage = Gson().toJson(
|
||||||
LiveRoomChatRawMessage(
|
LiveRoomChatRawMessage(
|
||||||
type = LiveRoomChatRawMessageType.DONATION,
|
type = LiveRoomChatRawMessageType.DONATION,
|
||||||
message = rawMessage,
|
message = rawMessage,
|
||||||
can = can,
|
can = can,
|
||||||
signatureImageUrl = signatureImage,
|
signature = signature,
|
||||||
|
signatureImageUrl = signature?.imageUrl,
|
||||||
donationMessage = message
|
donationMessage = message
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1300,7 +1325,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
)
|
)
|
||||||
invalidateChat()
|
invalidateChat()
|
||||||
viewModel.addDonationCan(can)
|
viewModel.addDonationCan(can)
|
||||||
addSignatureImage(signatureImage)
|
addSignature(signature)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onFailure = {
|
onFailure = {
|
||||||
|
@ -1310,12 +1335,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun spinRoulette() {
|
private fun spinRoulette(rouletteId: Long) {
|
||||||
viewModel.spinRoulette(roomId = roomId) { can, items, randomlySelectedItem ->
|
viewModel.spinRoulette(roomId = roomId, rouletteId = rouletteId) { can, items, randomItem ->
|
||||||
val rouletteRawMessage = Gson().toJson(
|
val rouletteRawMessage = Gson().toJson(
|
||||||
LiveRoomChatRawMessage(
|
LiveRoomChatRawMessage(
|
||||||
type = LiveRoomChatRawMessageType.ROULETTE_DONATION,
|
type = LiveRoomChatRawMessageType.ROULETTE_DONATION,
|
||||||
message = randomlySelectedItem,
|
message = randomItem,
|
||||||
can = can,
|
can = can,
|
||||||
donationMessage = "",
|
donationMessage = "",
|
||||||
)
|
)
|
||||||
|
@ -1324,7 +1349,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
RouletteSpinDialog(
|
RouletteSpinDialog(
|
||||||
activity = this@LiveRoomActivity,
|
activity = this@LiveRoomActivity,
|
||||||
items = items,
|
items = items,
|
||||||
selectedItem = randomlySelectedItem,
|
selectedItem = randomItem,
|
||||||
layoutInflater = layoutInflater
|
layoutInflater = layoutInflater
|
||||||
) {
|
) {
|
||||||
agora.sendRawMessageToGroup(
|
agora.sendRawMessageToGroup(
|
||||||
|
@ -1335,7 +1360,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
LiveRoomRouletteDonationChat(
|
LiveRoomRouletteDonationChat(
|
||||||
profileUrl = SharedPreferenceManager.profileImage,
|
profileUrl = SharedPreferenceManager.profileImage,
|
||||||
nickname = SharedPreferenceManager.nickname,
|
nickname = SharedPreferenceManager.nickname,
|
||||||
rouletteResult = randomlySelectedItem
|
rouletteResult = randomItem
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
invalidateChat()
|
invalidateChat()
|
||||||
|
@ -1407,9 +1432,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
)
|
)
|
||||||
invalidateChat()
|
invalidateChat()
|
||||||
viewModel.addDonationCan(rawMessage.can)
|
viewModel.addDonationCan(rawMessage.can)
|
||||||
addSignatureImage(
|
|
||||||
imageUrl = rawMessage.signatureImageUrl ?: ""
|
if (rawMessage.signature != null) {
|
||||||
)
|
addSignature(rawMessage.signature)
|
||||||
|
} else if (rawMessage.signatureImageUrl != null) {
|
||||||
|
addSignatureImage(rawMessage.signatureImageUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1762,14 +1790,47 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSignatureImage() {
|
private fun addSignature(signature: LiveRoomDonationResponse?) {
|
||||||
if (signatureImageUrl.isNotBlank()) {
|
if (signature != null) {
|
||||||
Glide
|
if (!isShowSignatureImage) {
|
||||||
.with(this)
|
this.signature = signature
|
||||||
.load(signatureImageUrl)
|
isShowSignatureImage = true
|
||||||
.into(binding.ivSignature)
|
} else {
|
||||||
|
signatureList.add(signature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.ivSignature.visibility = View.VISIBLE
|
private fun showSignatureImage() {
|
||||||
|
if (signature != null) {
|
||||||
|
if (viewModel.isSignatureOn.value!!) {
|
||||||
|
Glide
|
||||||
|
.with(this)
|
||||||
|
.load(signature!!.imageUrl)
|
||||||
|
.into(binding.ivSignature)
|
||||||
|
|
||||||
|
binding.ivSignature.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.postDelayed({
|
||||||
|
if (signatureList.isNotEmpty()) {
|
||||||
|
signature = signatureList.removeAt(0)
|
||||||
|
} else {
|
||||||
|
signature = null
|
||||||
|
isShowSignatureImage = false
|
||||||
|
binding.ivSignature.setImageDrawable(null)
|
||||||
|
binding.ivSignature.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}, signature!!.time * 1000L)
|
||||||
|
} else if (signatureImageUrl.isNotBlank()) {
|
||||||
|
if (viewModel.isSignatureOn.value!!) {
|
||||||
|
Glide
|
||||||
|
.with(this)
|
||||||
|
.load(signatureImageUrl)
|
||||||
|
.into(binding.ivSignature)
|
||||||
|
|
||||||
|
binding.ivSignature.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
if (signatureImageUrlList.isNotEmpty()) {
|
if (signatureImageUrlList.isNotEmpty()) {
|
||||||
signatureImageUrl = signatureImageUrlList.removeAt(0)
|
signatureImageUrl = signatureImageUrlList.removeAt(0)
|
||||||
|
|
|
@ -3,12 +3,6 @@ package kr.co.vividnext.sodalive.live.room
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.google.firebase.dynamiclinks.ShortDynamicLink
|
|
||||||
import com.google.firebase.dynamiclinks.ktx.androidParameters
|
|
||||||
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
|
|
||||||
import com.google.firebase.dynamiclinks.ktx.iosParameters
|
|
||||||
import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
|
|
||||||
import com.google.firebase.ktx.Firebase
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
@ -17,6 +11,7 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.live.LiveRepository
|
import kr.co.vividnext.sodalive.live.LiveRepository
|
||||||
import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationStatusResponse
|
import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationStatusResponse
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.menu.GetMenuPresetResponse
|
import kr.co.vividnext.sodalive.live.room.menu.GetMenuPresetResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
||||||
|
@ -35,7 +30,7 @@ import okhttp3.MultipartBody
|
||||||
import okhttp3.RequestBody.Companion.asRequestBody
|
import okhttp3.RequestBody.Companion.asRequestBody
|
||||||
import okhttp3.RequestBody.Companion.toRequestBody
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.math.floor
|
import java.util.Locale
|
||||||
|
|
||||||
class LiveRoomViewModel(
|
class LiveRoomViewModel(
|
||||||
private val repository: LiveRepository,
|
private val repository: LiveRepository,
|
||||||
|
@ -83,6 +78,10 @@ class LiveRoomViewModel(
|
||||||
val isBgOn: LiveData<Boolean>
|
val isBgOn: LiveData<Boolean>
|
||||||
get() = _isBgOn
|
get() = _isBgOn
|
||||||
|
|
||||||
|
private var _isSignatureOn = MutableLiveData(true)
|
||||||
|
val isSignatureOn: LiveData<Boolean>
|
||||||
|
get() = _isSignatureOn
|
||||||
|
|
||||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||||
|
|
||||||
fun getUserNickname(memberId: Int): String {
|
fun getUserNickname(memberId: Int): String {
|
||||||
|
@ -248,43 +247,6 @@ class LiveRoomViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shareRoomLink(
|
|
||||||
roomId: Long,
|
|
||||||
isPrivateRoom: Boolean,
|
|
||||||
password: String?,
|
|
||||||
onSuccess: (String) -> Unit
|
|
||||||
) {
|
|
||||||
_isLoading.value = true
|
|
||||||
Firebase.dynamicLinks.shortLinkAsync(ShortDynamicLink.Suffix.SHORT) {
|
|
||||||
link = Uri.parse("https://sodalive.net/?room_id=$roomId")
|
|
||||||
domainUriPrefix = "https://sodalive.page.link"
|
|
||||||
androidParameters { }
|
|
||||||
iosParameters("kr.co.vividnext.sodalive") {
|
|
||||||
appStoreId = "6461721697"
|
|
||||||
}
|
|
||||||
}.addOnSuccessListener {
|
|
||||||
val uri = it.shortLink
|
|
||||||
if (uri != null) {
|
|
||||||
val message = if (isPrivateRoom) {
|
|
||||||
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
|
||||||
"소다라이브의 비공개라이브에 초대하였습니다.\n" +
|
|
||||||
"※ 라이브 참여: $uri\n" +
|
|
||||||
"(입장 비밀번호 : $password)"
|
|
||||||
} else {
|
|
||||||
"${SharedPreferenceManager.nickname}님이 귀하를 " +
|
|
||||||
"소다라이브의 공개라이브에 초대하였습니다.\n" +
|
|
||||||
"※ 라이브 참여: $uri"
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuccess(message)
|
|
||||||
}
|
|
||||||
}.addOnFailureListener {
|
|
||||||
_toastLiveData.postValue("공유링크를 생성하지 못했습니다.\n다시 시도해 주세요.")
|
|
||||||
}.addOnCompleteListener {
|
|
||||||
_isLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun creatorFollow(creatorId: Long, roomId: Long, isGetUserProfile: Boolean = false) {
|
fun creatorFollow(creatorId: Long, roomId: Long, isGetUserProfile: Boolean = false) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
@ -378,6 +340,10 @@ class LiveRoomViewModel(
|
||||||
_isBgOn.value = !isBgOn.value!!
|
_isBgOn.value = !isBgOn.value!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleSignatureImage() {
|
||||||
|
_isSignatureOn.value = !isSignatureOn.value!!
|
||||||
|
}
|
||||||
|
|
||||||
fun editLiveRoomInfo(
|
fun editLiveRoomInfo(
|
||||||
roomId: Long,
|
roomId: Long,
|
||||||
newTitle: String,
|
newTitle: String,
|
||||||
|
@ -508,7 +474,12 @@ class LiveRoomViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun donation(roomId: Long, can: Int, message: String, onSuccess: (String) -> Unit) {
|
fun donation(
|
||||||
|
roomId: Long,
|
||||||
|
can: Int,
|
||||||
|
message: String,
|
||||||
|
onSuccess: (LiveRoomDonationResponse?) -> Unit
|
||||||
|
) {
|
||||||
_isLoading.postValue(true)
|
_isLoading.postValue(true)
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
repository.donation(roomId, can, message, "Bearer ${SharedPreferenceManager.token}")
|
repository.donation(roomId, can, message, "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
@ -519,7 +490,7 @@ class LiveRoomViewModel(
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
if (it.success) {
|
if (it.success) {
|
||||||
SharedPreferenceManager.can -= can
|
SharedPreferenceManager.can -= can
|
||||||
onSuccess(it.data ?: "")
|
onSuccess(it.data)
|
||||||
} else {
|
} else {
|
||||||
if (it.message != null) {
|
if (it.message != null) {
|
||||||
_toastLiveData.postValue(it.message)
|
_toastLiveData.postValue(it.message)
|
||||||
|
@ -808,7 +779,7 @@ class LiveRoomViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showRoulette(complete: (RoulettePreview) -> Unit) {
|
fun showRoulette(complete: (List<RoulettePreview>) -> Unit) {
|
||||||
if (!_isLoading.value!!) {
|
if (!_isLoading.value!!) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
@ -825,15 +796,19 @@ class LiveRoomViewModel(
|
||||||
val data = it.data
|
val data = it.data
|
||||||
if (
|
if (
|
||||||
it.success &&
|
it.success &&
|
||||||
data != null &&
|
!data.isNullOrEmpty()
|
||||||
data.isActive &&
|
|
||||||
data.items.isNotEmpty()
|
|
||||||
) {
|
) {
|
||||||
complete(
|
complete(
|
||||||
RoulettePreview(
|
data
|
||||||
data.can,
|
.filter { roulette -> roulette.isActive }
|
||||||
items = calculatePercentages(data.items)
|
.filter { roulette -> roulette.items.isNotEmpty() }
|
||||||
)
|
.map { roulette ->
|
||||||
|
RoulettePreview(
|
||||||
|
id = roulette.id,
|
||||||
|
can = roulette.can,
|
||||||
|
items = calculatePercentages(roulette.items)
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||||
|
@ -850,12 +825,16 @@ class LiveRoomViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun spinRoulette(roomId: Long, complete: (Int, List<RouletteItem>, String) -> Unit) {
|
fun spinRoulette(
|
||||||
|
roomId: Long,
|
||||||
|
rouletteId: Long,
|
||||||
|
complete: (Int, List<RouletteItem>, String) -> Unit
|
||||||
|
) {
|
||||||
if (!_isLoading.value!!) {
|
if (!_isLoading.value!!) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
rouletteRepository.spinRoulette(
|
rouletteRepository.spinRoulette(
|
||||||
request = SpinRouletteRequest(roomId = roomId),
|
request = SpinRouletteRequest(roomId = roomId, rouletteId = rouletteId),
|
||||||
token = "Bearer ${SharedPreferenceManager.token}"
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
)
|
)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
|
@ -868,11 +847,10 @@ class LiveRoomViewModel(
|
||||||
if (
|
if (
|
||||||
it.success &&
|
it.success &&
|
||||||
data != null &&
|
data != null &&
|
||||||
data.isActive &&
|
|
||||||
data.items.isNotEmpty()
|
data.items.isNotEmpty()
|
||||||
) {
|
) {
|
||||||
SharedPreferenceManager.can -= data.can
|
SharedPreferenceManager.can -= data.can
|
||||||
randomSelectRouletteItem(data.can, data.items, complete)
|
complete(data.can, data.items, data.result)
|
||||||
} else {
|
} else {
|
||||||
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||||
_toastLiveData.postValue(message)
|
_toastLiveData.postValue(message)
|
||||||
|
@ -961,31 +939,11 @@ class LiveRoomViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
private fun calculatePercentages(options: List<RouletteItem>): List<RoulettePreviewItem> {
|
||||||
val totalWeight = options.sumOf { it.weight }
|
val updatedOptions = options.map { option ->
|
||||||
val updatedOptions = options.asSequence().map { option ->
|
|
||||||
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
|
||||||
RoulettePreviewItem(
|
RoulettePreviewItem(
|
||||||
title = option.title,
|
title = option.title,
|
||||||
percent = "${String.format("%.2f", percent)}%"
|
percent = "${String.format(Locale.KOREAN, "%.2f", option.percentage)}%"
|
||||||
)
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package kr.co.vividnext.sodalive.live.room.chat
|
package kr.co.vividnext.sodalive.live.room.chat
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||||
|
|
||||||
data class LiveRoomChatRawMessage(
|
data class LiveRoomChatRawMessage(
|
||||||
@SerializedName("type") val type: LiveRoomChatRawMessageType,
|
@SerializedName("type") val type: LiveRoomChatRawMessageType,
|
||||||
@SerializedName("message") val message: String,
|
@SerializedName("message") val message: String,
|
||||||
@SerializedName("can") val can: Int,
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("signature") val signature: LiveRoomDonationResponse? = null,
|
||||||
@SerializedName("signatureImageUrl") val signatureImageUrl: String? = null,
|
@SerializedName("signatureImageUrl") val signatureImageUrl: String? = null,
|
||||||
@SerializedName("donationMessage") val donationMessage: String?,
|
@SerializedName("donationMessage") val donationMessage: String?,
|
||||||
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null
|
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null
|
||||||
|
|
|
@ -17,5 +17,6 @@ data class CreateLiveRoomRequest(
|
||||||
@SerializedName("password") val password: String? = null,
|
@SerializedName("password") val password: String? = null,
|
||||||
@SerializedName("menuPanId") val menuPanId: Long = 0,
|
@SerializedName("menuPanId") val menuPanId: Long = 0,
|
||||||
@SerializedName("menuPan") val menuPan: String = "",
|
@SerializedName("menuPan") val menuPan: String = "",
|
||||||
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean = false
|
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean = false,
|
||||||
|
@SerializedName("isAvailableJoinCreator") val isAvailableJoinCreator: Boolean = true
|
||||||
)
|
)
|
||||||
|
|
|
@ -322,6 +322,14 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
binding.llSelectMenu3.setOnClickListener {
|
binding.llSelectMenu3.setOnClickListener {
|
||||||
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
|
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.llAvailableJoinCreatorY.setOnClickListener {
|
||||||
|
viewModel.setAvailableJoinCreator(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.llAvailableJoinCreatorN.setOnClickListener {
|
||||||
|
viewModel.setAvailableJoinCreator(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
@ -647,6 +655,46 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
||||||
viewModel.menuLiveData.observe(this) {
|
viewModel.menuLiveData.observe(this) {
|
||||||
binding.etMenu.setText(it)
|
binding.etMenu.setText(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.isAvailableJoinCreatorLiveData.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
binding.ivAvailableJoinCreatorN.visibility = View.GONE
|
||||||
|
binding.llAvailableJoinCreatorN.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAvailableJoinCreatorN.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAvailableJoinCreatorY.visibility = View.VISIBLE
|
||||||
|
binding.llAvailableJoinCreatorY.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAvailableJoinCreatorY.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_eeeeee
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.ivAvailableJoinCreatorY.visibility = View.GONE
|
||||||
|
binding.llAvailableJoinCreatorY.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
binding.tvAvailableJoinCreatorY.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.ivAvailableJoinCreatorN.visibility = View.VISIBLE
|
||||||
|
binding.llAvailableJoinCreatorN.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||||
|
binding.tvAvailableJoinCreatorN.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
applicationContext,
|
||||||
|
R.color.color_eeeeee
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,10 @@ class LiveRoomCreateViewModel(
|
||||||
val isActivateMenuLiveData: LiveData<Boolean>
|
val isActivateMenuLiveData: LiveData<Boolean>
|
||||||
get() = _isActivateMenuLiveData
|
get() = _isActivateMenuLiveData
|
||||||
|
|
||||||
|
private val _isAvailableJoinCreatorLiveData = MutableLiveData(true)
|
||||||
|
val isAvailableJoinCreatorLiveData: LiveData<Boolean>
|
||||||
|
get() = _isAvailableJoinCreatorLiveData
|
||||||
|
|
||||||
private val _menuLiveData = MutableLiveData("")
|
private val _menuLiveData = MutableLiveData("")
|
||||||
val menuLiveData: LiveData<String>
|
val menuLiveData: LiveData<String>
|
||||||
get() = _menuLiveData
|
get() = _menuLiveData
|
||||||
|
@ -147,7 +151,8 @@ class LiveRoomCreateViewModel(
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
isActiveMenuPan = _isActivateMenuLiveData.value!!
|
isActiveMenuPan = _isActivateMenuLiveData.value!!,
|
||||||
|
isAvailableJoinCreator = _isAvailableJoinCreatorLiveData.value!!
|
||||||
)
|
)
|
||||||
|
|
||||||
val requestJson = Gson().toJson(request)
|
val requestJson = Gson().toJson(request)
|
||||||
|
@ -255,6 +260,10 @@ class LiveRoomCreateViewModel(
|
||||||
_isAdultLiveData.value = isAdult
|
_isAdultLiveData.value = isAdult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setAvailableJoinCreator(isAvailableJoinCreator: Boolean) {
|
||||||
|
_isAvailableJoinCreatorLiveData.value = isAvailableJoinCreator
|
||||||
|
}
|
||||||
|
|
||||||
fun getRecentInfo(onSuccess: (GetRecentRoomInfoResponse) -> Unit) {
|
fun getRecentInfo(onSuccess: (GetRecentRoomInfoResponse) -> Unit) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
|
|
@ -111,6 +111,14 @@ class LiveRoomDonationDialog(
|
||||||
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialogView.tvCharge.setOnClickListener {
|
||||||
|
bottomSheetDialog.dismiss()
|
||||||
|
|
||||||
|
val intent = Intent(activity, CanChargeActivity::class.java)
|
||||||
|
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
|
|
@ -2,9 +2,11 @@ package kr.co.vividnext.sodalive.live.room.donation
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomDonationMessageBinding
|
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomDonationMessageBinding
|
||||||
|
|
||||||
class LiveRoomDonationMessageAdapter(
|
class LiveRoomDonationMessageAdapter(
|
||||||
|
@ -20,8 +22,16 @@ class LiveRoomDonationMessageAdapter(
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
fun bind(item: LiveRoomDonationMessage) {
|
fun bind(item: LiveRoomDonationMessage) {
|
||||||
binding.tvNickname.text = "${item.nickname}님이"
|
if (item.canMessage.isNotBlank()) {
|
||||||
binding.tvCanMessage.text = item.canMessage
|
binding.tvNickname.text = "${item.nickname}님이"
|
||||||
|
binding.tvCanMessage.text = item.canMessage
|
||||||
|
binding.tvCanMessage.visibility = View.VISIBLE
|
||||||
|
binding.root.setBackgroundResource(R.drawable.bg_round_corner_5_3_333333)
|
||||||
|
} else {
|
||||||
|
binding.tvNickname.text = "${item.nickname}님의 룰렛 결과?"
|
||||||
|
binding.tvCanMessage.visibility = View.GONE
|
||||||
|
binding.root.setBackgroundResource(R.drawable.bg_round_corner_5_3_ccc25264)
|
||||||
|
}
|
||||||
binding.tvDonationMessage.text = "\"${item.donationMessage}\""
|
binding.tvDonationMessage.text = "\"${item.donationMessage}\""
|
||||||
binding.ivDelete.setOnClickListener { onClickDeleteMessage(item.uuid) }
|
binding.ivDelete.setOnClickListener { onClickDeleteMessage(item.uuid) }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.room.donation
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class LiveRoomDonationResponse(
|
||||||
|
@SerializedName("imageUrl") val imageUrl: String,
|
||||||
|
@SerializedName("time") val time: Int
|
||||||
|
)
|
|
@ -26,7 +26,7 @@ class LiveTagAdapter(
|
||||||
fun bind(item: GetLiveTagResponse) {
|
fun bind(item: GetLiveTagResponse) {
|
||||||
if (selectedTags.contains(item.tag)) {
|
if (selectedTags.contains(item.tag)) {
|
||||||
binding.ivTagChecked.visibility = View.VISIBLE
|
binding.ivTagChecked.visibility = View.VISIBLE
|
||||||
binding.tvTag.setTextColor(ContextCompat.getColor(context, R.color.color_9970ff))
|
binding.tvTag.setTextColor(ContextCompat.getColor(context, R.color.color_3bb9f1))
|
||||||
isChecked = true
|
isChecked = true
|
||||||
} else {
|
} else {
|
||||||
binding.ivTagChecked.visibility = View.GONE
|
binding.ivTagChecked.visibility = View.GONE
|
||||||
|
@ -50,7 +50,7 @@ class LiveTagAdapter(
|
||||||
binding.tvTag.setTextColor(
|
binding.tvTag.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
context,
|
context,
|
||||||
R.color.color_9970ff
|
R.color.color_3bb9f1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.live.roulette
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class GetRouletteResponse(
|
data class GetRouletteResponse(
|
||||||
|
@SerializedName("id") val id: Long,
|
||||||
@SerializedName("can") val can: Int,
|
@SerializedName("can") val can: Int,
|
||||||
@SerializedName("isActive") val isActive: Boolean,
|
@SerializedName("isActive") val isActive: Boolean,
|
||||||
@SerializedName("items") val items: List<RouletteItem>
|
@SerializedName("items") val items: List<RouletteItem>
|
||||||
|
@ -10,5 +11,5 @@ data class GetRouletteResponse(
|
||||||
|
|
||||||
data class RouletteItem(
|
data class RouletteItem(
|
||||||
@SerializedName("title") val title: String,
|
@SerializedName("title") val title: String,
|
||||||
@SerializedName("weight") val weight: Int
|
@SerializedName("percentage") val percentage: Float
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
package kr.co.vividnext.sodalive.live.roulette
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class RoulettePreview(
|
data class RoulettePreview(
|
||||||
val can: Int,
|
@SerializedName("id") val id: Long,
|
||||||
val items: List<RoulettePreviewItem>
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("items") val items: List<RoulettePreviewItem>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class RoulettePreviewItem(
|
data class RoulettePreviewItem(
|
||||||
val title: String,
|
@SerializedName("title") val title: String,
|
||||||
val percent: String
|
@SerializedName("percent") val percent: String
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,27 +8,36 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
import kr.co.vividnext.sodalive.databinding.DialogRoulettePreviewBinding
|
import kr.co.vividnext.sodalive.databinding.DialogRoulettePreviewBinding
|
||||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteSettingsViewModel.SelectedRoulette
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||||
|
|
||||||
class RoulettePreviewDialog(
|
class RoulettePreviewDialog(
|
||||||
private val activity: FragmentActivity,
|
private val activity: FragmentActivity,
|
||||||
private val preview: RoulettePreview,
|
private val previewList: List<RoulettePreview>,
|
||||||
private val title: String = "",
|
private val title: String = "",
|
||||||
private val onClickSpin: (() -> Unit)? = null,
|
private val onClickSpin: ((Long) -> Unit)? = null,
|
||||||
layoutInflater: LayoutInflater
|
layoutInflater: LayoutInflater
|
||||||
) {
|
) {
|
||||||
private val alertDialog: AlertDialog
|
private val alertDialog: AlertDialog
|
||||||
private val dialogView = DialogRoulettePreviewBinding.inflate(layoutInflater)
|
private val dialogView = DialogRoulettePreviewBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
private val selectedRouletteLiveData = MutableLiveData(
|
||||||
|
SelectedRoulette.ROULETTE_1
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val dialogBuilder = AlertDialog.Builder(activity)
|
val dialogBuilder = AlertDialog.Builder(activity)
|
||||||
dialogBuilder.setView(dialogView.root)
|
dialogBuilder.setView(dialogView.root)
|
||||||
|
@ -54,18 +63,189 @@ class RoulettePreviewDialog(
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
private fun setupView() {
|
private fun setupView() {
|
||||||
dialogView.tvCancel.setOnClickListener { alertDialog.dismiss() }
|
if (previewList.isEmpty()) {
|
||||||
|
alertDialog.dismiss()
|
||||||
|
} else {
|
||||||
|
initSelectRouletteButton()
|
||||||
|
setRouletteData(previewList[0])
|
||||||
|
}
|
||||||
|
|
||||||
dialogView.tvSpinRoulette.text = "${preview.can}캔으로 룰렛 돌리기"
|
dialogView.tvCancel.setOnClickListener { alertDialog.dismiss() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initSelectRouletteButton() {
|
||||||
|
if (previewList.size < 2) {
|
||||||
|
dialogView.llSelectRoulette.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
dialogView.llSelectRoulette.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
if (previewList.size > 2) {
|
||||||
|
dialogView.llSelectRoulette3.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
dialogView.llSelectRoulette3.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette1.setOnClickListener {
|
||||||
|
if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_1) {
|
||||||
|
selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette2.setOnClickListener {
|
||||||
|
if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_2) {
|
||||||
|
selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette3.setOnClickListener {
|
||||||
|
if (selectedRouletteLiveData.value != SelectedRoulette.ROULETTE_3) {
|
||||||
|
selectedRouletteLiveData.value = SelectedRoulette.ROULETTE_3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedRouletteLiveData.observe(activity) {
|
||||||
|
deselectAllRoulette()
|
||||||
|
when (it) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> {
|
||||||
|
selectRouletteButton(
|
||||||
|
dialogView.ivSelectRoulette2,
|
||||||
|
dialogView.llSelectRoulette2,
|
||||||
|
dialogView.tvSelectRoulette2
|
||||||
|
)
|
||||||
|
setRouletteData(previewList[1])
|
||||||
|
dialogView.tvCancel.setTextColor(
|
||||||
|
ContextCompat.getColor(activity, R.color.color_ffcb14)
|
||||||
|
)
|
||||||
|
dialogView.tvCancel.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_10_transparent_ffcb14
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedRoulette.ROULETTE_3 -> {
|
||||||
|
selectRouletteButton(
|
||||||
|
dialogView.ivSelectRoulette3,
|
||||||
|
dialogView.llSelectRoulette3,
|
||||||
|
dialogView.tvSelectRoulette3
|
||||||
|
)
|
||||||
|
setRouletteData(previewList[2])
|
||||||
|
dialogView.tvCancel.setTextColor(
|
||||||
|
ContextCompat.getColor(activity, R.color.color_ff14d9)
|
||||||
|
)
|
||||||
|
dialogView.tvCancel.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_10_transparent_ff14d9
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
selectRouletteButton(
|
||||||
|
dialogView.ivSelectRoulette1,
|
||||||
|
dialogView.llSelectRoulette1,
|
||||||
|
dialogView.tvSelectRoulette1
|
||||||
|
)
|
||||||
|
setRouletteData(previewList[0])
|
||||||
|
dialogView.tvCancel.setTextColor(
|
||||||
|
ContextCompat.getColor(activity, R.color.color_3bb9f1)
|
||||||
|
)
|
||||||
|
dialogView.tvCancel.setBackgroundResource(
|
||||||
|
R.drawable.bg_round_corner_10_transparent_3bb9f1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deselectAllRoulette() {
|
||||||
|
dialogView.ivSelectRoulette1.visibility = View.GONE
|
||||||
|
dialogView.ivSelectRoulette2.visibility = View.GONE
|
||||||
|
dialogView.ivSelectRoulette3.visibility = View.GONE
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette1.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
dialogView.tvSelectRoulette1.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
activity,
|
||||||
|
R.color.color_3bb9f1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette2.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
dialogView.tvSelectRoulette2.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
activity,
|
||||||
|
R.color.color_ffcb14
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
dialogView.llSelectRoulette3.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||||
|
dialogView.tvSelectRoulette3.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
activity,
|
||||||
|
R.color.color_ff14d9
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectRouletteButton(
|
||||||
|
ivSelectRoulette: ImageView,
|
||||||
|
llSelectRoulette: LinearLayout,
|
||||||
|
tvSelectRoulette: TextView
|
||||||
|
) {
|
||||||
|
ivSelectRoulette.visibility = View.VISIBLE
|
||||||
|
llSelectRoulette.setBackgroundResource(
|
||||||
|
when (selectedRouletteLiveData.value) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_6_7_ffcb14
|
||||||
|
SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_6_7_ff14d9
|
||||||
|
else -> R.drawable.bg_round_corner_6_7_3bb9f1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
tvSelectRoulette.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
activity,
|
||||||
|
when (selectedRouletteLiveData.value) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> R.color.black
|
||||||
|
else -> R.color.color_eeeeee
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
private fun setRouletteData(roulettePreview: RoulettePreview) {
|
||||||
|
dialogView.tvSpinRoulette.text = "${roulettePreview.can}캔으로 룰렛 돌리기"
|
||||||
dialogView.tvSpinRoulette.setOnClickListener {
|
dialogView.tvSpinRoulette.setOnClickListener {
|
||||||
if (onClickSpin != null) {
|
if (onClickSpin != null) {
|
||||||
onClickSpin!!()
|
onClickSpin!!(roulettePreview.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
alertDialog.dismiss()
|
alertDialog.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView.tvTitle.text = title.ifBlank { "룰렛" }
|
dialogView.tvSpinRoulette.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
activity,
|
||||||
|
when (selectedRouletteLiveData.value) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> R.color.black
|
||||||
|
else -> R.color.white
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
dialogView.tvSpinRoulette.setBackgroundResource(
|
||||||
|
when (selectedRouletteLiveData.value) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_10_ffcb14
|
||||||
|
SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_10_ff14d9
|
||||||
|
else -> R.drawable.bg_round_corner_10_3bb9f1
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
dialogView.tvTitle.text = title.ifBlank {
|
||||||
|
when (selectedRouletteLiveData.value) {
|
||||||
|
SelectedRoulette.ROULETTE_2 -> "룰렛 2"
|
||||||
|
SelectedRoulette.ROULETTE_3 -> "룰렛 3"
|
||||||
|
else -> "룰렛 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (onClickSpin != null) {
|
if (onClickSpin != null) {
|
||||||
dialogView.tvCan.visibility = View.VISIBLE
|
dialogView.tvCan.visibility = View.VISIBLE
|
||||||
dialogView.tvCan.text = SharedPreferenceManager.can.moneyFormat()
|
dialogView.tvCan.text = SharedPreferenceManager.can.moneyFormat()
|
||||||
|
@ -80,7 +260,8 @@ class RoulettePreviewDialog(
|
||||||
dialogView.tvCan.visibility = View.GONE
|
dialogView.tvCan.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
preview.items.forEachIndexed { index, item ->
|
dialogView.llRouletteOptionContainer.removeAllViews()
|
||||||
|
roulettePreview.items.forEachIndexed { index, item ->
|
||||||
dialogView.llRouletteOptionContainer.addView(createOptionView(index, item))
|
dialogView.llRouletteOptionContainer.addView(createOptionView(index, item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,12 +74,10 @@ class RouletteView @JvmOverloads constructor(
|
||||||
override fun onDraw(canvas: Canvas) {
|
override fun onDraw(canvas: Canvas) {
|
||||||
super.onDraw(canvas)
|
super.onDraw(canvas)
|
||||||
|
|
||||||
val totalWeight = items.asSequence().map { it.weight }.sum()
|
|
||||||
var startAngle = -90f
|
var startAngle = -90f
|
||||||
|
|
||||||
val shuffledColors = colors.shuffled()
|
val shuffledColors = colors.shuffled()
|
||||||
items.forEachIndexed { index, (option, weight) ->
|
items.forEachIndexed { index, (option, percentage) ->
|
||||||
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
val sweepAngle = (percentage / 100) * 360f
|
||||||
fillPaint.color = shuffledColors[index]
|
fillPaint.color = shuffledColors[index]
|
||||||
canvas.drawArc(rect, startAngle, sweepAngle, true, fillPaint)
|
canvas.drawArc(rect, startAngle, sweepAngle, true, fillPaint)
|
||||||
|
|
||||||
|
@ -117,11 +115,10 @@ class RouletteView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAngleForOption(option: String): Float {
|
private fun getAngleForOption(option: String): Float {
|
||||||
val totalWeight = items.asSequence().map { it.weight }.sum()
|
|
||||||
var startAngle = 0f
|
var startAngle = 0f
|
||||||
|
|
||||||
items.forEach { (currentOption, weight) ->
|
items.forEach { (currentOption, percentage) ->
|
||||||
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
val sweepAngle = (percentage / 100) * 360f
|
||||||
if (currentOption == option) {
|
if (currentOption == option) {
|
||||||
// Return the midpoint angle of the segment
|
// Return the midpoint angle of the segment
|
||||||
return (startAngle + sweepAngle / 2)
|
return (startAngle + sweepAngle / 2)
|
||||||
|
|
|
@ -4,5 +4,6 @@ import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
data class SpinRouletteRequest(
|
data class SpinRouletteRequest(
|
||||||
@SerializedName("roomId") val roomId: Long,
|
@SerializedName("roomId") val roomId: Long,
|
||||||
|
@SerializedName("rouletteId") val rouletteId: Long,
|
||||||
@SerializedName("container") val container: String = "aos"
|
@SerializedName("container") val container: String = "aos"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package kr.co.vividnext.sodalive.live.roulette
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class SpinRouletteResponse(
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("result") val result: String,
|
||||||
|
@SerializedName("items") val items: List<RouletteItem>
|
||||||
|
)
|
|
@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
import kr.co.vividnext.sodalive.live.roulette.GetNewRouletteResponse
|
import kr.co.vividnext.sodalive.live.roulette.GetNewRouletteResponse
|
||||||
import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse
|
import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse
|
||||||
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
|
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
|
||||||
|
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteResponse
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
|
@ -14,37 +15,37 @@ import retrofit2.http.Path
|
||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
interface RouletteApi {
|
interface RouletteApi {
|
||||||
@POST("/new-roulette")
|
@POST("/v2/roulette")
|
||||||
fun createRoulette(
|
fun createRoulette(
|
||||||
@Body request: CreateRouletteRequest,
|
@Body request: CreateRouletteRequest,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<Any>>
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
@PUT("/new-roulette")
|
@PUT("/v2/roulette")
|
||||||
fun updateRoulette(
|
fun updateRoulette(
|
||||||
@Body request: UpdateRouletteRequest,
|
@Body request: UpdateRouletteRequest,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<Any>>
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
@GET("/new-roulette/creator")
|
@GET("/v2/roulette/creator")
|
||||||
fun getAllRoulette(
|
fun getAllRoulette(
|
||||||
@Query("creatorId") creatorId: Long,
|
@Query("creatorId") creatorId: Long,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<List<GetNewRouletteResponse>>>
|
): Single<ApiResponse<List<GetNewRouletteResponse>>>
|
||||||
|
|
||||||
@GET("/new-roulette")
|
@GET("/v2/roulette")
|
||||||
fun getRoulette(
|
fun getRoulette(
|
||||||
@Query("creatorId") creatorId: Long,
|
@Query("creatorId") creatorId: Long,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<GetRouletteResponse>>
|
): Single<ApiResponse<List<GetRouletteResponse>>>
|
||||||
|
|
||||||
@POST("/new-roulette/spin")
|
@POST("/v2/roulette/spin")
|
||||||
fun spinRoulette(
|
fun spinRoulette(
|
||||||
@Body request: SpinRouletteRequest,
|
@Body request: SpinRouletteRequest,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<GetRouletteResponse>>
|
): Single<ApiResponse<SpinRouletteResponse>>
|
||||||
|
|
||||||
@POST("/new-roulette/refund/{id}")
|
@POST("/v2/roulette/refund/{id}")
|
||||||
fun refundRouletteDonation(
|
fun refundRouletteDonation(
|
||||||
@Path("id") id: Long,
|
@Path("id") id: Long,
|
||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
package kr.co.vividnext.sodalive.live.roulette.config
|
package kr.co.vividnext.sodalive.live.roulette.config
|
||||||
|
|
||||||
data class RouletteOption(var title: String, var weight: Int, var percentage: String = "50.00")
|
data class RouletteOption(var title: String, var percentage: String = "")
|
||||||
|
|
|
@ -26,6 +26,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
|
||||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
|
@ -103,6 +104,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
private fun bindData() {
|
private fun bindData() {
|
||||||
viewModel.selectedRouletteLiveData.observe(viewLifecycleOwner) {
|
viewModel.selectedRouletteLiveData.observe(viewLifecycleOwner) {
|
||||||
deselectAllRoulette()
|
deselectAllRoulette()
|
||||||
|
@ -156,12 +158,22 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
|
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
|
||||||
RoulettePreviewDialog(
|
RoulettePreviewDialog(
|
||||||
activity = requireActivity(),
|
activity = requireActivity(),
|
||||||
preview = it,
|
previewList = listOf(it),
|
||||||
title = "룰렛 미리보기",
|
title = "룰렛 미리보기",
|
||||||
layoutInflater = layoutInflater
|
layoutInflater = layoutInflater
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.totalPercentageLiveData.observe(viewLifecycleOwner) {
|
||||||
|
binding.tvTotalPercentage.text = "( ${
|
||||||
|
String.format(
|
||||||
|
Locale.KOREAN,
|
||||||
|
"%.2f%%",
|
||||||
|
it
|
||||||
|
)
|
||||||
|
} )"
|
||||||
|
}
|
||||||
|
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
binding.etSetPrice.textChanges().skip(1)
|
binding.etSetPrice.textChanges().skip(1)
|
||||||
.debounce(100, TimeUnit.MILLISECONDS)
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
@ -176,7 +188,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addOption() {
|
private fun addOption() {
|
||||||
val newOption = RouletteOption("", 1)
|
val newOption = RouletteOption("", "")
|
||||||
viewModel.addOption(newOption)
|
viewModel.addOption(newOption)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,16 +211,21 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
|
|
||||||
val etOption = optionView.findViewById<EditText>(R.id.et_option)
|
val etOption = optionView.findViewById<EditText>(R.id.et_option)
|
||||||
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
|
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
|
||||||
val tvPercentage = optionView.findViewById<TextView>(R.id.tv_option_percentage)
|
val etPercentage = optionView.findViewById<EditText>(R.id.et_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)
|
val tvDelete = optionView.findViewById<TextView>(R.id.tv_delete)
|
||||||
|
|
||||||
etOption.setText(option.title)
|
etOption.setText(option.title)
|
||||||
tvOptionTitle.text = "옵션 ${index + 1}"
|
tvOptionTitle.text = "옵션 ${index + 1}"
|
||||||
tvPercentage.text = "${option.percentage}%"
|
|
||||||
ivMinus.setOnClickListener { viewModel.subtractWeight(index) }
|
try {
|
||||||
ivPlus.setOnClickListener { viewModel.plusWeight(index) }
|
if (option.percentage.toFloat() > 0f) {
|
||||||
|
etPercentage.setText(option.percentage)
|
||||||
|
} else {
|
||||||
|
etPercentage.setText("")
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
etPercentage.setText("")
|
||||||
|
}
|
||||||
|
|
||||||
if (index == 0 || index == 1) {
|
if (index == 0 || index == 1) {
|
||||||
tvDelete.visibility = View.GONE
|
tvDelete.visibility = View.GONE
|
||||||
|
@ -227,6 +244,16 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
compositeDisposable.add(
|
||||||
|
etPercentage.textChanges().skip(1)
|
||||||
|
.debounce(100, TimeUnit.MILLISECONDS)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.subscribe {
|
||||||
|
viewModel.inputOptionPercentage(index, it.toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return optionView
|
return optionView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +275,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
binding.tvSelectRoulette2.setTextColor(
|
binding.tvSelectRoulette2.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_3bb9f1
|
R.color.color_ffcb14
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,7 +283,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
binding.tvSelectRoulette2.setTextColor(
|
binding.tvSelectRoulette2.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_555555
|
R.color.color_ff14d9
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -286,11 +313,20 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||||
tvSelectRoulette: TextView
|
tvSelectRoulette: TextView
|
||||||
) {
|
) {
|
||||||
ivSelectRoulette.visibility = View.VISIBLE
|
ivSelectRoulette.visibility = View.VISIBLE
|
||||||
llSelectRoulette.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
llSelectRoulette.setBackgroundResource(
|
||||||
|
when (viewModel.selectedRouletteLiveData.value) {
|
||||||
|
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> R.drawable.bg_round_corner_6_7_ffcb14
|
||||||
|
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_3 -> R.drawable.bg_round_corner_6_7_ff14d9
|
||||||
|
else -> R.drawable.bg_round_corner_6_7_3bb9f1
|
||||||
|
}
|
||||||
|
)
|
||||||
tvSelectRoulette.setTextColor(
|
tvSelectRoulette.setTextColor(
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
R.color.color_eeeeee
|
when (viewModel.selectedRouletteLiveData.value) {
|
||||||
|
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> R.color.black
|
||||||
|
else -> R.color.color_eeeeee
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import kr.co.vividnext.sodalive.live.roulette.RouletteItem
|
||||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
|
||||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
|
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
|
||||||
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
||||||
import kotlin.math.floor
|
|
||||||
|
|
||||||
class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {
|
class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {
|
||||||
|
|
||||||
|
@ -48,6 +47,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
val selectedRouletteLiveData: LiveData<SelectedRoulette>
|
val selectedRouletteLiveData: LiveData<SelectedRoulette>
|
||||||
get() = _selectedRouletteLiveData
|
get() = _selectedRouletteLiveData
|
||||||
|
|
||||||
|
private val _totalPercentageLiveData = MutableLiveData(0f)
|
||||||
|
val totalPercentageLiveData: LiveData<Float>
|
||||||
|
get() = _totalPercentageLiveData
|
||||||
|
|
||||||
var can = 0
|
var can = 0
|
||||||
var isActive = false
|
var isActive = false
|
||||||
private var rouletteId = 0L
|
private var rouletteId = 0L
|
||||||
|
@ -55,31 +58,17 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
|
|
||||||
val rouletteList = mutableListOf<GetNewRouletteResponse>()
|
val rouletteList = mutableListOf<GetNewRouletteResponse>()
|
||||||
|
|
||||||
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) {
|
fun addOption(newOption: RouletteOption) {
|
||||||
if (options.size >= 10) return
|
if (options.size >= 10) return
|
||||||
|
|
||||||
options.add(newOption)
|
options.add(newOption)
|
||||||
recalculatePercentages(options)
|
_optionsLiveData.value = options
|
||||||
|
calculateTotalPercentage()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteOption(index: Int) {
|
fun deleteOption(index: Int) {
|
||||||
val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
|
val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
|
||||||
removeAllAndAddOptions(updatedOptions)
|
removeAllAndAddOptions(updatedOptions)
|
||||||
recalculatePercentages(updatedOptions)
|
_optionsLiveData.value = updatedOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
fun inputOption(optionIndex: Int, title: String) {
|
fun inputOption(optionIndex: Int, title: String) {
|
||||||
|
@ -87,15 +76,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
options[optionIndex] = currentOption.copy(title = title)
|
options[optionIndex] = currentOption.copy(title = title)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun recalculatePercentages(options: List<RouletteOption>) {
|
fun inputOptionPercentage(optionIndex: Int, percentage: String) {
|
||||||
val totalWeight = options.sumOf { it.weight }
|
val currentOption = options[optionIndex]
|
||||||
val updatedOptions = options.asSequence().map { option ->
|
options[optionIndex] = currentOption.copy(percentage = percentage)
|
||||||
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
calculateTotalPercentage()
|
||||||
option.copy(percentage = String.format("%.2f", percent))
|
|
||||||
}.toList()
|
|
||||||
|
|
||||||
removeAllAndAddOptions(updatedOptions)
|
|
||||||
_optionsLiveData.value = updatedOptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleIsActive() {
|
fun toggleIsActive() {
|
||||||
|
@ -107,17 +91,20 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
||||||
val items = mutableListOf<RoulettePreviewItem>()
|
val items = mutableListOf<RoulettePreviewItem>()
|
||||||
for (option in options) {
|
if (validationOptions()) {
|
||||||
if (option.title.trim().isEmpty()) {
|
for (option in options) {
|
||||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
if (option.title.trim().isEmpty()) {
|
||||||
_isLoading.value = false
|
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||||
return
|
_isLoading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
|
_roulettePreviewLiveData.postValue(RoulettePreview(0, can, items))
|
||||||
}
|
}
|
||||||
|
|
||||||
_roulettePreviewLiveData.postValue(RoulettePreview(can, items))
|
|
||||||
_isLoading.value = false
|
_isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,24 +112,41 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
if (!_isLoading.value!!) {
|
if (!_isLoading.value!!) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
||||||
if (rouletteId > 0) {
|
if (validationOptions()) {
|
||||||
updateRoulette(onSuccess)
|
if (rouletteId > 0) {
|
||||||
} else {
|
updateRoulette(onSuccess)
|
||||||
createRoulette(onSuccess)
|
} else {
|
||||||
|
createRoulette(onSuccess)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun validationOptions(): Boolean {
|
||||||
|
var totalPercentage = 0f
|
||||||
|
for (option in options) {
|
||||||
|
if (option.title.trim().isEmpty()) {
|
||||||
|
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||||
|
_isLoading.value = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPercentage += option.percentage.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalPercentage != 100.0f) {
|
||||||
|
_toastLiveData.value = "확률이 100%가 아닙니다"
|
||||||
|
_isLoading.value = false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateRoulette(onSuccess: (Boolean) -> Unit) {
|
private fun updateRoulette(onSuccess: (Boolean) -> Unit) {
|
||||||
val items = mutableListOf<RouletteItem>()
|
val items = mutableListOf<RouletteItem>()
|
||||||
for (option in options) {
|
for (option in options) {
|
||||||
if (option.title.trim().isEmpty()) {
|
items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat()))
|
||||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
|
||||||
_isLoading.value = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
items.add(RouletteItem(title = option.title, weight = option.weight))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val selectedRoulette = rouletteList[_selectedRouletteLiveData.value!!.ordinal]
|
val selectedRoulette = rouletteList[_selectedRouletteLiveData.value!!.ordinal]
|
||||||
|
@ -169,24 +173,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
SelectedRoulette.ROULETTE_3 -> "룰렛 3"
|
SelectedRoulette.ROULETTE_3 -> "룰렛 3"
|
||||||
}
|
}
|
||||||
|
|
||||||
var isAllActive = false
|
|
||||||
|
|
||||||
rouletteList
|
|
||||||
.filter {
|
|
||||||
it.id != selectedRoulette.id
|
|
||||||
}
|
|
||||||
.forEach {
|
|
||||||
if (it.isActive) {
|
|
||||||
isAllActive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val successMessage = if (isActive) {
|
val successMessage = if (isActive) {
|
||||||
"${selectedRouletteTitle}로 설정하였습니다."
|
"${selectedRouletteTitle}을 활성화 했습니다."
|
||||||
} else if (!isAllActive) {
|
|
||||||
"${selectedRouletteTitle}이 비활성화 되었습니다."
|
|
||||||
} else {
|
} else {
|
||||||
"${selectedRouletteTitle}을 설정했습니다."
|
"${selectedRouletteTitle}을 비활성화 했습니다."
|
||||||
}
|
}
|
||||||
|
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
@ -224,13 +214,7 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
private fun createRoulette(onSuccess: (Boolean) -> Unit) {
|
private fun createRoulette(onSuccess: (Boolean) -> Unit) {
|
||||||
val items = mutableListOf<RouletteItem>()
|
val items = mutableListOf<RouletteItem>()
|
||||||
for (option in options) {
|
for (option in options) {
|
||||||
if (option.title.trim().isEmpty()) {
|
items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat()))
|
||||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
|
||||||
_isLoading.value = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
items.add(RouletteItem(title = option.title, weight = option.weight))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val request = CreateRouletteRequest(
|
val request = CreateRouletteRequest(
|
||||||
|
@ -348,10 +332,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
isActive = roulette.isActive
|
isActive = roulette.isActive
|
||||||
|
|
||||||
val options = roulette.items.asSequence().map { item ->
|
val options = roulette.items.asSequence().map { item ->
|
||||||
RouletteOption(title = item.title, weight = item.weight)
|
RouletteOption(title = item.title, percentage = item.percentage.toString())
|
||||||
}.toList()
|
}.toList()
|
||||||
removeAllAndAddOptions(options = options)
|
removeAllAndAddOptions(options = options)
|
||||||
recalculatePercentages(options)
|
_optionsLiveData.value = options
|
||||||
} else {
|
} else {
|
||||||
_canLiveData.value = 0
|
_canLiveData.value = 0
|
||||||
_isActiveLiveData.value = false
|
_isActiveLiveData.value = false
|
||||||
|
@ -361,15 +345,30 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
||||||
isActive = false
|
isActive = false
|
||||||
|
|
||||||
options.clear()
|
options.clear()
|
||||||
options.add(RouletteOption(title = "", weight = 1))
|
options.add(RouletteOption(title = "", percentage = ""))
|
||||||
options.add(RouletteOption(title = "", weight = 1))
|
options.add(RouletteOption(title = "", percentage = ""))
|
||||||
recalculatePercentages(options)
|
_optionsLiveData.value = options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
calculateTotalPercentage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAllAndAddOptions(options: List<RouletteOption>) {
|
private fun removeAllAndAddOptions(options: List<RouletteOption>) {
|
||||||
this.options.clear()
|
this.options.clear()
|
||||||
this.options.addAll(options)
|
this.options.addAll(options)
|
||||||
|
calculateTotalPercentage()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateTotalPercentage() {
|
||||||
|
val totalPercent = options.map {
|
||||||
|
try {
|
||||||
|
it.percentage.toFloat()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
0f
|
||||||
|
}
|
||||||
|
}.sum()
|
||||||
|
|
||||||
|
_totalPercentageLiveData.value = totalPercent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.google.android.material.tabs.TabLayout
|
||||||
import kr.co.vividnext.sodalive.R
|
import kr.co.vividnext.sodalive.R
|
||||||
import kr.co.vividnext.sodalive.base.BaseActivity
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
import kr.co.vividnext.sodalive.common.Constants
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
|
||||||
import kr.co.vividnext.sodalive.databinding.ActivityCanChargeBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityCanChargeBinding
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapFragment
|
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapFragment
|
||||||
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgFragment
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgFragment
|
||||||
|
@ -42,7 +41,10 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
)
|
)
|
||||||
|
|
||||||
supportFragmentManager.beginTransaction()
|
supportFragmentManager.beginTransaction()
|
||||||
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
.replace(
|
||||||
|
R.id.fl_container,
|
||||||
|
CanChargePgFragment()
|
||||||
|
).commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupView() {
|
override fun setupView() {
|
||||||
|
@ -56,33 +58,29 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTabs() {
|
private fun setupTabs() {
|
||||||
if (SharedPreferenceManager.isAuth) {
|
val tabs = binding.tabs
|
||||||
val tabs = binding.tabs
|
|
||||||
|
|
||||||
tabs.visibility = View.VISIBLE
|
tabs.visibility = View.VISIBLE
|
||||||
tabs.addTab(tabs.newTab().setText("인 앱 결제"))
|
tabs.addTab(tabs.newTab().setText("PG"))
|
||||||
tabs.addTab(tabs.newTab().setText("PG"))
|
tabs.addTab(tabs.newTab().setText("인 앱 결제"))
|
||||||
|
|
||||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||||
when (tab.position) {
|
when (tab.position) {
|
||||||
0 -> supportFragmentManager.beginTransaction()
|
0 -> supportFragmentManager.beginTransaction()
|
||||||
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
.replace(R.id.fl_container, CanChargePgFragment()).commit()
|
||||||
|
|
||||||
1 -> supportFragmentManager.beginTransaction()
|
1 -> supportFragmentManager.beginTransaction()
|
||||||
.replace(R.id.fl_container, CanChargePgFragment()).commit()
|
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTabUnselected(tab: TabLayout.Tab) {
|
override fun onTabUnselected(tab: TabLayout.Tab) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTabReselected(tab: TabLayout.Tab) {
|
override fun onTabReselected(tab: TabLayout.Tab) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
binding.tabs.visibility = View.GONE
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectCan(model: CanResponse) {
|
fun selectCan(model: CanResponse) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
|
@ -42,10 +41,6 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
|
|
||||||
private lateinit var purchaseUpdateListener: PurchasesUpdatedListener
|
private lateinit var purchaseUpdateListener: PurchasesUpdatedListener
|
||||||
|
|
||||||
fun safeContext(): Context? {
|
|
||||||
return if (isAdded) context else null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
@ -56,29 +51,9 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
setupBillingClient()
|
setupBillingClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onDestroy() {
|
||||||
super.onStart()
|
|
||||||
|
|
||||||
billingClient.startConnection(object : BillingClientStateListener {
|
|
||||||
override fun onBillingServiceDisconnected() {
|
|
||||||
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
|
||||||
viewModel.setLoading(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
|
||||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
|
||||||
queryAndConsumeUnconsumedPurchases()
|
|
||||||
} else {
|
|
||||||
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
|
||||||
viewModel.setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
billingClient.endConnection()
|
billingClient.endConnection()
|
||||||
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindData() {
|
private fun bindData() {
|
||||||
|
@ -171,6 +146,22 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
loadingDialog.show(screenWidth)
|
loadingDialog.show(screenWidth)
|
||||||
|
|
||||||
|
billingClient.startConnection(object : BillingClientStateListener {
|
||||||
|
override fun onBillingServiceDisconnected() {
|
||||||
|
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||||
|
viewModel.setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||||
|
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
|
queryAndConsumeUnconsumedPurchases()
|
||||||
|
} else {
|
||||||
|
viewModel.showToast("인 앱 결제 이용이 불가능 합니다. 다시 시도해 주세요.")
|
||||||
|
viewModel.setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
@ -219,7 +210,9 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
if (purchaseList.isNotEmpty()) {
|
if (purchaseList.isNotEmpty()) {
|
||||||
for (purchase in purchaseList) {
|
for (purchase in purchaseList) {
|
||||||
if (!purchase.isAcknowledged) {
|
if (!purchase.isAcknowledged) {
|
||||||
consumePurchase(purchase)
|
consumePurchase(purchase) {
|
||||||
|
queryAvailableCans()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,14 +222,14 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun consumePurchase(purchase: Purchase) {
|
private fun consumePurchase(purchase: Purchase, onSuccess: () -> Unit) {
|
||||||
val params = ConsumeParams.newBuilder()
|
val params = ConsumeParams.newBuilder()
|
||||||
.setPurchaseToken(purchase.purchaseToken)
|
.setPurchaseToken(purchase.purchaseToken)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
billingClient.consumeAsync(params) { billingResult, _ ->
|
billingClient.consumeAsync(params) { billingResult, _ ->
|
||||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||||
queryAvailableCans()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,237 @@
|
||||||
|
package kr.co.vividnext.sodalive.mypage.can.payment
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import kr.co.bootpay.android.Bootpay
|
||||||
|
import kr.co.bootpay.android.events.BootpayEventListener
|
||||||
|
import kr.co.bootpay.android.models.BootUser
|
||||||
|
import kr.co.bootpay.android.models.Payload
|
||||||
|
import kr.co.vividnext.sodalive.BuildConfig
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityCanPaymentBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.fontSpan
|
||||||
|
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||||
|
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.VerifyRequest
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class CanPaymentTempActivity : BaseActivity<ActivityCanPaymentBinding>(
|
||||||
|
ActivityCanPaymentBinding::inflate
|
||||||
|
) {
|
||||||
|
enum class PaymentMethod(val method: String) {
|
||||||
|
CARD("카드"), BANK("계좌이체"), PHONE("휴대폰")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val viewModel: CanPaymentTempViewModel by inject()
|
||||||
|
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var title: String
|
||||||
|
private var can: Int = 0
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
bindData()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
override fun setupView() {
|
||||||
|
title = intent.getStringExtra("title") ?: ""
|
||||||
|
can = intent.getIntExtra("can", 0)
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
|
||||||
|
if (title.isBlank() || can <= 0) {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
"다시 시도해 주세요.\n계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다.",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.toolbar.tvBack.text = "결제하기"
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
binding.ivCan.visibility = View.GONE
|
||||||
|
binding.tvAlert.visibility = View.GONE
|
||||||
|
binding.tvChargeCanTitle.text = title
|
||||||
|
binding.tvPrice.text = (can * 110).moneyFormat()
|
||||||
|
binding.tvPaymentPrice.text = "${(can * 110).moneyFormat()}원".fontSpan(
|
||||||
|
ResourcesCompat.getFont(applicationContext, R.font.gmarket_sans_light),
|
||||||
|
"원"
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.tvAgree.setOnClickListener {
|
||||||
|
binding.tvAgree.isSelected = !binding.tvAgree.isSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvPayment.setOnClickListener {
|
||||||
|
if (viewModel.paymentMethodLiveData.value == null) {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
"결제수단을 선택해 주세요.",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!binding.tvAgree.isSelected) {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
"결제 진행에 동의하셔야 결제가 가능합니다.",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
|
||||||
|
requestCharge()
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvMethodCard.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.CARD) }
|
||||||
|
binding.tvMethodBank.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.BANK) }
|
||||||
|
binding.tvMethodPhone.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.PHONE) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun allPaymentMethodSelectFalse() {
|
||||||
|
paymentMethodSelectFalse(binding.tvMethodBank)
|
||||||
|
paymentMethodSelectFalse(binding.tvMethodCard)
|
||||||
|
paymentMethodSelectFalse(binding.tvMethodPhone)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun paymentMethodSelectFalse(view: TextView) {
|
||||||
|
view.typeface = ResourcesCompat.getFont(
|
||||||
|
applicationContext,
|
||||||
|
R.font.gmarket_sans_medium
|
||||||
|
)
|
||||||
|
|
||||||
|
view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_eeeeee))
|
||||||
|
view.setBackgroundResource(R.drawable.bg_round_corner_10_232323_777777)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun paymentMethodSelect(view: TextView) {
|
||||||
|
view.typeface = ResourcesCompat.getFont(
|
||||||
|
applicationContext,
|
||||||
|
R.font.gmarket_sans_bold
|
||||||
|
)
|
||||||
|
|
||||||
|
view.setTextColor(ContextCompat.getColor(applicationContext, R.color.color_3bb9f1))
|
||||||
|
view.setBackgroundResource(R.drawable.bg_round_corner_10_13181b_3bb9f1)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestCharge() {
|
||||||
|
viewModel.chargeCan(
|
||||||
|
can = can,
|
||||||
|
paymentGateway = PaymentGateway.PG,
|
||||||
|
onSuccess = {
|
||||||
|
requestPayment(chargeId = it)
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestPayment(chargeId: Long) {
|
||||||
|
val user = BootUser()
|
||||||
|
.setId("${SharedPreferenceManager.userId}")
|
||||||
|
.setUsername(SharedPreferenceManager.nickname)
|
||||||
|
|
||||||
|
val payload = Payload()
|
||||||
|
.setApplicationId(BuildConfig.BOOTPAY_APP_ID)
|
||||||
|
.setOrderId("$chargeId")
|
||||||
|
.setOrderName(title)
|
||||||
|
.setPrice((can * 110).toDouble())
|
||||||
|
.setTaxFree(0.toDouble())
|
||||||
|
.setPg("세틀뱅크")
|
||||||
|
.setMethod(viewModel.paymentMethodLiveData.value!!.method)
|
||||||
|
.setUser(user)
|
||||||
|
|
||||||
|
Bootpay.init(this, this)
|
||||||
|
.setPayload(payload)
|
||||||
|
.setEventListener(object : BootpayEventListener {
|
||||||
|
override fun onCancel(data: String) {
|
||||||
|
Logger.e("onCancel: $data")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(data: String) {
|
||||||
|
Logger.e("onError: $data")
|
||||||
|
Toast.makeText(applicationContext, data, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClose() {
|
||||||
|
Logger.e("onClose")
|
||||||
|
Bootpay.removePaymentWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onIssued(data: String) {
|
||||||
|
Logger.e("onIssued: $data")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfirm(data: String): Boolean {
|
||||||
|
Logger.e("onConfirm: $data")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDone(data: String) {
|
||||||
|
Logger.e("onDone: $data")
|
||||||
|
handler.post {
|
||||||
|
verifyPayment(data)
|
||||||
|
Bootpay.removePaymentWindow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).requestPayment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verifyPayment(data: String) {
|
||||||
|
val bootpayResponse = Gson().fromJson(data, BootpayResponse::class.java)
|
||||||
|
val request = VerifyRequest(bootpayResponse.data.receiptId, bootpayResponse.data.orderId)
|
||||||
|
|
||||||
|
viewModel.verify(
|
||||||
|
request,
|
||||||
|
onSuccess = {
|
||||||
|
SharedPreferenceManager.can += can
|
||||||
|
setResult(RESULT_OK)
|
||||||
|
finish()
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.paymentMethodLiveData.observe(this) {
|
||||||
|
allPaymentMethodSelectFalse()
|
||||||
|
|
||||||
|
if (it != null) {
|
||||||
|
when (it) {
|
||||||
|
PaymentMethod.CARD -> paymentMethodSelect(binding.tvMethodCard)
|
||||||
|
PaymentMethod.BANK -> paymentMethodSelect(binding.tvMethodBank)
|
||||||
|
PaymentMethod.PHONE -> paymentMethodSelect(binding.tvMethodPhone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth, "")
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package kr.co.vividnext.sodalive.mypage.can.payment
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.VerifyRequest
|
||||||
|
|
||||||
|
class CanPaymentTempRepository(private val api: CanTempApi) {
|
||||||
|
fun chargeCan(
|
||||||
|
request: ChargeTempRequest,
|
||||||
|
token: String
|
||||||
|
) = api.chargeCan(request, authHeader = token)
|
||||||
|
|
||||||
|
fun verify(
|
||||||
|
request: VerifyRequest,
|
||||||
|
token: String
|
||||||
|
) = api.verifyCharge(request, authHeader = token)
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package kr.co.vividnext.sodalive.mypage.can.payment
|
||||||
|
|
||||||
|
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.mypage.can.charge.pg.VerifyRequest
|
||||||
|
|
||||||
|
class CanPaymentTempViewModel(private val repository: CanPaymentTempRepository) : BaseViewModel() {
|
||||||
|
private val _paymentMethodLiveData = MutableLiveData<CanPaymentTempActivity.PaymentMethod?>()
|
||||||
|
val paymentMethodLiveData: LiveData<CanPaymentTempActivity.PaymentMethod?>
|
||||||
|
get() = _paymentMethodLiveData
|
||||||
|
|
||||||
|
private var _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
fun chargeCan(
|
||||||
|
can: Int,
|
||||||
|
paymentGateway: PaymentGateway,
|
||||||
|
onSuccess: (Long) -> Unit,
|
||||||
|
onFailure: (String) -> Unit
|
||||||
|
) {
|
||||||
|
_isLoading.value = true
|
||||||
|
val request = ChargeTempRequest(can, can * 110, paymentGateway)
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.chargeCan(request, "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
onSuccess(it.data.chargeId)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
onFailure(it.message)
|
||||||
|
} else {
|
||||||
|
onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verify(request: VerifyRequest, onSuccess: () -> Unit, onFailure: (String) -> Unit) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.verify(
|
||||||
|
request = request,
|
||||||
|
"Bearer ${SharedPreferenceManager.token}"
|
||||||
|
).subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
onFailure(it.message)
|
||||||
|
} else {
|
||||||
|
onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
onFailure("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPaymentMethod(paymentMethod: CanPaymentTempActivity.PaymentMethod) {
|
||||||
|
_paymentMethodLiveData.value = paymentMethod
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package kr.co.vividnext.sodalive.mypage.can.payment
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.ChargeResponse
|
||||||
|
import kr.co.vividnext.sodalive.mypage.can.charge.pg.VerifyRequest
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
interface CanTempApi {
|
||||||
|
@POST("/charge/temp")
|
||||||
|
fun chargeCan(
|
||||||
|
@Body chargeRequest: ChargeTempRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<ChargeResponse>>
|
||||||
|
|
||||||
|
@POST("/charge/temp/verify")
|
||||||
|
fun verifyCharge(
|
||||||
|
@Body request: VerifyRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
data class ChargeTempRequest(
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("paymentGateway") val paymentGateway: PaymentGateway
|
||||||
|
)
|
|
@ -23,7 +23,7 @@ class MemberTagAdapter(
|
||||||
fun bind(item: MemberTagResponse) {
|
fun bind(item: MemberTagResponse) {
|
||||||
if (selectedTags.contains(item.tag)) {
|
if (selectedTags.contains(item.tag)) {
|
||||||
binding.ivTagChecked.visibility = View.VISIBLE
|
binding.ivTagChecked.visibility = View.VISIBLE
|
||||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_3bb9f1)
|
||||||
isChecked = true
|
isChecked = true
|
||||||
} else {
|
} else {
|
||||||
binding.ivTagChecked.visibility = View.GONE
|
binding.ivTagChecked.visibility = View.GONE
|
||||||
|
@ -44,7 +44,7 @@ class MemberTagAdapter(
|
||||||
if (onItemClick(item.tag, isChecked)) {
|
if (onItemClick(item.tag, isChecked)) {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
binding.ivTagChecked.visibility = View.VISIBLE
|
binding.ivTagChecked.visibility = View.VISIBLE
|
||||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_3bb9f1)
|
||||||
} else {
|
} else {
|
||||||
binding.ivTagChecked.visibility = View.GONE
|
binding.ivTagChecked.visibility = View.GONE
|
||||||
binding.ivTag.background = null
|
binding.ivTag.background = null
|
||||||
|
|
|
@ -34,8 +34,13 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val lp = binding.ivText.layoutParams as ConstraintLayout.LayoutParams
|
val lp = binding.ivText.layoutParams as ConstraintLayout.LayoutParams
|
||||||
lp.topMargin = screenHeight * 787 / 2337
|
lp.topMargin = screenHeight * 302 / 2337
|
||||||
binding.ivText.layoutParams = lp
|
binding.ivText.layoutParams = lp
|
||||||
|
|
||||||
|
val lp2 = binding.ivText2.layoutParams as ConstraintLayout.LayoutParams
|
||||||
|
lp2.bottomMargin = screenHeight * 195 / 2337
|
||||||
|
binding.ivText2.layoutParams = lp2
|
||||||
|
|
||||||
setupRemoteConfig()
|
setupRemoteConfig()
|
||||||
fetchAndroidLatestVersion()
|
fetchAndroidLatestVersion()
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 996 B |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 886 B |
After Width: | Height: | Size: 418 B |
After Width: | Height: | Size: 3.3 MiB |
Before Width: | Height: | Size: 3.1 MiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ff14d9" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ff14d9" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ffcb14" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ffcb14" />
|
||||||
|
</shape>
|
|
@ -4,5 +4,5 @@
|
||||||
<corners android:radius="10dp" />
|
<corners android:radius="10dp" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="1dp"
|
android:width="1dp"
|
||||||
android:color="@color/color_9970ff" />
|
android:color="@color/color_ff14d9" />
|
||||||
</shape>
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="10dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ffcb14" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_002abd" />
|
||||||
|
<corners android:radius="13.3dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_002abd" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_3bb9f1" />
|
||||||
|
<corners android:radius="13.3dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_3bb9f1" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ec6033" />
|
||||||
|
<corners android:radius="13.3dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ec6033" />
|
||||||
|
</shape>
|
|
@ -4,5 +4,5 @@
|
||||||
<corners android:radius="16.7dp" />
|
<corners android:radius="16.7dp" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="1dp"
|
android:width="1dp"
|
||||||
android:color="@color/color_9970ff" />
|
android:color="@color/color_3bb9f1" />
|
||||||
</shape>
|
</shape>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_222222" />
|
||||||
|
<corners android:radius="26.7dp" />
|
||||||
|
<stroke android:width="0dp" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="26.7dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_909090" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_312827" />
|
||||||
|
<corners android:radius="2.6dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_312827" />
|
||||||
|
</shape>
|
|
@ -3,5 +3,5 @@
|
||||||
<corners android:radius="30dp" />
|
<corners android:radius="30dp" />
|
||||||
<stroke
|
<stroke
|
||||||
android:width="1dp"
|
android:width="1dp"
|
||||||
android:color="@color/color_9970ff" />
|
android:color="@color/color_3bb9f1" />
|
||||||
</shape>
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ccc25264" />
|
||||||
|
<corners android:radius="5.3dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ccc25264" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ff14d9" />
|
||||||
|
<corners android:radius="6.7dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ff14d9" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_ffcb14" />
|
||||||
|
<corners android:radius="6.7dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_ffcb14" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_111111" />
|
||||||
|
<corners
|
||||||
|
android:topLeftRadius="21.3dp"
|
||||||
|
android:topRightRadius="21.3dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_111111" />
|
||||||
|
</shape>
|
|
@ -295,6 +295,7 @@
|
||||||
tools:text="매버릭 팔레트 (feat. J-DRAGON)" />
|
tools:text="매버릭 팔레트 (feat. J-DRAGON)" />
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
android:id="@+id/sv_action_buttons"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="13.3dp">
|
android:layout_marginTop="13.3dp">
|
||||||
|
@ -545,6 +546,7 @@
|
||||||
android:visibility="gone">
|
android:visibility="gone">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/iv_can"
|
||||||
android:layout_width="16.7dp"
|
android:layout_width="16.7dp"
|
||||||
android:layout_height="16.7dp"
|
android:layout_height="16.7dp"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
|
@ -561,6 +563,7 @@
|
||||||
tools:text="300" />
|
tools:text="300" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/tv_unit"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_light"
|
android:fontFamily="@font/gmarket_sans_light"
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
android:layout_width="106.7dp"
|
android:layout_width="106.7dp"
|
||||||
android:layout_height="106.7dp"
|
android:layout_height="106.7dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@drawable/bg_round_corner_13_3_3e3358"
|
android:background="@drawable/bg_round_corner_13_3_13181b"
|
||||||
android:contentDescription="@null"
|
android:contentDescription="@null"
|
||||||
android:padding="13.3dp"
|
android:padding="13.3dp"
|
||||||
android:src="@drawable/ic_logo" />
|
android:src="@drawable/ic_logo" />
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingVertical="14.3dp">
|
android:paddingVertical="14.3dp">
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:text="전체 연령"
|
android:text="전체 연령"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
android:textSize="14.7sp" />
|
android:textSize="14.7sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="13.3dp"
|
android:layout_marginStart="13.3dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingVertical="14.3dp">
|
android:paddingVertical="14.3dp">
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:text="19세 이상"
|
android:text="19세 이상"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
android:textSize="14.7sp" />
|
android:textSize="14.7sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -300,7 +300,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingVertical="14.3dp">
|
android:paddingVertical="14.3dp">
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:text="댓글 가능"
|
android:text="댓글 가능"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
android:textSize="14.7sp" />
|
android:textSize="14.7sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="13.3dp"
|
android:layout_marginStart="13.3dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingVertical="14.3dp">
|
android:paddingVertical="14.3dp">
|
||||||
|
|
||||||
|
@ -348,7 +348,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:text="댓글 불가"
|
android:text="댓글 불가"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
android:textSize="14.7sp" />
|
android:textSize="14.7sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -368,11 +368,11 @@
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_marginEnd="6.7dp"
|
android:layout_marginEnd="6.7dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_1f1734_9970ff"
|
android:background="@drawable/bg_round_corner_6_7_13181b_3bb9f1"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="취소"
|
android:text="취소"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
android:textSize="18.3sp" />
|
android:textSize="18.3sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -381,7 +381,7 @@
|
||||||
android:layout_height="50dp"
|
android:layout_height="50dp"
|
||||||
android:layout_marginStart="6.7dp"
|
android:layout_marginStart="6.7dp"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:background="@drawable/bg_round_corner_6_7_9970ff"
|
android:background="@drawable/bg_round_corner_6_7_3bb9f1"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="수정"
|
android:text="수정"
|
||||||
|
|
|
@ -33,29 +33,32 @@
|
||||||
android:paddingHorizontal="13.3dp"
|
android:paddingHorizontal="13.3dp"
|
||||||
android:paddingVertical="23.3dp">
|
android:paddingVertical="23.3dp">
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:id="@+id/ic_can"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@null"
|
android:orientation="horizontal"
|
||||||
android:src="@drawable/ic_can"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/tv_charge_can_title"
|
android:id="@+id/iv_can"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="13.3dp"
|
android:layout_marginEnd="13.3dp"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:contentDescription="@null"
|
||||||
android:gravity="center"
|
android:src="@drawable/ic_can" />
|
||||||
android:textColor="@color/color_eeeeee"
|
|
||||||
android:textSize="15.3sp"
|
<TextView
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/ic_can"
|
android:id="@+id/tv_charge_can_title"
|
||||||
app:layout_constraintStart_toEndOf="@+id/ic_can"
|
android:layout_width="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="@+id/ic_can"
|
android:layout_height="wrap_content"
|
||||||
tools:text="5000 캔 + 1000 캔" />
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="@color/color_eeeeee"
|
||||||
|
android:textSize="15.3sp"
|
||||||
|
tools:text="5000 캔 + 1000 캔" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/ll_price"
|
android:id="@+id/ll_price"
|
||||||
|
@ -171,6 +174,7 @@
|
||||||
app:drawableStartCompat="@drawable/ic_select" />
|
app:drawableStartCompat="@drawable/ic_select" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/tv_alert"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="26.7dp"
|
android:layout_marginHorizontal="26.7dp"
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="13.3dp"
|
android:layout_marginHorizontal="13.3dp"
|
||||||
android:layout_marginTop="60dp"
|
android:layout_marginTop="60dp"
|
||||||
android:background="@drawable/bg_round_corner_6_7_9970ff"
|
android:background="@drawable/bg_round_corner_6_7_3bb9f1"
|
||||||
android:fontFamily="@font/gmarket_sans_bold"
|
android:fontFamily="@font/gmarket_sans_bold"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingVertical="16dp"
|
android:paddingVertical="16dp"
|
||||||
|
@ -102,13 +102,13 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginTop="93dp"
|
android:layout_marginTop="93dp"
|
||||||
android:background="@drawable/bg_round_corner_8_transparent_9970ff"
|
android:background="@drawable/bg_round_corner_8_transparent_3bb9f1"
|
||||||
android:drawablePadding="13.3dp"
|
android:drawablePadding="13.3dp"
|
||||||
android:paddingHorizontal="18.7dp"
|
android:paddingHorizontal="18.7dp"
|
||||||
android:paddingVertical="10.7dp"
|
android:paddingVertical="10.7dp"
|
||||||
android:text="고객센터로 문의하기"
|
android:text="고객센터로 문의하기"
|
||||||
android:textColor="@color/color_9970ff"
|
android:textColor="@color/color_3bb9f1"
|
||||||
app:drawableStartCompat="@drawable/ic_headphones_purple" />
|
app:drawableStartCompat="@drawable/ic_headphones_blue" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -29,9 +29,10 @@
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginTop="28.3dp"
|
android:layout_marginTop="28.3dp"
|
||||||
android:fontFamily="@font/gmarket_sans_medium"
|
android:fontFamily="@font/gmarket_sans_medium"
|
||||||
android:text="🙀현재 참여 가능한 라이브 방송이 없거나\n연령제한으로 입장이 불가능합니다.\n본인인증을 해보거나 채널을 팔로잉하고\n라이브 방송 알림을 받아보세요."
|
android:text="현재 참여 가능한 라이브 방송이 없거나\n연령제한으로 입장이 불가능합니다.\n본인인증을 해보거나 채널을 팔로잉하고\n라이브 방송 알림을 받아보세요."
|
||||||
android:textColor="@color/color_bbbbbb"
|
android:textColor="@color/color_bbbbbb"
|
||||||
android:textSize="15sp"
|
android:textSize="13sp"
|
||||||
|
android:lineSpacingExtra="8dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -63,9 +63,10 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="@font/gmarket_sans_medium"
|
android:fontFamily="@font/gmarket_sans_medium"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="지금 예약중인 라이브가 없습니다.\n채널을 팔로잉 하고 라이브 알림을 받아 보세요."
|
android:text="지금 예약중인 라이브가 없습니다.\n다른 날짜의 라이브를 예약하고 참여해 보세요."
|
||||||
android:textColor="@color/color_bbbbbb"
|
android:textColor="@color/color_bbbbbb"
|
||||||
android:textSize="10.7sp"
|
android:textSize="13sp"
|
||||||
|
android:lineSpacingExtra="8dp"
|
||||||
tools:ignore="SmallSp" />
|
tools:ignore="SmallSp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|