Compare commits
No commits in common. "b876695adc886b4ae04b8409165a7ebc6f23ed2f" and "e52075a692f14a3009954604ca0d19e3cfed14b9" have entirely different histories.
b876695adc
...
e52075a692
|
@ -1,10 +0,0 @@
|
|||
<?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"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 74
|
||||
versionName "1.11.3"
|
||||
versionCode 46
|
||||
versionName "1.8.21"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
|
|
@ -89,7 +89,6 @@
|
|||
android:name=".mypage.can.charge.CanChargeActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden" />
|
||||
<activity android:name=".mypage.can.payment.CanPaymentActivity" />
|
||||
<activity android:name=".mypage.can.payment.CanPaymentTempActivity" />
|
||||
<activity android:name=".mypage.can.coupon.CanCouponActivity" />
|
||||
<activity android:name=".live.room.create.LiveRoomCreateActivity" />
|
||||
<activity android:name=".live.room.update.LiveRoomEditActivity" />
|
||||
|
@ -134,9 +133,6 @@
|
|||
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
|
||||
<activity android:name=".audio_content.all.by_theme.AudioContentAllByThemeActivity" />
|
||||
<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
|
||||
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.content.Intent
|
|||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.media.AudioAttributes
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaPlayer
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
|
@ -368,7 +367,6 @@ class AudioContentPlayService :
|
|||
mediaPlayer.setOnCompletionListener(this)
|
||||
mediaPlayer.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.build()
|
||||
)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package kr.co.vividnext.sodalive.audio_content.detail
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
@ -14,8 +13,6 @@ import android.view.View
|
|||
import android.widget.RelativeLayout
|
||||
import android.widget.SeekBar
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
@ -40,16 +37,13 @@ import kr.co.vividnext.sodalive.common.Utils
|
|||
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
|
||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
|
||||
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.mypage.auth.Auth
|
||||
import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
|
||||
import kr.co.vividnext.sodalive.mypage.auth.BootpayResponse
|
||||
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 org.koin.android.ext.android.inject
|
||||
import kotlin.math.ceil
|
||||
|
||||
class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBinding>(
|
||||
ActivityAudioContentDetailBinding::inflate
|
||||
|
@ -69,10 +63,6 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
private var refresh = false
|
||||
private var title = ""
|
||||
|
||||
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
|
||||
private lateinit var audioContent: GetAudioContentDetailResponse
|
||||
private lateinit var orderType: OrderType
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
|
@ -97,14 +87,6 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
finish()
|
||||
}
|
||||
|
||||
activityResultLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) {
|
||||
if (it.resultCode == Activity.RESULT_OK) {
|
||||
contentOrder(audioContent, orderType)
|
||||
}
|
||||
}
|
||||
|
||||
bindData()
|
||||
viewModel.getAudioContentDetail(audioContentId = audioContentId) { finish() }
|
||||
}
|
||||
|
@ -451,11 +433,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
}
|
||||
|
||||
private fun setupCommentArea(response: GetAudioContentDetailResponse) {
|
||||
if (
|
||||
response.isCommentAvailable &&
|
||||
response.contentUrl.isNotBlank() &&
|
||||
response.releaseDate == null
|
||||
) {
|
||||
if (response.isCommentAvailable) {
|
||||
binding.llDonation.visibility = View.VISIBLE
|
||||
binding.llComment.visibility = View.VISIBLE
|
||||
binding.tvCommentCount.text = "${response.commentCount}"
|
||||
|
@ -534,29 +512,12 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
binding.tvReleaseDate.visibility = View.GONE
|
||||
binding.llPurchase.visibility = View.VISIBLE
|
||||
binding.llPurchasePrice.visibility = View.VISIBLE
|
||||
binding.tvPrice.text = response.price.toString()
|
||||
binding.llPurchase.background = ContextCompat.getDrawable(
|
||||
applicationContext,
|
||||
R.drawable.bg_round_corner_5_3_3bb9f1
|
||||
)
|
||||
|
||||
binding.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) {
|
||||
" 대여하기"
|
||||
} else {
|
||||
|
@ -696,54 +657,45 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
binding.tvTag.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (response.contentUrl.isNotBlank() && response.releaseDate == null) {
|
||||
binding.svActionButtons.visibility = View.VISIBLE
|
||||
binding.llLike.visibility = View.VISIBLE
|
||||
binding.ivLike.setImageResource(
|
||||
if (response.isLike) {
|
||||
R.drawable.ic_audio_content_heart_pressed
|
||||
binding.ivLike.setImageResource(
|
||||
if (response.isLike) {
|
||||
R.drawable.ic_audio_content_heart_pressed
|
||||
} else {
|
||||
R.drawable.ic_audio_content_heart_normal
|
||||
}
|
||||
)
|
||||
|
||||
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 {
|
||||
R.drawable.ic_audio_content_heart_normal
|
||||
}
|
||||
)
|
||||
|
||||
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)
|
||||
binding.tvLike.text = if (likeCount - 1 < 0) {
|
||||
"0"
|
||||
} else {
|
||||
binding.tvLike.text = if (likeCount - 1 < 0) {
|
||||
"0"
|
||||
} else {
|
||||
"${likeCount - 1}"
|
||||
}
|
||||
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_normal)
|
||||
"${likeCount - 1}"
|
||||
}
|
||||
binding.ivLike.setImageResource(R.drawable.ic_audio_content_heart_normal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.tvShare.visibility = View.VISIBLE
|
||||
binding.tvShare.setOnClickListener {
|
||||
viewModel.shareAudioContent(
|
||||
audioContentId = audioContentId,
|
||||
contentImage = response.coverImageUrl,
|
||||
contentTitle = "${response.title} - ${response.creator.nickname}"
|
||||
) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = "text/plain"
|
||||
intent.putExtra(Intent.EXTRA_TEXT, it)
|
||||
binding.tvShare.setOnClickListener {
|
||||
viewModel.shareAudioContent(
|
||||
audioContentId = audioContentId,
|
||||
contentImage = response.coverImageUrl,
|
||||
contentTitle = "${response.title} - ${response.creator.nickname}"
|
||||
) {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.type = "text/plain"
|
||||
intent.putExtra(Intent.EXTRA_TEXT, it)
|
||||
|
||||
val shareIntent = Intent.createChooser(intent, "오디오콘텐츠 공유")
|
||||
startActivity(shareIntent)
|
||||
}
|
||||
val shareIntent = Intent.createChooser(intent, "오디오콘텐츠 공유")
|
||||
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) {
|
||||
|
@ -882,43 +834,18 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
|
|||
|
||||
binding.rlPreviewAlert.visibility = View.GONE
|
||||
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
this@AudioContentDetailActivity.audioContent = audioContent
|
||||
this@AudioContentDetailActivity.orderType = orderType
|
||||
activityResultLauncher.launch(
|
||||
Intent(applicationContext, CanPaymentTempActivity::class.java).apply {
|
||||
putExtra("title", audioContent.title)
|
||||
putExtra(
|
||||
"can",
|
||||
if (orderType == OrderType.RENTAL) {
|
||||
ceil(audioContent.price * 0.6).toInt()
|
||||
} else {
|
||||
audioContent.price
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
contentOrder(audioContent, 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)
|
||||
}
|
||||
},
|
||||
).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() {
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package kr.co.vividnext.sodalive.audio_content.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.ContextCompat
|
||||
|
@ -27,19 +29,18 @@ 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.new_content.AudioContentMainNewContentThemeAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderListViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingAdapter
|
||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel
|
||||
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.base.BaseFragment
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.FragmentAudioContentMainBinding
|
||||
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.settings.event.EventDetailActivity
|
||||
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||
|
@ -49,8 +50,8 @@ import kotlin.math.roundToInt
|
|||
class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
||||
FragmentAudioContentMainBinding::inflate
|
||||
) {
|
||||
private val recommendSeriesViewModel: AudioContentMainRecommendSeriesViewModel by inject()
|
||||
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
||||
private val newContentCreatorViewModel: AudioContentMainNewContentCreatorViewModel by inject()
|
||||
private lateinit var newContentCreatorAdapter: AudioContentMainNewContentCreatorAdapter
|
||||
|
||||
private val bannerViewModel: AudioContentMainBannerViewModel by inject()
|
||||
private lateinit var bannerAdapter: AudioContentMainBannerAdapter
|
||||
|
@ -79,7 +80,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
newContentViewModel.getNewContentOfTheme("전체")
|
||||
contentRankingViewModel.getContentRanking()
|
||||
contentRankingViewModel.getContentRankingSortType()
|
||||
recommendSeriesViewModel.getRecommendSeriesList()
|
||||
newContentCreatorViewModel.getNewContentUploadCreatorList()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
|
@ -97,7 +98,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
binding.llUploadContent.visibility = View.GONE
|
||||
}
|
||||
|
||||
setupRecommendSeries()
|
||||
setupNewContentCreator()
|
||||
setupBanner()
|
||||
setupOrderList()
|
||||
setupNewContentTheme()
|
||||
|
@ -106,6 +107,17 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
setupContentRanking()
|
||||
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 {
|
||||
startActivity(
|
||||
Intent(requireContext(), AudioContentAllByThemeActivity::class.java).apply {
|
||||
|
@ -123,33 +135,20 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupRecommendSeries() {
|
||||
seriesAdapter = UserProfileSeriesListAdapter(
|
||||
onClickItem = {
|
||||
startActivity(
|
||||
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
|
||||
)
|
||||
private fun setupNewContentCreator() {
|
||||
newContentCreatorAdapter = AudioContentMainNewContentCreatorAdapter {
|
||||
val intent = Intent(requireContext(), UserProfileActivity::class.java)
|
||||
intent.putExtra(Constants.EXTRA_USER_ID, it)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
val recyclerView = binding.rvRecommendSeries
|
||||
recyclerView.layoutManager = LinearLayoutManager(
|
||||
requireContext(),
|
||||
binding.rvNewContentCreator.layoutManager = LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
|
||||
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
binding.rvNewContentCreator.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||
override fun getItemOffsets(
|
||||
outRect: Rect,
|
||||
view: View,
|
||||
|
@ -161,28 +160,28 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
when (parent.getChildAdapterPosition(view)) {
|
||||
0 -> {
|
||||
outRect.left = 0
|
||||
outRect.right = 6.7f.dpToPx().toInt()
|
||||
outRect.right = 10.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
seriesAdapter.itemCount - 1 -> {
|
||||
newContentCreatorAdapter.itemCount - 1 -> {
|
||||
outRect.left = 10.7f.dpToPx().toInt()
|
||||
outRect.right = 0
|
||||
outRect.left = 6.7f.dpToPx().toInt()
|
||||
}
|
||||
|
||||
else -> {
|
||||
outRect.left = 6.7f.dpToPx().toInt()
|
||||
outRect.right = 6.7f.dpToPx().toInt()
|
||||
outRect.left = 10.7f.dpToPx().toInt()
|
||||
outRect.right = 10.7f.dpToPx().toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
recyclerView.adapter = seriesAdapter
|
||||
binding.rvNewContentCreator.adapter = newContentCreatorAdapter
|
||||
|
||||
recommendSeriesViewModel.seriesListLiveData.observe(viewLifecycleOwner) {
|
||||
seriesAdapter.addItems(it)
|
||||
binding.llRecommendSeries.visibility = if (
|
||||
seriesAdapter.itemCount <= 0 && it.isEmpty()
|
||||
newContentCreatorViewModel.newContentUploadCreatorListLiveData.observe(viewLifecycleOwner) {
|
||||
newContentCreatorAdapter.addItems(it)
|
||||
binding.rvNewContentCreator.visibility = if (
|
||||
newContentCreatorAdapter.itemCount <= 0 && it.isEmpty()
|
||||
) {
|
||||
View.GONE
|
||||
} else {
|
||||
|
@ -190,14 +189,9 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
recommendSeriesViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
newContentCreatorViewModel.toastLiveData.observe(viewLifecycleOwner) {
|
||||
it?.let { Toast.makeText(requireContext(), it, Toast.LENGTH_LONG).show() }
|
||||
}
|
||||
|
||||
binding.llRecommendSeriesRefresh.setOnClickListener {
|
||||
seriesAdapter.clear()
|
||||
recommendSeriesViewModel.getRecommendSeriesList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupBanner() {
|
||||
|
|
|
@ -61,7 +61,6 @@ class AudioContentMainNewContentViewModel(
|
|||
}
|
||||
|
||||
fun getNewContentOfTheme(theme: String) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
repository.getNewContentOfTheme(
|
||||
theme = if (theme == "전체") {
|
||||
|
@ -86,13 +85,10 @@ class AudioContentMainNewContentViewModel(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
_isLoading.value = false
|
||||
},
|
||||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
_isLoading.value = false
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
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,42 +1,44 @@
|
|||
package kr.co.vividnext.sodalive.audio_content.main.recommend_series
|
||||
package kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
|
||||
import kr.co.vividnext.sodalive.audio_content.main.GetNewContentUploadCreator
|
||||
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
|
||||
class AudioContentMainRecommendSeriesViewModel(
|
||||
private val repository: SeriesRepository
|
||||
class AudioContentMainNewContentCreatorViewModel(
|
||||
private val repository: AudioContentRepository
|
||||
) : BaseViewModel() {
|
||||
private val _toastLiveData = MutableLiveData<String?>()
|
||||
val toastLiveData: LiveData<String?>
|
||||
get() = _toastLiveData
|
||||
|
||||
private var _seriesListLiveData = MutableLiveData<List<GetSeriesListResponse.SeriesListItem>>()
|
||||
val seriesListLiveData: LiveData<List<GetSeriesListResponse.SeriesListItem>>
|
||||
get() = _seriesListLiveData
|
||||
private var _newContentUploadCreatorListLiveData =
|
||||
MutableLiveData<List<GetNewContentUploadCreator>>()
|
||||
val newContentUploadCreatorListLiveData: LiveData<List<GetNewContentUploadCreator>>
|
||||
get() = _newContentUploadCreatorListLiveData
|
||||
|
||||
fun getRecommendSeriesList() {
|
||||
fun getNewContentUploadCreatorList() {
|
||||
compositeDisposable.add(
|
||||
repository
|
||||
.getRecommendSeriesList(token = "Bearer ${SharedPreferenceManager.token}")
|
||||
repository.getNewContentUploadCreatorList(
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
if (it.success && it.data != null) {
|
||||
_seriesListLiveData.value = it.data!!
|
||||
_newContentUploadCreatorListLiveData.postValue(it.data!!)
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
} else {
|
||||
_toastLiveData.postValue(
|
||||
"추천 시리즈를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
)
|
||||
}
|
||||
|
@ -45,7 +47,7 @@ class AudioContentMainRecommendSeriesViewModel(
|
|||
{
|
||||
it.message?.let { message -> Logger.e(message) }
|
||||
_toastLiveData.postValue(
|
||||
"추천 시리즈를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||
"크리에이터 리스트를 불러오지 못했습니다. 다시 시도해 주세요.\n" +
|
||||
"계속 같은 문제가 발생할 경우 고객센터로 문의 주시기 바랍니다."
|
||||
)
|
||||
}
|
|
@ -173,17 +173,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
|||
R.color.color_eeeeee
|
||||
)
|
||||
)
|
||||
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
binding.llCommentYes.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
||||
|
||||
binding.ivCommentNo.visibility = View.GONE
|
||||
binding.tvCommentNo.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_3bb9f1
|
||||
R.color.color_9970ff
|
||||
)
|
||||
)
|
||||
binding.llCommentNo.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_6_7_13181b_3bb9f1
|
||||
R.drawable.bg_round_corner_6_7_1f1734_9970ff
|
||||
)
|
||||
} else {
|
||||
binding.ivCommentNo.visibility = View.VISIBLE
|
||||
|
@ -193,17 +193,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
|||
R.color.color_eeeeee
|
||||
)
|
||||
)
|
||||
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
binding.llCommentNo.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
||||
|
||||
binding.ivCommentYes.visibility = View.GONE
|
||||
binding.tvCommentYes.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_3bb9f1
|
||||
R.color.color_9970ff
|
||||
)
|
||||
)
|
||||
binding.llCommentYes
|
||||
.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b_3bb9f1)
|
||||
.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734_9970ff)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,17 +223,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
|||
if (it) {
|
||||
binding.ivAgeAll.visibility = View.GONE
|
||||
binding.llAgeAll.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_6_7_13181b
|
||||
R.drawable.bg_round_corner_6_7_1f1734
|
||||
)
|
||||
binding.tvAgeAll.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_3bb9f1
|
||||
R.color.color_9970ff
|
||||
)
|
||||
)
|
||||
|
||||
binding.ivAge19.visibility = View.VISIBLE
|
||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
|
||||
binding.tvAge19.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
|
@ -242,17 +242,17 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
|
|||
)
|
||||
} else {
|
||||
binding.ivAge19.visibility = View.GONE
|
||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_13181b)
|
||||
binding.llAge19.setBackgroundResource(R.drawable.bg_round_corner_6_7_1f1734)
|
||||
binding.tvAge19.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
applicationContext,
|
||||
R.color.color_3bb9f1
|
||||
R.color.color_9970ff
|
||||
)
|
||||
)
|
||||
|
||||
binding.ivAgeAll.visibility = View.VISIBLE
|
||||
binding.llAgeAll.setBackgroundResource(
|
||||
R.drawable.bg_round_corner_6_7_3bb9f1
|
||||
R.drawable.bg_round_corner_6_7_9970ff
|
||||
)
|
||||
binding.tvAgeAll.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
|
|
|
@ -4,17 +4,14 @@ import android.app.Activity
|
|||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import coil.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
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.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kotlin.math.ceil
|
||||
|
||||
class AudioContentOrderConfirmDialog(
|
||||
|
@ -61,35 +58,16 @@ class AudioContentOrderConfirmDialog(
|
|||
}
|
||||
|
||||
dialogView.tvDuration.text = duration
|
||||
|
||||
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()}원"
|
||||
}
|
||||
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
|
||||
"${ceil(price * 0.6).toInt()}"
|
||||
} else {
|
||||
dialogView.ivCan.visibility = View.VISIBLE
|
||||
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
|
||||
ceil(price * 0.6).toInt().moneyFormat()
|
||||
} else {
|
||||
price.moneyFormat()
|
||||
}
|
||||
"$price"
|
||||
}
|
||||
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||
"콘텐츠를 대여하시겠습니까?"
|
||||
} else {
|
||||
"콘텐츠를 소장하시겠습니까?"
|
||||
}
|
||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||
"콘텐츠를 대여하시겠습니까?\n아래 캔이 차감됩니다."
|
||||
} else {
|
||||
dialogView.tvNotice.text = if (orderType == OrderType.RENTAL) {
|
||||
"콘텐츠를 대여하시겠습니까?\n아래 캔이 차감됩니다."
|
||||
} else {
|
||||
"콘텐츠를 소장하시겠습니까?\n아래 캔이 차감됩니다."
|
||||
}
|
||||
"콘텐츠를 소장하시겠습니까?\n아래 캔이 차감됩니다."
|
||||
}
|
||||
|
||||
dialogView.tvCancel.setOnClickListener {
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
package kr.co.vividnext.sodalive.audio_content.order
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.extensions.moneyFormat
|
||||
import kotlin.math.ceil
|
||||
|
||||
class AudioContentOrderFragment(
|
||||
|
@ -29,33 +26,15 @@ class AudioContentOrderFragment(
|
|||
return binding.root
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
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 (SharedPreferenceManager.userId == 17958L) {
|
||||
binding.tvRental.text = "${(price * 110).moneyFormat()}원"
|
||||
} else {
|
||||
binding.tvRental.text = price.moneyFormat()
|
||||
}
|
||||
binding.tvRental.text = "$price"
|
||||
binding.rlKeep.visibility = View.GONE
|
||||
} else {
|
||||
if (SharedPreferenceManager.userId == 17958L) {
|
||||
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.tvKeep.text = "$price"
|
||||
binding.tvRental.text = "${ceil(price * 0.6).toInt()}"
|
||||
|
||||
binding.rlKeep.visibility = View.VISIBLE
|
||||
binding.llKeep.setOnClickListener {
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
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
|
||||
)
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
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>>>
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
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()
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
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)
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
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()
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
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
|
|
@ -1,36 +0,0 @@
|
|||
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
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
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,17 +20,14 @@ object Constants {
|
|||
const val EXTRA_DATA = "extra_data"
|
||||
const val EXTRA_TERMS = "extra_terms"
|
||||
const val EXTRA_EVENT = "extra_event"
|
||||
const val EXTRA_SERIES = "extra_series"
|
||||
const val EXTRA_NOTICE = "extra_notice"
|
||||
const val EXTRA_ROOM_ID = "extra_room_id"
|
||||
const val EXTRA_USER_ID = "extra_user_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_MESSAGE_ID = "extra_message_id"
|
||||
const val EXTRA_ROOM_DETAIL = "extra_room_detail"
|
||||
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_LIVE_TIME_NOW = "extra_live_time_now"
|
||||
const val EXTRA_RESULT_ROULETTE = "extra_result_roulette"
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
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,16 +19,11 @@ 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.curation.AudioContentMainCurationViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.new_content_upload_creator.AudioContentMainNewContentCreatorViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderListViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
|
||||
import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel
|
||||
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.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.theme.AudioContentThemeViewModel
|
||||
import kr.co.vividnext.sodalive.common.ApiBuilder
|
||||
|
@ -82,10 +77,7 @@ 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.pg.CanChargePgViewModel
|
||||
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.CanTempApi
|
||||
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
|
||||
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
|
||||
|
@ -124,7 +116,6 @@ import org.koin.dsl.module
|
|||
import retrofit2.Retrofit
|
||||
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class AppDI(private val context: Context, isDebugMode: Boolean) {
|
||||
private val baseUrl = BuildConfig.BASE_URL
|
||||
|
@ -147,9 +138,6 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
OkHttpClient().newBuilder()
|
||||
.addInterceptor(logging)
|
||||
.authenticator(TokenAuthenticator(get()))
|
||||
.connectTimeout(60, TimeUnit.SECONDS)
|
||||
.readTimeout(60, TimeUnit.SECONDS)
|
||||
.writeTimeout(60, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
@ -163,14 +151,12 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
}
|
||||
|
||||
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(), UserApi::class.java) }
|
||||
single { ApiBuilder().build(get(), MenuApi::class.java) }
|
||||
single { ApiBuilder().build(get(), LiveApi::class.java) }
|
||||
single { ApiBuilder().build(get(), TermsApi::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(), LiveRecommendApi::class.java) }
|
||||
single { ApiBuilder().build(get(), ExplorerApi::class.java) }
|
||||
|
@ -195,7 +181,6 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { CanStatusViewModel(get()) }
|
||||
viewModel { CanChargePgViewModel(get()) }
|
||||
viewModel { CanPaymentViewModel(get()) }
|
||||
viewModel { CanPaymentTempViewModel(get()) }
|
||||
viewModel { LiveRoomDetailViewModel(get()) }
|
||||
viewModel { LiveRoomCreateViewModel(get()) }
|
||||
viewModel { LiveTagViewModel(get()) }
|
||||
|
@ -210,14 +195,11 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { VoiceMessageViewModel(get()) }
|
||||
viewModel { VoiceMessageWriteViewModel(get()) }
|
||||
viewModel { SelectMessageRecipientViewModel(get(), get()) }
|
||||
viewModel { SignOutViewModel(get()) }
|
||||
viewModel { NoticeViewModel(get()) }
|
||||
viewModel { EventViewModel(get()) }
|
||||
viewModel { NotificationSettingsViewModel(get()) }
|
||||
viewModel { SettingsViewModel(get()) }
|
||||
viewModel { SeriesDetailViewModel(get(), get()) }
|
||||
viewModel { SeriesListAllViewModel(get()) }
|
||||
viewModel { SeriesContentAllViewModel(get()) }
|
||||
viewModel { SignOutViewModel(get()) }
|
||||
viewModel { TextMessageDetailViewModel(get()) }
|
||||
viewModel { LiveReservationStatusViewModel(get()) }
|
||||
viewModel { AudioContentMainBannerViewModel(get()) }
|
||||
|
@ -225,7 +207,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
viewModel { AudioContentMainCurationViewModel(get()) }
|
||||
viewModel { AudioContentMainOrderListViewModel(get()) }
|
||||
viewModel { AudioContentMainNewContentViewModel(get()) }
|
||||
viewModel { AudioContentMainRecommendSeriesViewModel(get()) }
|
||||
viewModel { AudioContentMainNewContentCreatorViewModel(get()) }
|
||||
viewModel { AudioContentViewModel(get()) }
|
||||
viewModel { AudioContentOrderListViewModel(get()) }
|
||||
viewModel { AudioContentUploadViewModel(get()) }
|
||||
|
@ -256,13 +238,11 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||
private val repositoryModule = module {
|
||||
factory { UserRepository(get()) }
|
||||
factory { TermsRepository(get()) }
|
||||
factory { SeriesRepository(get()) }
|
||||
factory { LiveRepository(get(), get(), get()) }
|
||||
factory { EventRepository(get()) }
|
||||
factory { LiveRecommendRepository(get()) }
|
||||
factory { AuthRepository(get()) }
|
||||
factory { CanRepository(get()) }
|
||||
factory { CanPaymentTempRepository(get()) }
|
||||
factory { LiveTagRepository(get()) }
|
||||
factory { ReportRepository(get()) }
|
||||
factory { ExplorerRepository(get()) }
|
||||
|
|
|
@ -121,11 +121,7 @@ class ExplorerAdapter(
|
|||
)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
if (item.creators.isNotEmpty()) {
|
||||
holder.bind(items[position])
|
||||
}
|
||||
holder.bind(items[position])
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package kr.co.vividnext.sodalive.explorer.profile
|
||||
|
||||
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
|
||||
|
||||
data class GetCreatorProfileResponse(
|
||||
|
@ -21,8 +20,6 @@ data class GetCreatorProfileResponse(
|
|||
val cheers: GetCheersResponse,
|
||||
@SerializedName("activitySummary")
|
||||
val activitySummary: GetCreatorActivitySummary,
|
||||
@SerializedName("seriesList")
|
||||
val seriesList: List<GetSeriesListResponse.SeriesListItem>,
|
||||
@SerializedName("isBlock")
|
||||
val isBlock: Boolean
|
||||
)
|
||||
|
|
|
@ -26,10 +26,6 @@ import kr.co.vividnext.sodalive.R
|
|||
import kr.co.vividnext.sodalive.audio_content.AudioContentActivity
|
||||
import kr.co.vividnext.sodalive.audio_content.AudioContentAdapter
|
||||
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.base.BaseActivity
|
||||
import kr.co.vividnext.sodalive.base.SodaDialog
|
||||
|
@ -46,7 +42,6 @@ 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.fantalk.UserProfileFantalkAllViewActivity
|
||||
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.loadUrl
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
|
@ -75,7 +70,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
private lateinit var loadingDialog: LoadingDialog
|
||||
private lateinit var liveAdapter: UserProfileLiveAdapter
|
||||
private lateinit var audioContentAdapter: AudioContentAdapter
|
||||
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
||||
private lateinit var donationAdapter: UserProfileDonationAdapter
|
||||
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
||||
|
||||
|
@ -123,7 +117,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
setupLiveView()
|
||||
setupDonationView()
|
||||
setupFanTalkView()
|
||||
setupSeriesListView()
|
||||
setupAudioContentListView()
|
||||
setupCreatorCommunityView()
|
||||
}
|
||||
|
@ -422,65 +415,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
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() {
|
||||
binding.layoutUserProfileAudioContent.tvAll.setOnClickListener {
|
||||
val intent = Intent(applicationContext, AudioContentActivity::class.java)
|
||||
|
@ -583,7 +517,6 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||
|
||||
viewModel.creatorProfileLiveData.observe(this) {
|
||||
setCheers(it.cheers)
|
||||
setSeriesList(it.seriesList)
|
||||
setCreatorProfile(it.creator)
|
||||
setAudioContentList(it.contentList)
|
||||
setLiveRoomList(it.liveRoomList)
|
||||
|
@ -617,19 +550,6 @@ 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")
|
||||
private fun setCreatorProfile(creator: CreatorResponse) {
|
||||
val layoutUserProfile = binding.layoutUserProfile
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
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,7 +21,6 @@ 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.LiveRoomDonationMessage
|
||||
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.kick_out.LiveRoomKickOutRequest
|
||||
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
||||
|
@ -157,11 +156,11 @@ interface LiveApi {
|
|||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@POST("/live/room/donation/v2")
|
||||
@POST("/live/room/donation")
|
||||
fun donation(
|
||||
@Body request: LiveRoomDonationRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<LiveRoomDonationResponse>>
|
||||
): Single<ApiResponse<String>>
|
||||
|
||||
@POST("/live/room/donation/refund/{id}")
|
||||
fun refundDonation(
|
||||
|
|
|
@ -129,6 +129,8 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
val intent = Intent(requireContext(), LiveRoomCreateActivity::class.java)
|
||||
activityResultLauncher.launch(intent)
|
||||
}
|
||||
|
||||
binding.swipeRefreshLayout.setOnRefreshListener { refreshSummary() }
|
||||
}
|
||||
|
||||
private fun refreshSummary() {
|
||||
|
@ -138,6 +140,8 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
|
||||
message = "라이브를 불러오고 있습니다."
|
||||
viewModel.getSummary()
|
||||
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
|
@ -180,7 +184,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
.setIndicatorVisibility(View.GONE)
|
||||
.setIndicatorSliderColor(
|
||||
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
||||
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
|
||||
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
|
||||
)
|
||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||
.setIndicatorHeight(4f.dpToPx().toInt())
|
||||
|
@ -283,11 +287,6 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
startActivity(Intent(requireContext(), LiveNowAllActivity::class.java))
|
||||
}
|
||||
|
||||
binding
|
||||
.layoutLiveNow
|
||||
.llRefresh
|
||||
.setOnClickListener { refreshSummary() }
|
||||
|
||||
val recyclerView = binding
|
||||
.layoutLiveNow
|
||||
.rvSudaNow
|
||||
|
@ -487,7 +486,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
|
|||
.setIndicatorVisibility(View.GONE)
|
||||
.setIndicatorSliderColor(
|
||||
ContextCompat.getColor(requireContext(), R.color.color_909090),
|
||||
ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
|
||||
ContextCompat.getColor(requireContext(), R.color.color_9970ff)
|
||||
)
|
||||
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
|
||||
.setIndicatorHeight(4f.dpToPx().toInt())
|
||||
|
|
|
@ -14,7 +14,6 @@ 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.donation.DeleteLiveRoomDonationMessage
|
||||
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.menu.MenuApi
|
||||
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
|
||||
|
@ -164,7 +163,7 @@ class LiveRepository(
|
|||
can: Int,
|
||||
message: String,
|
||||
token: String
|
||||
): Single<ApiResponse<LiveRoomDonationResponse>> {
|
||||
): Single<ApiResponse<String>> {
|
||||
return api.donation(
|
||||
request = LiveRoomDonationRequest(
|
||||
roomId = roomId,
|
||||
|
|
|
@ -68,7 +68,6 @@ import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
|||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageDialog
|
||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
|
||||
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.profile.LiveRoomProfileDialog
|
||||
import kr.co.vividnext.sodalive.live.room.profile.LiveRoomProfileListAdapter
|
||||
|
@ -125,16 +124,6 @@ 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 val countDownTimer = object : CountDownTimer(remainingNoChattingTime * 1000, 1000) {
|
||||
|
@ -479,7 +468,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
binding.tvMenuPan.setOnClickListener { viewModel.toggleShowMenuPan() }
|
||||
|
||||
binding.tvBgSwitch.setOnClickListener { viewModel.toggleBackgroundImage() }
|
||||
binding.tvSignatureSwitch.setOnClickListener { viewModel.toggleSignatureImage() }
|
||||
binding.llDonation.setOnClickListener {
|
||||
LiveRoomDonationRankingDialog(
|
||||
activity = this,
|
||||
|
@ -638,31 +626,6 @@ 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) {
|
||||
if (it) {
|
||||
loadingDialog.show(screenWidth)
|
||||
|
@ -728,7 +691,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
copyMessage = {
|
||||
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText(it, it))
|
||||
showToast("후원 히스토리가 복사되었습니다.")
|
||||
showToast("후원 메시지가 복사되었습니다.")
|
||||
}
|
||||
).show()
|
||||
}
|
||||
|
@ -796,6 +759,21 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
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) {
|
||||
binding.llViewUsers.visibility = View.VISIBLE
|
||||
binding.llViewUsers.setOnClickListener { roomProfileDialog.show() }
|
||||
|
@ -950,10 +928,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
viewModel.showRoulette {
|
||||
RoulettePreviewDialog(
|
||||
activity = this,
|
||||
previewList = it,
|
||||
onClickSpin = { rouletteId ->
|
||||
spinRoulette(rouletteId = rouletteId)
|
||||
},
|
||||
preview = it,
|
||||
onClickSpin = { spinRoulette() },
|
||||
layoutInflater = layoutInflater
|
||||
).show()
|
||||
}
|
||||
|
@ -1294,14 +1270,13 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
private fun donation(can: Int, message: String) {
|
||||
val rawMessage = "${can}캔을 후원하셨습니다.\uD83D\uDCB0\uD83E\uDE99"
|
||||
|
||||
viewModel.donation(roomId, can, message) { signature ->
|
||||
viewModel.donation(roomId, can, message) { signatureImage ->
|
||||
val donationRawMessage = Gson().toJson(
|
||||
LiveRoomChatRawMessage(
|
||||
type = LiveRoomChatRawMessageType.DONATION,
|
||||
message = rawMessage,
|
||||
can = can,
|
||||
signature = signature,
|
||||
signatureImageUrl = signature?.imageUrl,
|
||||
signatureImageUrl = signatureImage,
|
||||
donationMessage = message
|
||||
)
|
||||
)
|
||||
|
@ -1325,7 +1300,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
)
|
||||
invalidateChat()
|
||||
viewModel.addDonationCan(can)
|
||||
addSignature(signature)
|
||||
addSignatureImage(signatureImage)
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
|
@ -1335,12 +1310,12 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
}
|
||||
}
|
||||
|
||||
private fun spinRoulette(rouletteId: Long) {
|
||||
viewModel.spinRoulette(roomId = roomId, rouletteId = rouletteId) { can, items, randomItem ->
|
||||
private fun spinRoulette() {
|
||||
viewModel.spinRoulette(roomId = roomId) { can, items, randomlySelectedItem ->
|
||||
val rouletteRawMessage = Gson().toJson(
|
||||
LiveRoomChatRawMessage(
|
||||
type = LiveRoomChatRawMessageType.ROULETTE_DONATION,
|
||||
message = randomItem,
|
||||
message = randomlySelectedItem,
|
||||
can = can,
|
||||
donationMessage = "",
|
||||
)
|
||||
|
@ -1349,7 +1324,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
RouletteSpinDialog(
|
||||
activity = this@LiveRoomActivity,
|
||||
items = items,
|
||||
selectedItem = randomItem,
|
||||
selectedItem = randomlySelectedItem,
|
||||
layoutInflater = layoutInflater
|
||||
) {
|
||||
agora.sendRawMessageToGroup(
|
||||
|
@ -1360,7 +1335,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
LiveRoomRouletteDonationChat(
|
||||
profileUrl = SharedPreferenceManager.profileImage,
|
||||
nickname = SharedPreferenceManager.nickname,
|
||||
rouletteResult = randomItem
|
||||
rouletteResult = randomlySelectedItem
|
||||
)
|
||||
)
|
||||
invalidateChat()
|
||||
|
@ -1432,12 +1407,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
)
|
||||
invalidateChat()
|
||||
viewModel.addDonationCan(rawMessage.can)
|
||||
|
||||
if (rawMessage.signature != null) {
|
||||
addSignature(rawMessage.signature)
|
||||
} else if (rawMessage.signatureImageUrl != null) {
|
||||
addSignatureImage(rawMessage.signatureImageUrl)
|
||||
}
|
||||
addSignatureImage(
|
||||
imageUrl = rawMessage.signatureImageUrl ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1790,47 +1762,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
|
|||
}
|
||||
}
|
||||
|
||||
private fun addSignature(signature: LiveRoomDonationResponse?) {
|
||||
if (signature != null) {
|
||||
if (!isShowSignatureImage) {
|
||||
this.signature = signature
|
||||
isShowSignatureImage = true
|
||||
} else {
|
||||
signatureList.add(signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSignatureImage() {
|
||||
if (signature != null) {
|
||||
if (viewModel.isSignatureOn.value!!) {
|
||||
Glide
|
||||
.with(this)
|
||||
.load(signature!!.imageUrl)
|
||||
.into(binding.ivSignature)
|
||||
if (signatureImageUrl.isNotBlank()) {
|
||||
Glide
|
||||
.with(this)
|
||||
.load(signatureImageUrl)
|
||||
.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
|
||||
}
|
||||
binding.ivSignature.visibility = View.VISIBLE
|
||||
handler.postDelayed({
|
||||
if (signatureImageUrlList.isNotEmpty()) {
|
||||
signatureImageUrl = signatureImageUrlList.removeAt(0)
|
||||
|
|
|
@ -3,6 +3,12 @@ package kr.co.vividnext.sodalive.live.room
|
|||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
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.orhanobut.logger.Logger
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
|
@ -11,7 +17,6 @@ import kr.co.vividnext.sodalive.base.BaseViewModel
|
|||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.live.LiveRepository
|
||||
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.menu.GetMenuPresetResponse
|
||||
import kr.co.vividnext.sodalive.live.room.profile.GetLiveRoomUserProfileResponse
|
||||
|
@ -30,7 +35,7 @@ import okhttp3.MultipartBody
|
|||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import kotlin.math.floor
|
||||
|
||||
class LiveRoomViewModel(
|
||||
private val repository: LiveRepository,
|
||||
|
@ -78,10 +83,6 @@ class LiveRoomViewModel(
|
|||
val isBgOn: LiveData<Boolean>
|
||||
get() = _isBgOn
|
||||
|
||||
private var _isSignatureOn = MutableLiveData(true)
|
||||
val isSignatureOn: LiveData<Boolean>
|
||||
get() = _isSignatureOn
|
||||
|
||||
lateinit var getRealPathFromURI: (Uri) -> String?
|
||||
|
||||
fun getUserNickname(memberId: Int): String {
|
||||
|
@ -247,6 +248,43 @@ 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) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
|
@ -340,10 +378,6 @@ class LiveRoomViewModel(
|
|||
_isBgOn.value = !isBgOn.value!!
|
||||
}
|
||||
|
||||
fun toggleSignatureImage() {
|
||||
_isSignatureOn.value = !isSignatureOn.value!!
|
||||
}
|
||||
|
||||
fun editLiveRoomInfo(
|
||||
roomId: Long,
|
||||
newTitle: String,
|
||||
|
@ -474,12 +508,7 @@ class LiveRoomViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun donation(
|
||||
roomId: Long,
|
||||
can: Int,
|
||||
message: String,
|
||||
onSuccess: (LiveRoomDonationResponse?) -> Unit
|
||||
) {
|
||||
fun donation(roomId: Long, can: Int, message: String, onSuccess: (String) -> Unit) {
|
||||
_isLoading.postValue(true)
|
||||
compositeDisposable.add(
|
||||
repository.donation(roomId, can, message, "Bearer ${SharedPreferenceManager.token}")
|
||||
|
@ -490,7 +519,7 @@ class LiveRoomViewModel(
|
|||
_isLoading.value = false
|
||||
if (it.success) {
|
||||
SharedPreferenceManager.can -= can
|
||||
onSuccess(it.data)
|
||||
onSuccess(it.data ?: "")
|
||||
} else {
|
||||
if (it.message != null) {
|
||||
_toastLiveData.postValue(it.message)
|
||||
|
@ -779,7 +808,7 @@ class LiveRoomViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
fun showRoulette(complete: (List<RoulettePreview>) -> Unit) {
|
||||
fun showRoulette(complete: (RoulettePreview) -> Unit) {
|
||||
if (!_isLoading.value!!) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
|
@ -796,19 +825,15 @@ class LiveRoomViewModel(
|
|||
val data = it.data
|
||||
if (
|
||||
it.success &&
|
||||
!data.isNullOrEmpty()
|
||||
data != null &&
|
||||
data.isActive &&
|
||||
data.items.isNotEmpty()
|
||||
) {
|
||||
complete(
|
||||
data
|
||||
.filter { roulette -> roulette.isActive }
|
||||
.filter { roulette -> roulette.items.isNotEmpty() }
|
||||
.map { roulette ->
|
||||
RoulettePreview(
|
||||
id = roulette.id,
|
||||
can = roulette.can,
|
||||
items = calculatePercentages(roulette.items)
|
||||
)
|
||||
}
|
||||
RoulettePreview(
|
||||
data.can,
|
||||
items = calculatePercentages(data.items)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||
|
@ -825,16 +850,12 @@ class LiveRoomViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun spinRoulette(
|
||||
roomId: Long,
|
||||
rouletteId: Long,
|
||||
complete: (Int, List<RouletteItem>, String) -> Unit
|
||||
) {
|
||||
fun spinRoulette(roomId: Long, complete: (Int, List<RouletteItem>, String) -> Unit) {
|
||||
if (!_isLoading.value!!) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
rouletteRepository.spinRoulette(
|
||||
request = SpinRouletteRequest(roomId = roomId, rouletteId = rouletteId),
|
||||
request = SpinRouletteRequest(roomId = roomId),
|
||||
token = "Bearer ${SharedPreferenceManager.token}"
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
@ -847,10 +868,11 @@ class LiveRoomViewModel(
|
|||
if (
|
||||
it.success &&
|
||||
data != null &&
|
||||
data.isActive &&
|
||||
data.items.isNotEmpty()
|
||||
) {
|
||||
SharedPreferenceManager.can -= data.can
|
||||
complete(data.can, data.items, data.result)
|
||||
randomSelectRouletteItem(data.can, data.items, complete)
|
||||
} else {
|
||||
val message = it.message ?: "룰렛을 사용할 수 없습니다. 다시 시도해 주세요."
|
||||
_toastLiveData.postValue(message)
|
||||
|
@ -939,11 +961,31 @@ 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> {
|
||||
val updatedOptions = options.map { option ->
|
||||
val totalWeight = options.sumOf { it.weight }
|
||||
val updatedOptions = options.asSequence().map { option ->
|
||||
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
||||
RoulettePreviewItem(
|
||||
title = option.title,
|
||||
percent = "${String.format(Locale.KOREAN, "%.2f", option.percentage)}%"
|
||||
percent = "${String.format("%.2f", percent)}%"
|
||||
)
|
||||
}.toList()
|
||||
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package kr.co.vividnext.sodalive.live.room.chat
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse
|
||||
|
||||
data class LiveRoomChatRawMessage(
|
||||
@SerializedName("type") val type: LiveRoomChatRawMessageType,
|
||||
@SerializedName("message") val message: String,
|
||||
@SerializedName("can") val can: Int,
|
||||
@SerializedName("signature") val signature: LiveRoomDonationResponse? = null,
|
||||
@SerializedName("signatureImageUrl") val signatureImageUrl: String? = null,
|
||||
@SerializedName("donationMessage") val donationMessage: String?,
|
||||
@SerializedName("isActiveRoulette") val isActiveRoulette: Boolean? = null
|
||||
|
|
|
@ -17,6 +17,5 @@ data class CreateLiveRoomRequest(
|
|||
@SerializedName("password") val password: String? = null,
|
||||
@SerializedName("menuPanId") val menuPanId: Long = 0,
|
||||
@SerializedName("menuPan") val menuPan: String = "",
|
||||
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean = false,
|
||||
@SerializedName("isAvailableJoinCreator") val isAvailableJoinCreator: Boolean = true
|
||||
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean = false
|
||||
)
|
||||
|
|
|
@ -322,14 +322,6 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
binding.llSelectMenu3.setOnClickListener {
|
||||
viewModel.selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
|
||||
}
|
||||
|
||||
binding.llAvailableJoinCreatorY.setOnClickListener {
|
||||
viewModel.setAvailableJoinCreator(true)
|
||||
}
|
||||
|
||||
binding.llAvailableJoinCreatorN.setOnClickListener {
|
||||
viewModel.setAvailableJoinCreator(false)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
|
@ -655,46 +647,6 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
|
|||
viewModel.menuLiveData.observe(this) {
|
||||
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,10 +71,6 @@ class LiveRoomCreateViewModel(
|
|||
val isActivateMenuLiveData: LiveData<Boolean>
|
||||
get() = _isActivateMenuLiveData
|
||||
|
||||
private val _isAvailableJoinCreatorLiveData = MutableLiveData(true)
|
||||
val isAvailableJoinCreatorLiveData: LiveData<Boolean>
|
||||
get() = _isAvailableJoinCreatorLiveData
|
||||
|
||||
private val _menuLiveData = MutableLiveData("")
|
||||
val menuLiveData: LiveData<String>
|
||||
get() = _menuLiveData
|
||||
|
@ -151,8 +147,7 @@ class LiveRoomCreateViewModel(
|
|||
} else {
|
||||
""
|
||||
},
|
||||
isActiveMenuPan = _isActivateMenuLiveData.value!!,
|
||||
isAvailableJoinCreator = _isAvailableJoinCreatorLiveData.value!!
|
||||
isActiveMenuPan = _isActivateMenuLiveData.value!!
|
||||
)
|
||||
|
||||
val requestJson = Gson().toJson(request)
|
||||
|
@ -260,10 +255,6 @@ class LiveRoomCreateViewModel(
|
|||
_isAdultLiveData.value = isAdult
|
||||
}
|
||||
|
||||
fun setAvailableJoinCreator(isAvailableJoinCreator: Boolean) {
|
||||
_isAvailableJoinCreatorLiveData.value = isAvailableJoinCreator
|
||||
}
|
||||
|
||||
fun getRecentInfo(onSuccess: (GetRecentRoomInfoResponse) -> Unit) {
|
||||
_isLoading.value = true
|
||||
compositeDisposable.add(
|
||||
|
|
|
@ -111,14 +111,6 @@ class LiveRoomDonationDialog(
|
|||
intent.putExtra(Constants.EXTRA_GO_TO_PREV_PAGE, true)
|
||||
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")
|
||||
|
|
|
@ -2,11 +2,9 @@ package kr.co.vividnext.sodalive.live.room.donation
|
|||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.databinding.ItemLiveRoomDonationMessageBinding
|
||||
|
||||
class LiveRoomDonationMessageAdapter(
|
||||
|
@ -22,16 +20,8 @@ class LiveRoomDonationMessageAdapter(
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(item: LiveRoomDonationMessage) {
|
||||
if (item.canMessage.isNotBlank()) {
|
||||
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.tvNickname.text = "${item.nickname}님이"
|
||||
binding.tvCanMessage.text = item.canMessage
|
||||
binding.tvDonationMessage.text = "\"${item.donationMessage}\""
|
||||
binding.ivDelete.setOnClickListener { onClickDeleteMessage(item.uuid) }
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
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) {
|
||||
if (selectedTags.contains(item.tag)) {
|
||||
binding.ivTagChecked.visibility = View.VISIBLE
|
||||
binding.tvTag.setTextColor(ContextCompat.getColor(context, R.color.color_3bb9f1))
|
||||
binding.tvTag.setTextColor(ContextCompat.getColor(context, R.color.color_9970ff))
|
||||
isChecked = true
|
||||
} else {
|
||||
binding.ivTagChecked.visibility = View.GONE
|
||||
|
@ -50,7 +50,7 @@ class LiveTagAdapter(
|
|||
binding.tvTag.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.color_3bb9f1
|
||||
R.color.color_9970ff
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -3,7 +3,6 @@ package kr.co.vividnext.sodalive.live.roulette
|
|||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class GetRouletteResponse(
|
||||
@SerializedName("id") val id: Long,
|
||||
@SerializedName("can") val can: Int,
|
||||
@SerializedName("isActive") val isActive: Boolean,
|
||||
@SerializedName("items") val items: List<RouletteItem>
|
||||
|
@ -11,5 +10,5 @@ data class GetRouletteResponse(
|
|||
|
||||
data class RouletteItem(
|
||||
@SerializedName("title") val title: String,
|
||||
@SerializedName("percentage") val percentage: Float
|
||||
@SerializedName("weight") val weight: Int
|
||||
)
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
package kr.co.vividnext.sodalive.live.roulette
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RoulettePreview(
|
||||
@SerializedName("id") val id: Long,
|
||||
@SerializedName("can") val can: Int,
|
||||
@SerializedName("items") val items: List<RoulettePreviewItem>
|
||||
val can: Int,
|
||||
val items: List<RoulettePreviewItem>
|
||||
)
|
||||
|
||||
data class RoulettePreviewItem(
|
||||
@SerializedName("title") val title: String,
|
||||
@SerializedName("percent") val percent: String
|
||||
val title: String,
|
||||
val percent: String
|
||||
)
|
||||
|
|
|
@ -8,36 +8,27 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import kr.co.vividnext.sodalive.R
|
||||
import kr.co.vividnext.sodalive.common.Constants
|
||||
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||
import kr.co.vividnext.sodalive.databinding.DialogRoulettePreviewBinding
|
||||
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||
import kr.co.vividnext.sodalive.extensions.moneyFormat
|
||||
import kr.co.vividnext.sodalive.live.roulette.config.RouletteSettingsViewModel.SelectedRoulette
|
||||
import kr.co.vividnext.sodalive.mypage.can.charge.CanChargeActivity
|
||||
|
||||
class RoulettePreviewDialog(
|
||||
private val activity: FragmentActivity,
|
||||
private val previewList: List<RoulettePreview>,
|
||||
private val preview: RoulettePreview,
|
||||
private val title: String = "",
|
||||
private val onClickSpin: ((Long) -> Unit)? = null,
|
||||
private val onClickSpin: (() -> Unit)? = null,
|
||||
layoutInflater: LayoutInflater
|
||||
) {
|
||||
private val alertDialog: AlertDialog
|
||||
private val dialogView = DialogRoulettePreviewBinding.inflate(layoutInflater)
|
||||
|
||||
private val selectedRouletteLiveData = MutableLiveData(
|
||||
SelectedRoulette.ROULETTE_1
|
||||
)
|
||||
|
||||
init {
|
||||
val dialogBuilder = AlertDialog.Builder(activity)
|
||||
dialogBuilder.setView(dialogView.root)
|
||||
|
@ -63,189 +54,18 @@ class RoulettePreviewDialog(
|
|||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun setupView() {
|
||||
if (previewList.isEmpty()) {
|
||||
alertDialog.dismiss()
|
||||
} else {
|
||||
initSelectRouletteButton()
|
||||
setRouletteData(previewList[0])
|
||||
}
|
||||
|
||||
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.text = "${preview.can}캔으로 룰렛 돌리기"
|
||||
dialogView.tvSpinRoulette.setOnClickListener {
|
||||
if (onClickSpin != null) {
|
||||
onClickSpin!!(roulettePreview.id)
|
||||
onClickSpin!!()
|
||||
}
|
||||
|
||||
alertDialog.dismiss()
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
dialogView.tvTitle.text = title.ifBlank { "룰렛" }
|
||||
if (onClickSpin != null) {
|
||||
dialogView.tvCan.visibility = View.VISIBLE
|
||||
dialogView.tvCan.text = SharedPreferenceManager.can.moneyFormat()
|
||||
|
@ -260,8 +80,7 @@ class RoulettePreviewDialog(
|
|||
dialogView.tvCan.visibility = View.GONE
|
||||
}
|
||||
|
||||
dialogView.llRouletteOptionContainer.removeAllViews()
|
||||
roulettePreview.items.forEachIndexed { index, item ->
|
||||
preview.items.forEachIndexed { index, item ->
|
||||
dialogView.llRouletteOptionContainer.addView(createOptionView(index, item))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,10 +74,12 @@ class RouletteView @JvmOverloads constructor(
|
|||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
|
||||
val totalWeight = items.asSequence().map { it.weight }.sum()
|
||||
var startAngle = -90f
|
||||
|
||||
val shuffledColors = colors.shuffled()
|
||||
items.forEachIndexed { index, (option, percentage) ->
|
||||
val sweepAngle = (percentage / 100) * 360f
|
||||
items.forEachIndexed { index, (option, weight) ->
|
||||
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
||||
fillPaint.color = shuffledColors[index]
|
||||
canvas.drawArc(rect, startAngle, sweepAngle, true, fillPaint)
|
||||
|
||||
|
@ -115,10 +117,11 @@ class RouletteView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun getAngleForOption(option: String): Float {
|
||||
val totalWeight = items.asSequence().map { it.weight }.sum()
|
||||
var startAngle = 0f
|
||||
|
||||
items.forEach { (currentOption, percentage) ->
|
||||
val sweepAngle = (percentage / 100) * 360f
|
||||
items.forEach { (currentOption, weight) ->
|
||||
val sweepAngle = (weight / totalWeight.toFloat()) * 360f
|
||||
if (currentOption == option) {
|
||||
// Return the midpoint angle of the segment
|
||||
return (startAngle + sweepAngle / 2)
|
||||
|
|
|
@ -4,6 +4,5 @@ import com.google.gson.annotations.SerializedName
|
|||
|
||||
data class SpinRouletteRequest(
|
||||
@SerializedName("roomId") val roomId: Long,
|
||||
@SerializedName("rouletteId") val rouletteId: Long,
|
||||
@SerializedName("container") val container: String = "aos"
|
||||
)
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
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,7 +5,6 @@ import kr.co.vividnext.sodalive.common.ApiResponse
|
|||
import kr.co.vividnext.sodalive.live.roulette.GetNewRouletteResponse
|
||||
import kr.co.vividnext.sodalive.live.roulette.GetRouletteResponse
|
||||
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteRequest
|
||||
import kr.co.vividnext.sodalive.live.roulette.SpinRouletteResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
|
@ -15,37 +14,37 @@ import retrofit2.http.Path
|
|||
import retrofit2.http.Query
|
||||
|
||||
interface RouletteApi {
|
||||
@POST("/v2/roulette")
|
||||
@POST("/new-roulette")
|
||||
fun createRoulette(
|
||||
@Body request: CreateRouletteRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@PUT("/v2/roulette")
|
||||
@PUT("/new-roulette")
|
||||
fun updateRoulette(
|
||||
@Body request: UpdateRouletteRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<Any>>
|
||||
|
||||
@GET("/v2/roulette/creator")
|
||||
@GET("/new-roulette/creator")
|
||||
fun getAllRoulette(
|
||||
@Query("creatorId") creatorId: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetNewRouletteResponse>>>
|
||||
|
||||
@GET("/v2/roulette")
|
||||
@GET("/new-roulette")
|
||||
fun getRoulette(
|
||||
@Query("creatorId") creatorId: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<List<GetRouletteResponse>>>
|
||||
): Single<ApiResponse<GetRouletteResponse>>
|
||||
|
||||
@POST("/v2/roulette/spin")
|
||||
@POST("/new-roulette/spin")
|
||||
fun spinRoulette(
|
||||
@Body request: SpinRouletteRequest,
|
||||
@Header("Authorization") authHeader: String
|
||||
): Single<ApiResponse<SpinRouletteResponse>>
|
||||
): Single<ApiResponse<GetRouletteResponse>>
|
||||
|
||||
@POST("/v2/roulette/refund/{id}")
|
||||
@POST("/new-roulette/refund/{id}")
|
||||
fun refundRouletteDonation(
|
||||
@Path("id") id: Long,
|
||||
@Header("Authorization") authHeader: String
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package kr.co.vividnext.sodalive.live.roulette.config
|
||||
|
||||
data class RouletteOption(var title: String, var percentage: String = "")
|
||||
data class RouletteOption(var title: String, var weight: Int, var percentage: String = "50.00")
|
||||
|
|
|
@ -26,7 +26,6 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
|
|||
import kr.co.vividnext.sodalive.databinding.FragmentRouletteSettingsBinding
|
||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewDialog
|
||||
import org.koin.android.ext.android.inject
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
||||
|
@ -104,7 +103,6 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun bindData() {
|
||||
viewModel.selectedRouletteLiveData.observe(viewLifecycleOwner) {
|
||||
deselectAllRoulette()
|
||||
|
@ -158,22 +156,12 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
viewModel.roulettePreviewLiveData.observe(viewLifecycleOwner) {
|
||||
RoulettePreviewDialog(
|
||||
activity = requireActivity(),
|
||||
previewList = listOf(it),
|
||||
preview = it,
|
||||
title = "룰렛 미리보기",
|
||||
layoutInflater = layoutInflater
|
||||
).show()
|
||||
}
|
||||
|
||||
viewModel.totalPercentageLiveData.observe(viewLifecycleOwner) {
|
||||
binding.tvTotalPercentage.text = "( ${
|
||||
String.format(
|
||||
Locale.KOREAN,
|
||||
"%.2f%%",
|
||||
it
|
||||
)
|
||||
} )"
|
||||
}
|
||||
|
||||
compositeDisposable.add(
|
||||
binding.etSetPrice.textChanges().skip(1)
|
||||
.debounce(100, TimeUnit.MILLISECONDS)
|
||||
|
@ -188,7 +176,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
}
|
||||
|
||||
private fun addOption() {
|
||||
val newOption = RouletteOption("", "")
|
||||
val newOption = RouletteOption("", 1)
|
||||
viewModel.addOption(newOption)
|
||||
}
|
||||
|
||||
|
@ -211,21 +199,16 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
|
||||
val etOption = optionView.findViewById<EditText>(R.id.et_option)
|
||||
val tvOptionTitle = optionView.findViewById<TextView>(R.id.tv_option_title)
|
||||
val etPercentage = optionView.findViewById<EditText>(R.id.et_option_percentage)
|
||||
val tvPercentage = optionView.findViewById<TextView>(R.id.tv_option_percentage)
|
||||
val ivMinus = optionView.findViewById<ImageView>(R.id.iv_minus)
|
||||
val ivPlus = optionView.findViewById<ImageView>(R.id.iv_plus)
|
||||
val tvDelete = optionView.findViewById<TextView>(R.id.tv_delete)
|
||||
|
||||
etOption.setText(option.title)
|
||||
tvOptionTitle.text = "옵션 ${index + 1}"
|
||||
|
||||
try {
|
||||
if (option.percentage.toFloat() > 0f) {
|
||||
etPercentage.setText(option.percentage)
|
||||
} else {
|
||||
etPercentage.setText("")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
etPercentage.setText("")
|
||||
}
|
||||
tvPercentage.text = "${option.percentage}%"
|
||||
ivMinus.setOnClickListener { viewModel.subtractWeight(index) }
|
||||
ivPlus.setOnClickListener { viewModel.plusWeight(index) }
|
||||
|
||||
if (index == 0 || index == 1) {
|
||||
tvDelete.visibility = View.GONE
|
||||
|
@ -244,16 +227,6 @@ 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
|
||||
}
|
||||
|
||||
|
@ -275,7 +248,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
binding.tvSelectRoulette2.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_ffcb14
|
||||
R.color.color_3bb9f1
|
||||
)
|
||||
)
|
||||
} else {
|
||||
|
@ -283,7 +256,7 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
binding.tvSelectRoulette2.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
R.color.color_ff14d9
|
||||
R.color.color_555555
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -313,20 +286,11 @@ class RouletteSettingsFragment : BaseFragment<FragmentRouletteSettingsBinding>(
|
|||
tvSelectRoulette: TextView
|
||||
) {
|
||||
ivSelectRoulette.visibility = View.VISIBLE
|
||||
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
|
||||
}
|
||||
)
|
||||
llSelectRoulette.setBackgroundResource(R.drawable.bg_round_corner_6_7_3bb9f1)
|
||||
tvSelectRoulette.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
when (viewModel.selectedRouletteLiveData.value) {
|
||||
RouletteSettingsViewModel.SelectedRoulette.ROULETTE_2 -> R.color.black
|
||||
else -> R.color.color_eeeeee
|
||||
}
|
||||
R.color.color_eeeeee
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.live.roulette.RouletteItem
|
|||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreview
|
||||
import kr.co.vividnext.sodalive.live.roulette.RoulettePreviewItem
|
||||
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
|
||||
import kotlin.math.floor
|
||||
|
||||
class RouletteSettingsViewModel(private val repository: RouletteRepository) : BaseViewModel() {
|
||||
|
||||
|
@ -47,10 +48,6 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
val selectedRouletteLiveData: LiveData<SelectedRoulette>
|
||||
get() = _selectedRouletteLiveData
|
||||
|
||||
private val _totalPercentageLiveData = MutableLiveData(0f)
|
||||
val totalPercentageLiveData: LiveData<Float>
|
||||
get() = _totalPercentageLiveData
|
||||
|
||||
var can = 0
|
||||
var isActive = false
|
||||
private var rouletteId = 0L
|
||||
|
@ -58,17 +55,31 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
|
||||
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) {
|
||||
if (options.size >= 10) return
|
||||
|
||||
options.add(newOption)
|
||||
_optionsLiveData.value = options
|
||||
calculateTotalPercentage()
|
||||
recalculatePercentages(options)
|
||||
}
|
||||
|
||||
fun deleteOption(index: Int) {
|
||||
val updatedOptions = options.filterIndexed { currentIndex, _ -> currentIndex != index }
|
||||
removeAllAndAddOptions(updatedOptions)
|
||||
_optionsLiveData.value = updatedOptions
|
||||
recalculatePercentages(updatedOptions)
|
||||
}
|
||||
|
||||
fun inputOption(optionIndex: Int, title: String) {
|
||||
|
@ -76,10 +87,15 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
options[optionIndex] = currentOption.copy(title = title)
|
||||
}
|
||||
|
||||
fun inputOptionPercentage(optionIndex: Int, percentage: String) {
|
||||
val currentOption = options[optionIndex]
|
||||
options[optionIndex] = currentOption.copy(percentage = percentage)
|
||||
calculateTotalPercentage()
|
||||
private fun recalculatePercentages(options: List<RouletteOption>) {
|
||||
val totalWeight = options.sumOf { it.weight }
|
||||
val updatedOptions = options.asSequence().map { option ->
|
||||
val percent = floor(option.weight.toDouble() / totalWeight * 10000) / 100
|
||||
option.copy(percentage = String.format("%.2f", percent))
|
||||
}.toList()
|
||||
|
||||
removeAllAndAddOptions(updatedOptions)
|
||||
_optionsLiveData.value = updatedOptions
|
||||
}
|
||||
|
||||
fun toggleIsActive() {
|
||||
|
@ -91,20 +107,17 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
_isLoading.value = true
|
||||
|
||||
val items = mutableListOf<RoulettePreviewItem>()
|
||||
if (validationOptions()) {
|
||||
for (option in options) {
|
||||
if (option.title.trim().isEmpty()) {
|
||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||
_isLoading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
|
||||
for (option in options) {
|
||||
if (option.title.trim().isEmpty()) {
|
||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||
_isLoading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
_roulettePreviewLiveData.postValue(RoulettePreview(0, can, items))
|
||||
items.add(RoulettePreviewItem(option.title, "${option.percentage}%"))
|
||||
}
|
||||
|
||||
_roulettePreviewLiveData.postValue(RoulettePreview(can, items))
|
||||
_isLoading.value = false
|
||||
}
|
||||
|
||||
|
@ -112,41 +125,24 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
if (!_isLoading.value!!) {
|
||||
_isLoading.value = true
|
||||
|
||||
if (validationOptions()) {
|
||||
if (rouletteId > 0) {
|
||||
updateRoulette(onSuccess)
|
||||
} else {
|
||||
createRoulette(onSuccess)
|
||||
}
|
||||
if (rouletteId > 0) {
|
||||
updateRoulette(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) {
|
||||
val items = mutableListOf<RouletteItem>()
|
||||
for (option in options) {
|
||||
items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat()))
|
||||
if (option.title.trim().isEmpty()) {
|
||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||
_isLoading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
items.add(RouletteItem(title = option.title, weight = option.weight))
|
||||
}
|
||||
|
||||
val selectedRoulette = rouletteList[_selectedRouletteLiveData.value!!.ordinal]
|
||||
|
@ -173,10 +169,24 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
SelectedRoulette.ROULETTE_3 -> "룰렛 3"
|
||||
}
|
||||
|
||||
var isAllActive = false
|
||||
|
||||
rouletteList
|
||||
.filter {
|
||||
it.id != selectedRoulette.id
|
||||
}
|
||||
.forEach {
|
||||
if (it.isActive) {
|
||||
isAllActive = true
|
||||
}
|
||||
}
|
||||
|
||||
val successMessage = if (isActive) {
|
||||
"${selectedRouletteTitle}을 활성화 했습니다."
|
||||
"${selectedRouletteTitle}로 설정하였습니다."
|
||||
} else if (!isAllActive) {
|
||||
"${selectedRouletteTitle}이 비활성화 되었습니다."
|
||||
} else {
|
||||
"${selectedRouletteTitle}을 비활성화 했습니다."
|
||||
"${selectedRouletteTitle}을 설정했습니다."
|
||||
}
|
||||
|
||||
compositeDisposable.add(
|
||||
|
@ -214,7 +224,13 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
private fun createRoulette(onSuccess: (Boolean) -> Unit) {
|
||||
val items = mutableListOf<RouletteItem>()
|
||||
for (option in options) {
|
||||
items.add(RouletteItem(title = option.title, percentage = option.percentage.toFloat()))
|
||||
if (option.title.trim().isEmpty()) {
|
||||
_toastLiveData.value = "옵션은 빈칸을 할 수 없습니다."
|
||||
_isLoading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
items.add(RouletteItem(title = option.title, weight = option.weight))
|
||||
}
|
||||
|
||||
val request = CreateRouletteRequest(
|
||||
|
@ -332,10 +348,10 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
isActive = roulette.isActive
|
||||
|
||||
val options = roulette.items.asSequence().map { item ->
|
||||
RouletteOption(title = item.title, percentage = item.percentage.toString())
|
||||
RouletteOption(title = item.title, weight = item.weight)
|
||||
}.toList()
|
||||
removeAllAndAddOptions(options = options)
|
||||
_optionsLiveData.value = options
|
||||
recalculatePercentages(options)
|
||||
} else {
|
||||
_canLiveData.value = 0
|
||||
_isActiveLiveData.value = false
|
||||
|
@ -345,30 +361,15 @@ class RouletteSettingsViewModel(private val repository: RouletteRepository) : Ba
|
|||
isActive = false
|
||||
|
||||
options.clear()
|
||||
options.add(RouletteOption(title = "", percentage = ""))
|
||||
options.add(RouletteOption(title = "", percentage = ""))
|
||||
_optionsLiveData.value = options
|
||||
options.add(RouletteOption(title = "", weight = 1))
|
||||
options.add(RouletteOption(title = "", weight = 1))
|
||||
recalculatePercentages(options)
|
||||
}
|
||||
|
||||
calculateTotalPercentage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAllAndAddOptions(options: List<RouletteOption>) {
|
||||
this.options.clear()
|
||||
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,6 +10,7 @@ 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.SharedPreferenceManager
|
||||
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.pg.CanChargePgFragment
|
||||
|
@ -41,10 +42,7 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
)
|
||||
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(
|
||||
R.id.fl_container,
|
||||
CanChargePgFragment()
|
||||
).commit()
|
||||
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||
}
|
||||
|
||||
override fun setupView() {
|
||||
|
@ -58,29 +56,33 @@ class CanChargeActivity : BaseActivity<ActivityCanChargeBinding>(
|
|||
}
|
||||
|
||||
private fun setupTabs() {
|
||||
val tabs = binding.tabs
|
||||
if (SharedPreferenceManager.isAuth) {
|
||||
val tabs = binding.tabs
|
||||
|
||||
tabs.visibility = View.VISIBLE
|
||||
tabs.addTab(tabs.newTab().setText("PG"))
|
||||
tabs.addTab(tabs.newTab().setText("인 앱 결제"))
|
||||
tabs.visibility = View.VISIBLE
|
||||
tabs.addTab(tabs.newTab().setText("인 앱 결제"))
|
||||
tabs.addTab(tabs.newTab().setText("PG"))
|
||||
|
||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
when (tab.position) {
|
||||
0 -> supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_container, CanChargePgFragment()).commit()
|
||||
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
when (tab.position) {
|
||||
0 -> supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||
|
||||
1 -> supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_container, CanChargeIapFragment()).commit()
|
||||
1 -> supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_container, CanChargePgFragment()).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) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package kr.co.vividnext.sodalive.mypage.can.charge.iap
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
|
@ -41,6 +42,10 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
|||
|
||||
private lateinit var purchaseUpdateListener: PurchasesUpdatedListener
|
||||
|
||||
fun safeContext(): Context? {
|
||||
return if (isAdded) context else null
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
@ -51,9 +56,29 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
|||
setupBillingClient()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
override fun onStart() {
|
||||
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()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun bindData() {
|
||||
|
@ -146,22 +171,6 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
|||
.build()
|
||||
|
||||
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")
|
||||
|
@ -210,9 +219,7 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
|||
if (purchaseList.isNotEmpty()) {
|
||||
for (purchase in purchaseList) {
|
||||
if (!purchase.isAcknowledged) {
|
||||
consumePurchase(purchase) {
|
||||
queryAvailableCans()
|
||||
}
|
||||
consumePurchase(purchase)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -222,14 +229,14 @@ class CanChargeIapFragment : BaseFragment<FragmentCanChargeIapBinding>(
|
|||
}
|
||||
}
|
||||
|
||||
private fun consumePurchase(purchase: Purchase, onSuccess: () -> Unit) {
|
||||
private fun consumePurchase(purchase: Purchase) {
|
||||
val params = ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.purchaseToken)
|
||||
.build()
|
||||
|
||||
billingClient.consumeAsync(params) { billingResult, _ ->
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
onSuccess()
|
||||
queryAvailableCans()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
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)
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
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) {
|
||||
if (selectedTags.contains(item.tag)) {
|
||||
binding.ivTagChecked.visibility = View.VISIBLE
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_3bb9f1)
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
||||
isChecked = true
|
||||
} else {
|
||||
binding.ivTagChecked.visibility = View.GONE
|
||||
|
@ -44,7 +44,7 @@ class MemberTagAdapter(
|
|||
if (onItemClick(item.tag, isChecked)) {
|
||||
if (isChecked) {
|
||||
binding.ivTagChecked.visibility = View.VISIBLE
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_3bb9f1)
|
||||
binding.ivTag.setBackgroundResource(R.drawable.bg_round_corner_30_9970ff)
|
||||
} else {
|
||||
binding.ivTagChecked.visibility = View.GONE
|
||||
binding.ivTag.background = null
|
||||
|
|
|
@ -34,13 +34,8 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(ActivitySplashBinding
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
val lp = binding.ivText.layoutParams as ConstraintLayout.LayoutParams
|
||||
lp.topMargin = screenHeight * 302 / 2337
|
||||
lp.topMargin = screenHeight * 787 / 2337
|
||||
binding.ivText.layoutParams = lp
|
||||
|
||||
val lp2 = binding.ivText2.layoutParams as ConstraintLayout.LayoutParams
|
||||
lp2.bottomMargin = screenHeight * 195 / 2337
|
||||
binding.ivText2.layoutParams = lp2
|
||||
|
||||
setupRemoteConfig()
|
||||
fetchAndroidLatestVersion()
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 996 B After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 886 B |
Before Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 3.3 MiB |
After Width: | Height: | Size: 3.1 MiB |
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 4.5 KiB |
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_ff14d9" />
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,6 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_3bb9f1" />
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -1,8 +0,0 @@
|
|||
<?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>
|
|
@ -4,5 +4,5 @@
|
|||
<corners android:radius="16.7dp" />
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/color_3bb9f1" />
|
||||
android:color="@color/color_9970ff" />
|
||||
</shape>
|
|
@ -1,10 +0,0 @@
|
|||
<?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,7 +295,6 @@
|
|||
tools:text="매버릭 팔레트 (feat. J-DRAGON)" />
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/sv_action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="13.3dp">
|
||||
|
@ -546,7 +545,6 @@
|
|||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_can"
|
||||
android:layout_width="16.7dp"
|
||||
android:layout_height="16.7dp"
|
||||
android:contentDescription="@null"
|
||||
|
@ -563,7 +561,6 @@
|
|||
tools:text="300" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_unit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_light"
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
android:layout_width="106.7dp"
|
||||
android:layout_height="106.7dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@drawable/bg_round_corner_13_3_13181b"
|
||||
android:background="@drawable/bg_round_corner_13_3_3e3358"
|
||||
android:contentDescription="@null"
|
||||
android:padding="13.3dp"
|
||||
android:src="@drawable/ic_logo" />
|
||||
|
@ -209,7 +209,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
|
@ -228,7 +228,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="전체 연령"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -238,7 +238,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
|
@ -257,7 +257,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="19세 이상"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -300,7 +300,7 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
|
@ -319,7 +319,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="댓글 가능"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -329,7 +329,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b"
|
||||
android:background="@drawable/bg_round_corner_6_7_1f1734"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="14.3dp">
|
||||
|
||||
|
@ -348,7 +348,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:text="댓글 불가"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="14.7sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
@ -368,11 +368,11 @@
|
|||
android:layout_height="50dp"
|
||||
android:layout_marginEnd="6.7dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_13181b_3bb9f1"
|
||||
android:background="@drawable/bg_round_corner_6_7_1f1734_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:text="취소"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
android:textColor="@color/color_9970ff"
|
||||
android:textSize="18.3sp" />
|
||||
|
||||
<TextView
|
||||
|
@ -381,7 +381,7 @@
|
|||
android:layout_height="50dp"
|
||||
android:layout_marginStart="6.7dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_round_corner_6_7_3bb9f1"
|
||||
android:background="@drawable/bg_round_corner_6_7_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:text="수정"
|
||||
|
|
|
@ -33,32 +33,29 @@
|
|||
android:paddingHorizontal="13.3dp"
|
||||
android:paddingVertical="23.3dp">
|
||||
|
||||
<LinearLayout
|
||||
<ImageView
|
||||
android:id="@+id/ic_can"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_can"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_can"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="13.3dp"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_can" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_charge_can_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="15.3sp"
|
||||
tools:text="5000 캔 + 1000 캔" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/tv_charge_can_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="13.3dp"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/color_eeeeee"
|
||||
android:textSize="15.3sp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/ic_can"
|
||||
app:layout_constraintStart_toEndOf="@+id/ic_can"
|
||||
app:layout_constraintTop_toTopOf="@+id/ic_can"
|
||||
tools:text="5000 캔 + 1000 캔" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/ll_price"
|
||||
|
@ -174,7 +171,6 @@
|
|||
app:drawableStartCompat="@drawable/ic_select" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_alert"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="26.7dp"
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="13.3dp"
|
||||
android:layout_marginTop="60dp"
|
||||
android:background="@drawable/bg_round_corner_6_7_3bb9f1"
|
||||
android:background="@drawable/bg_round_corner_6_7_9970ff"
|
||||
android:fontFamily="@font/gmarket_sans_bold"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="16dp"
|
||||
|
@ -102,13 +102,13 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="93dp"
|
||||
android:background="@drawable/bg_round_corner_8_transparent_3bb9f1"
|
||||
android:background="@drawable/bg_round_corner_8_transparent_9970ff"
|
||||
android:drawablePadding="13.3dp"
|
||||
android:paddingHorizontal="18.7dp"
|
||||
android:paddingVertical="10.7dp"
|
||||
android:text="고객센터로 문의하기"
|
||||
android:textColor="@color/color_3bb9f1"
|
||||
app:drawableStartCompat="@drawable/ic_headphones_blue" />
|
||||
android:textColor="@color/color_9970ff"
|
||||
app:drawableStartCompat="@drawable/ic_headphones_purple" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -29,10 +29,9 @@
|
|||
android:layout_gravity="center"
|
||||
android:layout_marginTop="28.3dp"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:text="현재 참여 가능한 라이브 방송이 없거나\n연령제한으로 입장이 불가능합니다.\n본인인증을 해보거나 채널을 팔로잉하고\n라이브 방송 알림을 받아보세요."
|
||||
android:text="🙀현재 참여 가능한 라이브 방송이 없거나\n연령제한으로 입장이 불가능합니다.\n본인인증을 해보거나 채널을 팔로잉하고\n라이브 방송 알림을 받아보세요."
|
||||
android:textColor="@color/color_bbbbbb"
|
||||
android:textSize="13sp"
|
||||
android:lineSpacingExtra="8dp"
|
||||
android:textSize="15sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -63,10 +63,9 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/gmarket_sans_medium"
|
||||
android:gravity="center"
|
||||
android:text="지금 예약중인 라이브가 없습니다.\n다른 날짜의 라이브를 예약하고 참여해 보세요."
|
||||
android:text="지금 예약중인 라이브가 없습니다.\n채널을 팔로잉 하고 라이브 알림을 받아 보세요."
|
||||
android:textColor="@color/color_bbbbbb"
|
||||
android:textSize="13sp"
|
||||
android:lineSpacingExtra="8dp"
|
||||
android:textSize="10.7sp"
|
||||
tools:ignore="SmallSp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|