Compare commits

...

28 Commits

Author SHA1 Message Date
3a62ed8463 chore(git): worktree 디렉터리를 제외한다 2026-07-22 18:11:14 +09:00
6755c8ae99 feat(main): 메인 탭 당겨서 새로고침을 추가한다 2026-07-22 17:48:33 +09:00
b17e250665 docs(main): 당겨서 새로고침 계획을 추가한다 2026-07-22 00:35:34 +09:00
074c945008 chore(app): 앱 버전을 1.55.1로 올린다 2026-07-20 15:41:48 +09:00
16aa946621 feat(main): 홈 크리에이터 FAB를 추가한다 2026-07-17 00:08:33 +09:00
831533b4f6 refactor(creator): 진행 중 라이브 컴포넌트를 공통화한다 2026-07-16 22:59:07 +09:00
de90f771c1 refactor(v2): 도메인 액션 경로를 통합한다 2026-07-16 16:57:39 +09:00
4373452478 docs(v2): 라이브 액션 검증 기록을 갱신한다 2026-07-15 21:27:53 +09:00
0b3042d29e refactor(onair): 라이브 입장 흐름을 공통화한다 2026-07-15 21:27:44 +09:00
cc23992d2e refactor(home): 추천 라이브 진입을 공통화한다 2026-07-15 21:27:37 +09:00
3a49158243 refactor(creator): 라이브 액션을 공통화한다 2026-07-15 21:27:31 +09:00
d1509d4359 refactor(live): 공통 액션 코디네이터를 추가한다 2026-07-15 21:27:23 +09:00
c223b3b8a4 feat(live): 생성 결과 계약을 추가한다 2026-07-15 21:26:53 +09:00
b582545991 feat(live): 입장 정책 모델을 추가한다 2026-07-15 21:26:37 +09:00
fe79431744 refactor(content): 상세 진입을 공통 액션으로 통합한다 2026-07-14 22:11:10 +09:00
1c5fbb38f1 style(content): 주석 오디오 너비 계산 줄바꿈을 정리한다 2026-07-14 20:48:53 +09:00
dadf3a519d test(home): 팔로잉 empty 문구 검증을 정리한다 2026-07-14 20:45:34 +09:00
ddc949f9d9 refactor(live): 온에어 접근 가드를 공통화한다 2026-07-14 20:45:29 +09:00
6973816b8c refactor(creator): 크리에이터 접근 가드를 공통화한다 2026-07-14 20:45:23 +09:00
e5b99be9c4 refactor(main): 기존 로그인 가드를 제거한다 2026-07-14 20:45:16 +09:00
5ff92980a2 refactor(chat): 채팅 접근 가드를 공통화한다 2026-07-14 20:44:58 +09:00
2fda80d602 refactor(content): 콘텐츠 접근 가드를 공통화한다 2026-07-14 20:44:53 +09:00
7e12aa8720 refactor(home): 홈 접근 가드를 공통화한다 2026-07-14 20:44:42 +09:00
d5d3444c3a refactor(main): 메인 접근 가드를 공통화한다 2026-07-14 20:44:36 +09:00
a6601dcea1 feat(access): 공통 접근 실행기를 추가한다 2026-07-14 20:44:20 +09:00
4d51806cee feat(access): 접근 정책 모델을 추가한다 2026-07-14 20:44:13 +09:00
98db0b657e docs(v2): 공통 접근 가드 계획을 보강한다 2026-07-14 20:44:06 +09:00
9f70bcd3eb docs(v2): 공통 접근 가드 계획을 기록한다 2026-07-14 12:22:58 +09:00
210 changed files with 9662 additions and 2007 deletions

1
.gitignore vendored
View File

@@ -319,5 +319,6 @@ app/release/
.kiro/ .kiro/
.omo/ .omo/
.antigravitycli/ .antigravitycli/
.worktrees/
# End of https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio,visualstudiocode,git,kotlin,java # End of https://www.toptal.com/developers/gitignore/api/macos,android,androidstudio,visualstudiocode,git,kotlin,java

View File

@@ -86,8 +86,8 @@ android {
applicationId "kr.co.vividnext.sodalive" applicationId "kr.co.vividnext.sodalive"
minSdk 23 minSdk 23
targetSdk 35 targetSdk 35
versionCode 242 versionCode 243
versionName "1.55.0" versionName "1.55.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -361,17 +361,20 @@ class Agora(
fun deInitRtmClient(rtmEventListener: RtmEventListener) { fun deInitRtmClient(rtmEventListener: RtmEventListener) {
rtmClient?.removeEventListener(rtmEventListener) rtmClient?.removeEventListener(rtmEventListener)
rtmClient?.unsubscribe(roomChannelName, object : ResultCallback<Void> { rtmClient?.unsubscribe(
override fun onSuccess(responseInfo: Void?) { roomChannelName,
Logger.e("RTM unsubscribe - $roomChannelName") object : ResultCallback<Void> {
roomChannelName = null override fun onSuccess(responseInfo: Void?) {
} Logger.e("RTM unsubscribe - $roomChannelName")
roomChannelName = null
}
override fun onFailure(errorInfo: ErrorInfo) { override fun onFailure(errorInfo: ErrorInfo) {
Logger.e("RTM unsubscribe fail - ${errorInfo.errorCode}") Logger.e("RTM unsubscribe fail - ${errorInfo.errorCode}")
Logger.e("RTM unsubscribe fail - ${errorInfo.errorReason}") Logger.e("RTM unsubscribe fail - ${errorInfo.errorReason}")
}
} }
}) )
rtmClient?.unsubscribe( rtmClient?.unsubscribe(
"inbox_${SharedPreferenceManager.userId}", "inbox_${SharedPreferenceManager.userId}",
object : ResultCallback<Void> { object : ResultCallback<Void> {
@@ -383,7 +386,8 @@ class Agora(
Logger.e("RTM unsubscribe fail - ${errorInfo.errorCode}") Logger.e("RTM unsubscribe fail - ${errorInfo.errorCode}")
Logger.e("RTM unsubscribe fail - ${errorInfo.errorReason}") Logger.e("RTM unsubscribe fail - ${errorInfo.errorReason}")
} }
}) }
)
rtmClient?.logout(object : ResultCallback<Void> { rtmClient?.logout(object : ResultCallback<Void> {
override fun onSuccess(responseInfo: Void?) { override fun onSuccess(responseInfo: Void?) {
Logger.e("RTM logout") Logger.e("RTM logout")
@@ -398,7 +402,6 @@ class Agora(
// 상태 리셋 // 상태 리셋
rtmLoggedIn = false rtmLoggedIn = false
rtmLoginInProgress = false rtmLoginInProgress = false
} }
// endregion // endregion
} }

View File

@@ -136,7 +136,7 @@ class SodaLiveApp : Application(), DefaultLifecycleObserver {
applicationContext, applicationContext,
BuildConfig.NOTIFLY_PROJECT_ID, BuildConfig.NOTIFLY_PROJECT_ID,
BuildConfig.NOTIFLY_USERNAME, BuildConfig.NOTIFLY_USERNAME,
BuildConfig.NOTIFLY_PASSWORD, BuildConfig.NOTIFLY_PASSWORD
) )
} }

View File

@@ -14,5 +14,5 @@ data class AddAllPlaybackTrackingRequest(
data class PlaybackTrackingData( data class PlaybackTrackingData(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("playDateTime") val playDateTime: String, @SerializedName("playDateTime") val playDateTime: String,
@SerializedName("isPreview") val isPreview: Boolean, @SerializedName("isPreview") val isPreview: Boolean
) )

View File

@@ -127,7 +127,7 @@ class AudioContentViewModel(private val repository: AudioContentRepository) : Ba
compositeDisposable.add( compositeDisposable.add(
repository.getCategoryList( repository.getCategoryList(
creatorId = userId, creatorId = userId,
token = "Bearer ${SharedPreferenceManager.token}", token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@@ -10,5 +10,5 @@ enum class PurchaseOption {
BUY_ONLY, BUY_ONLY,
@SerializedName("RENT_ONLY") @SerializedName("RENT_ONLY")
RENT_ONLY, RENT_ONLY
} }

View File

@@ -21,7 +21,7 @@ import kr.co.vividnext.sodalive.extensions.moneyFormat
class AudioContentNewAllAdapter( class AudioContentNewAllAdapter(
private val itemWidth: Int, private val itemWidth: Int,
private val onClickItem: (Long) -> Unit, private val onClickItem: (Long) -> Unit,
private val onClickCreator: (Long) -> Unit, private val onClickCreator: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentNewAllAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AudioContentNewAllAdapter.ViewHolder>() {
inner class ViewHolder( inner class ViewHolder(

View File

@@ -35,7 +35,7 @@ class AudioContentCommentReplyAdapter(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false false
), )
) )
} else { } else {
AudioContentCommentReplyItemViewHolder( AudioContentCommentReplyItemViewHolder(
@@ -172,9 +172,7 @@ class AudioContentCommentReplyItemViewHolder(
private val context: Context, private val context: Context,
private val creatorId: Long, private val creatorId: Long,
private val binding: ItemAudioContentCommentReplyBinding, private val binding: ItemAudioContentCommentReplyBinding,
private val showOptionMenu: ( private val showOptionMenu: (Context, View, Long, Long, Long, onClickModify: () -> Unit) -> Unit,
Context, View, Long, Long, Long, onClickModify: () -> Unit
) -> Unit,
private val modifyComment: (Long, String) -> Unit private val modifyComment: (Long, String) -> Unit
) : AudioContentCommentReplyViewHolder(binding) { ) : AudioContentCommentReplyViewHolder(binding) {

View File

@@ -51,7 +51,7 @@ data class GetAudioContentDetailResponse(
data class OtherContentResponse( data class OtherContentResponse(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("coverUrl") val coverUrl: String, @SerializedName("coverUrl") val coverUrl: String
) )
@Keep @Keep

View File

@@ -25,10 +25,15 @@ class AudioContentMainNewContentThemeAdapter(
fun bind(theme: String) { fun bind(theme: String) {
if ( if (
theme == selectedTheme || theme == selectedTheme ||
(selectedTheme == "" && theme == SodaLiveApplicationHolder.get() (
.getString(R.string.audio_content_label_all)) || selectedTheme == "" && theme == SodaLiveApplicationHolder.get()
(selectedTheme == "" && theme == SodaLiveApplicationHolder.get() .getString(R.string.audio_content_label_all)) ||
.getString(R.string.screen_home_sort_revenue)) (
selectedTheme == "" && theme == SodaLiveApplicationHolder.get()
.getString(
R.string.screen_home_sort_revenue
)
)
) { ) {
binding.tvTheme.setBackgroundResource( binding.tvTheme.setBackgroundResource(
R.drawable.bg_round_corner_16_7_transparent_3bb9f1 R.drawable.bg_round_corner_16_7_transparent_3bb9f1

View File

@@ -76,7 +76,8 @@ class AudioContentModifyActivity : BaseActivity<ActivityAudioContentModifyBindin
excludeGif = true, excludeGif = true,
isEnabledFreeStyleCrop = true, isEnabledFreeStyleCrop = true,
config = ImagePickerCropper.Config( config = ImagePickerCropper.Config(
aspectX = 1f, aspectY = 1f, aspectX = 1f,
aspectY = 1f,
compressFormat = Bitmap.CompressFormat.JPEG, compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90 compressQuality = 90
), ),

View File

@@ -28,7 +28,7 @@ class AudioContentOrderConfirmDialog(
orderType: OrderType, orderType: OrderType,
price: Int, price: Int,
isAvailableUsePoint: Boolean, isAvailableUsePoint: Boolean,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog

View File

@@ -1,20 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.order package kr.co.vividnext.sodalive.audio_content.order
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentOrderListBinding import kr.co.vividnext.sodalive.databinding.ActivityAudioContentOrderListBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderListBinding>( class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderListBinding>(
ActivityAudioContentOrderListBinding::inflate ActivityAudioContentOrderListBinding::inflate

View File

@@ -20,5 +20,5 @@ data class GetAudioContentOrderListItem(
@SerializedName("isAdult") val isAdult: Boolean, @SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("orderType") val orderType: OrderType, @SerializedName("orderType") val orderType: OrderType,
@SerializedName("likeCount") val likeCount: Int, @SerializedName("likeCount") val likeCount: Int,
@SerializedName("commentCount") val commentCount: Int, @SerializedName("commentCount") val commentCount: Int
) )

View File

@@ -429,7 +429,6 @@ class AudioContentPlayerFragment(
mediaController?.seekTo(progress.toLong()) mediaController?.seekTo(progress.toLong())
} }
} }
}) })
updateMediaMetadata(mediaController?.currentMediaItem?.mediaMetadata) updateMediaMetadata(mediaController?.currentMediaItem?.mediaMetadata)

View File

@@ -14,8 +14,11 @@ import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseViewModel() { class SeriesListAllViewModel(private val repository: SeriesRepository) : BaseViewModel() {
enum class SeriesSortType { enum class SeriesSortType {
@SerializedName("NEWEST") NEWEST, @SerializedName("NEWEST")
@SerializedName("OLDEST") OLDEST NEWEST,
@SerializedName("OLDEST")
OLDEST
} }
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<String?>()

View File

@@ -1,6 +1,5 @@
package kr.co.vividnext.sodalive.audio_content.series.detail package kr.co.vividnext.sodalive.audio_content.series.detail
import android.annotation.SuppressLint
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle

View File

@@ -240,7 +240,7 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
title = getString(R.string.audio_content_upload_dialog_title), title = getString(R.string.audio_content_upload_dialog_title),
desc = getString(R.string.audio_content_upload_dialog_desc), desc = getString(R.string.audio_content_upload_dialog_desc),
confirmButtonTitle = getString(R.string.confirm), confirmButtonTitle = getString(R.string.confirm),
confirmButtonClick = { finish() }, confirmButtonClick = { finish() }
).show(screenWidth) ).show(screenWidth)
} }
} }

View File

@@ -20,5 +20,5 @@ data class CreateAudioContentRequest(
@SerializedName("isPointAvailable") val isPointAvailable: Boolean, @SerializedName("isPointAvailable") val isPointAvailable: Boolean,
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean, @SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
@SerializedName("previewStartTime") val previewStartTime: String? = null, @SerializedName("previewStartTime") val previewStartTime: String? = null,
@SerializedName("previewEndTime") val previewEndTime: String? = null, @SerializedName("previewEndTime") val previewEndTime: String? = null
) )

View File

@@ -80,13 +80,7 @@ class AuditionApplicantListAdapter(
binding.sbProgress.max = currentTotalDuration binding.sbProgress.max = currentTotalDuration
binding.sbProgress.progress = currentTime binding.sbProgress.progress = currentTime
binding.tvTotalDuration.text = binding.tvTotalDuration.text = "/${Utils.convertDurationToString(currentTotalDuration, showHours = false)}"
"/${
Utils.convertDurationToString(
currentTotalDuration,
showHours = false
)
}"
binding.tvCurrentTime.text = Utils.convertDurationToString( binding.tvCurrentTime.text = Utils.convertDurationToString(
currentTime, currentTime,
showHours = false showHours = false

View File

@@ -17,7 +17,6 @@ import kr.co.vividnext.sodalive.audition.role.AuditionRoleDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.databinding.ActivityAuditionDetailBinding import kr.co.vividnext.sodalive.databinding.ActivityAuditionDetailBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject

View File

@@ -43,7 +43,8 @@ class CharacterAdapter(
translationY = fm.descent translationY = fm.descent
return true return true
} }
}) }
)
} }
} else { } else {
binding.tvRanking.visibility = View.GONE binding.tvRanking.visibility = View.GONE

View File

@@ -17,7 +17,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.UiText
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentListBinding import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentListBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
@@ -151,8 +150,7 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy) super.onScrolled(recyclerView, dx, dy)
val lastVisible = (recyclerView.layoutManager as LinearLayoutManager) val lastVisible = (recyclerView.layoutManager as LinearLayoutManager).findLastCompletelyVisibleItemPosition()
.findLastCompletelyVisibleItemPosition()
val total = recyclerView.adapter?.itemCount ?: 0 val total = recyclerView.adapter?.itemCount ?: 0
if (!recyclerView.canScrollVertically(1) && lastVisible == total - 1) { if (!recyclerView.canScrollVertically(1) && lastVisible == total - 1) {
viewModel.getCommentList(characterId) viewModel.getCommentList(characterId)
@@ -195,7 +193,6 @@ class CharacterCommentListFragment : BaseFragment<FragmentCharacterCommentListBi
imm.hideSoftInputFromWindow(view?.windowToken, 0) imm.hideSoftInputFromWindow(view?.windowToken, 0)
} }
companion object { companion object {
private const val EXTRA_CHARACTER_ID = "extra_character_id" private const val EXTRA_CHARACTER_ID = "extra_character_id"
fun newInstance(characterId: Long): CharacterCommentListFragment { fun newInstance(characterId: Long): CharacterCommentListFragment {

View File

@@ -15,7 +15,6 @@ import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.UiText
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentReplyBinding import kr.co.vividnext.sodalive.databinding.FragmentCharacterCommentReplyBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
@@ -48,15 +47,19 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
characterId = arguments?.getLong(EXTRA_CHARACTER_ID) ?: 0 characterId = arguments?.getLong(EXTRA_CHARACTER_ID) ?: 0
original = arguments?.let { original = arguments?.let {
val cid = it.getLong(EXTRA_ORIGINAL_COMMENT_ID, -1) val cid = it.getLong(EXTRA_ORIGINAL_COMMENT_ID, -1)
if (cid == -1L) null else CharacterCommentResponse( if (cid == -1L) {
commentId = cid, null
memberId = it.getLong(EXTRA_ORIGINAL_MEMBER_ID), } else {
memberProfileImage = it.getString(EXTRA_ORIGINAL_MEMBER_PROFILE_IMAGE) ?: "", CharacterCommentResponse(
memberNickname = it.getString(EXTRA_ORIGINAL_MEMBER_NICKNAME) ?: "", commentId = cid,
createdAt = it.getLong(EXTRA_ORIGINAL_CREATED_AT), memberId = it.getLong(EXTRA_ORIGINAL_MEMBER_ID),
replyCount = it.getInt(EXTRA_ORIGINAL_REPLY_COUNT), memberProfileImage = it.getString(EXTRA_ORIGINAL_MEMBER_PROFILE_IMAGE) ?: "",
comment = it.getString(EXTRA_ORIGINAL_COMMENT_TEXT) ?: "" memberNickname = it.getString(EXTRA_ORIGINAL_MEMBER_NICKNAME) ?: "",
) createdAt = it.getLong(EXTRA_ORIGINAL_CREATED_AT),
replyCount = it.getInt(EXTRA_ORIGINAL_REPLY_COUNT),
comment = it.getString(EXTRA_ORIGINAL_COMMENT_TEXT) ?: ""
)
}
} }
return super.onCreateView(inflater, container, savedInstanceState) return super.onCreateView(inflater, container, savedInstanceState)
} }
@@ -140,7 +143,7 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
outRect.right = 24f.dpToPx().toInt() outRect.right = 24f.dpToPx().toInt()
when (parent.getChildAdapterPosition(view)) { when (parent.getChildAdapterPosition(view)) {
0 -> { 0 -> {
outRect.top = 24f.dpToPx().toInt(); outRect.top = 24f.dpToPx().toInt()
outRect.bottom = 12f.dpToPx().toInt() outRect.bottom = 12f.dpToPx().toInt()
} }
@@ -196,7 +199,6 @@ class CharacterCommentReplyFragment : BaseFragment<FragmentCharacterCommentReply
} }
} }
companion object { companion object {
private const val EXTRA_CHARACTER_ID = "extra_character_id" private const val EXTRA_CHARACTER_ID = "extra_character_id"
private const val EXTRA_ORIGINAL_COMMENT_ID = "extra_original_comment_id" private const val EXTRA_ORIGINAL_COMMENT_ID = "extra_original_comment_id"

View File

@@ -1,6 +1,5 @@
package kr.co.vividnext.sodalive.chat.character.comment package kr.co.vividnext.sodalive.chat.character.comment
import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup

View File

@@ -434,5 +434,4 @@ class CharacterDetailFragment : BaseFragment<FragmentCharacterDetailBinding>(
binding.tvPersonalityContent.maxLines = 3 binding.tvPersonalityContent.maxLines = 3
binding.tvPersonalityContent.ellipsize = TextUtils.TruncateAt.END binding.tvPersonalityContent.ellipsize = TextUtils.TruncateAt.END
} }
} }

View File

@@ -29,6 +29,7 @@ data class CharacterDetailResponse(
enum class CharacterType { enum class CharacterType {
@SerializedName("Clone") @SerializedName("Clone")
CLONE, CLONE,
@SerializedName("Character") @SerializedName("Character")
CHARACTER CHARACTER
} }

View File

@@ -49,7 +49,6 @@ class OtherCharacterAdapter(
transformations(RoundedCornersTransformation(16f.dpToPx())) transformations(RoundedCornersTransformation(16f.dpToPx()))
} }
binding.root.setOnClickListener { binding.root.setOnClickListener {
onItemClick?.invoke(item) onItemClick?.invoke(item)
} }

View File

@@ -118,9 +118,7 @@ class CharacterGalleryViewModel(
val token = "Bearer ${SharedPreferenceManager.token}" val token = "Bearer ${SharedPreferenceManager.token}"
isPurchasing = true isPurchasing = true
_uiState.value = _uiState.value?.copy( _uiState.value = _uiState.value?.copy(isLoading = isRequesting || isPurchasing)
isLoading = isRequesting || isPurchasing,
)
compositeDisposable.add( compositeDisposable.add(
repository.purchaseCharacterImage(token = token, imageId = imageId) repository.purchaseCharacterImage(token = token, imageId = imageId)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())

View File

@@ -85,7 +85,6 @@ class OriginalWorkDetailActivity : BaseActivity<ActivityOriginalWorkDetailBindin
override fun onTabReselected(tab: TabLayout.Tab) { override fun onTabReselected(tab: TabLayout.Tab) {
} }
}) })
} }

View File

@@ -99,7 +99,6 @@ class ChatBackgroundPickerDialogFragment : DialogFragment() {
items.addAll(list.map { BgItem(id = it.id, url = it.imageUrl) }) items.addAll(list.map { BgItem(id = it.id, url = it.imageUrl) })
adapter.submit(items, selectedId) adapter.submit(items, selectedId)
loadingDialog.dismiss() loadingDialog.dismiss()
}, { _ -> }, { _ ->
// 실패 시에도 현재까지의 목록 표시(없으면 빈 목록) // 실패 시에도 현재까지의 목록 표시(없으면 빈 목록)
@@ -161,9 +160,7 @@ class ChatBackgroundPickerDialogFragment : DialogFragment() {
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BgVH { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BgVH {
val binding = ItemChatBackgroundImageBinding.inflate( val binding = ItemChatBackgroundImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
LayoutInflater.from(parent.context), parent, false
)
return BgVH(binding, onClick) return BgVH(binding, onClick)
} }

View File

@@ -12,8 +12,10 @@ import androidx.annotation.Keep
enum class MessageStatus { enum class MessageStatus {
/** 전송 중 */ /** 전송 중 */
SENDING, SENDING,
/** 전송 완료 */ /** 전송 완료 */
SENT, SENT,
/** 전송 실패 */ /** 전송 실패 */
FAILED FAILED
} }

View File

@@ -4,7 +4,11 @@
package kr.co.vividnext.sodalive.chat.talk.room.db package kr.co.vividnext.sodalive.chat.talk.room.db
import androidx.annotation.Keep import androidx.annotation.Keep
import androidx.room.* import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
@Keep @Keep
@Dao @Dao

View File

@@ -45,15 +45,21 @@ class ImagePickerCropper(
// 13+ : 시스템 Photo Picker // 13+ : 시스템 Photo Picker
private val pickPhoto: ActivityResultLauncher<PickVisualMediaRequest> = private val pickPhoto: ActivityResultLauncher<PickVisualMediaRequest> =
caller.registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri -> caller.registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
if (uri == null) onError(CancellationException("이미지 선택을 취소했습니다.")) if (uri == null) {
else handlePickedUri(uri) onError(CancellationException("이미지 선택을 취소했습니다."))
} else {
handlePickedUri(uri)
}
} }
// 12- : SAF GetContent // 12- : SAF GetContent
private val pickContent: ActivityResultLauncher<String> = private val pickContent: ActivityResultLauncher<String> =
caller.registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> caller.registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri == null) onError(CancellationException("이미지 선택을 취소했습니다.")) if (uri == null) {
else handlePickedUri(uri) onError(CancellationException("이미지 선택을 취소했습니다."))
} else {
handlePickedUri(uri)
}
} }
// uCrop 결과 수신 // uCrop 결과 수신
@@ -105,7 +111,9 @@ class ImagePickerCropper(
val gifFile = copyUriToCacheAsGif(source) val gifFile = copyUriToCacheAsGif(source)
lastCroppedFile = gifFile lastCroppedFile = gifFile
val fileUri = FileProvider.getUriForFile( val fileUri = FileProvider.getUriForFile(
context, "${BuildConfig.APPLICATION_ID}.fileprovider", gifFile context,
"${BuildConfig.APPLICATION_ID}.fileprovider",
gifFile
) )
// 2) 바로 반환 (크롭 생략) // 2) 바로 반환 (크롭 생략)
@@ -137,13 +145,20 @@ class ImagePickerCropper(
) )
?.use { c -> ?.use { c ->
val idx = c.getColumnIndex(OpenableColumns.DISPLAY_NAME) val idx = c.getColumnIndex(OpenableColumns.DISPLAY_NAME)
if (idx >= 0 && c.moveToFirst()) c.getString(idx) else null if (idx >= 0 && c.moveToFirst()) {
c.getString(idx)
} else {
null
}
} }
} }
private fun copyUriToCacheAsGif(uri: Uri): File { private fun copyUriToCacheAsGif(uri: Uri): File {
val base = if (config.useExternalCache) context.externalCacheDir ?: context.cacheDir val base = if (config.useExternalCache) {
else context.cacheDir context.externalCacheDir ?: context.cacheDir
} else {
context.cacheDir
}
// 원본 이름 유지 시도, 실패하면 타임스탬프 // 원본 이름 유지 시도, 실패하면 타임스탬프
val name = getDisplayName(uri)?.takeIf { it.endsWith(".gif", true) } val name = getDisplayName(uri)?.takeIf { it.endsWith(".gif", true) }
@@ -201,8 +216,11 @@ class ImagePickerCropper(
} }
private fun createTempCropFile(): File { private fun createTempCropFile(): File {
val base = if (config.useExternalCache) context.externalCacheDir ?: context.cacheDir val base = if (config.useExternalCache) {
else context.cacheDir context.externalCacheDir ?: context.cacheDir
} else {
context.cacheDir
}
val ext = when (config.compressFormat) { val ext = when (config.compressFormat) {
Bitmap.CompressFormat.PNG -> "png" Bitmap.CompressFormat.PNG -> "png"

View File

@@ -89,14 +89,17 @@ object RealPathUtil {
} // MediaProvider } // MediaProvider
// DownloadsProvider // DownloadsProvider
} else if ("content".equals(uri.scheme!!, ignoreCase = true)) { } else if ("content".equals(uri.scheme!!, ignoreCase = true)) {
// Return the remote address // Return the remote address
return if (isGooglePhotosUri(uri)) uri.lastPathSegment else getDataColumn( return if (isGooglePhotosUri(uri)) {
context, uri.lastPathSegment
uri, } else {
null, getDataColumn(
null context,
) uri,
null,
null
)
}
} else if ("file".equals(uri.scheme!!, ignoreCase = true)) { } else if ("file".equals(uri.scheme!!, ignoreCase = true)) {
return uri.path return uri.path
} // File } // File
@@ -122,7 +125,6 @@ object RealPathUtil {
selection: String?, selection: String?,
selectionArgs: Array<String>? selectionArgs: Array<String>?
): String? { ): String? {
var cursor: Cursor? = null var cursor: Cursor? = null
val column = "_data" val column = "_data"
val projection = arrayOf(column) val projection = arrayOf(column)

View File

@@ -1,10 +1,7 @@
package kr.co.vividnext.sodalive.common package kr.co.vividnext.sodalive.common
import android.content.Context
import android.os.Build
import java.net.URLEncoder import java.net.URLEncoder
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import kr.co.vividnext.sodalive.settings.language.LanguageManager
object Utils { object Utils {
fun convertDurationToString(duration: Int, showHours: Boolean = true): String { fun convertDurationToString(duration: Int, showHours: Boolean = true): String {

View File

@@ -18,7 +18,7 @@ open class LiveDialog(
confirmButtonTitle: String, confirmButtonTitle: String,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit,
cancelButtonTitle: String = "", cancelButtonTitle: String = "",
cancelButtonClick: (() -> Unit)? = null, cancelButtonClick: (() -> Unit)? = null
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog

View File

@@ -11,7 +11,7 @@ import kr.co.vividnext.sodalive.R
class CreatorFollowNotifyFragment( class CreatorFollowNotifyFragment(
private val onClickNotifyAll: () -> Unit, private val onClickNotifyAll: () -> Unit,
private val onClickNotifyNone: () -> Unit, private val onClickNotifyNone: () -> Unit,
private val onClickUnFollow: () -> Unit, private val onClickUnFollow: () -> Unit
) : BottomSheetDialogFragment() { ) : BottomSheetDialogFragment() {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,

View File

@@ -37,12 +37,12 @@ import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllActivity 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.series.detail.SeriesDetailActivity
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
import kr.co.vividnext.sodalive.common.image.BlurTransformation
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.image.BlurTransformation
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
@@ -138,7 +138,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
binding.ivMenu.setOnClickListener { binding.ivMenu.setOnClickListener {
showOptionMenu( showOptionMenu(
this, this,
binding.ivMenu, binding.ivMenu
) )
} }
@@ -468,7 +468,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
viewModel.modifyCheers( viewModel.modifyCheers(
cheersId = cheersId, cheersId = cheersId,
creatorId = userId, creatorId = userId,
cheersContent = content, cheersContent = content
) )
} }
}, },

View File

@@ -7,5 +7,5 @@ import com.google.gson.annotations.SerializedName
data class PutModifyCheersRequest( data class PutModifyCheersRequest(
@SerializedName("cheersId") val cheersId: Long, @SerializedName("cheersId") val cheersId: Long,
@SerializedName("content") var content: String? = null, @SerializedName("content") var content: String? = null,
@SerializedName("isActive") var isActive: Boolean? = null, @SerializedName("isActive") var isActive: Boolean? = null
) )

View File

@@ -149,7 +149,6 @@ class CreatorCommunityAllViewModel(
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {}) .subscribe({}, {})
) )
} }
fun registerComment( fun registerComment(
@@ -282,49 +281,48 @@ class CreatorCommunityAllViewModel(
) )
) )
} }
} }
fun updateCommunityPostFixed(postId: Long, isFixed: Boolean) { fun updateCommunityPostFixed(postId: Long, isFixed: Boolean) {
if (_isLoading.value == true) return if (_isLoading.value == true) return
_isLoading.value = true _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
repository.updateCommunityPostFixed( repository.updateCommunityPostFixed(
postId = postId, postId = postId,
isFixed = isFixed, isFixed = isFixed,
token = "Bearer ${SharedPreferenceManager.token}" token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
// 목록을 초기화하고 재조회하여 최신 고정 상태를 반영한다.
page = 1
isLast = false
getCommunityPostList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
)
) )
} .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
// 목록을 초기화하고 재조회하여 최신 고정 상태를 반영한다.
page = 1
isLast = false
getCommunityPostList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(
SodaLiveApplicationHolder.get()
.getString(R.string.common_error_unknown)
)
}
)
)
}
} }

View File

@@ -39,7 +39,8 @@ class CreatorCommunityReportDialog(
alertDialog.dismiss() alertDialog.dismiss()
confirmButtonClick(reason) confirmButtonClick(reason)
} else { } else {
Toast.makeText(activity, Toast.makeText(
activity,
SodaLiveApplicationHolder.get() SodaLiveApplicationHolder.get()
.getString(R.string.screen_audio_content_detail_report_reason_required), .getString(R.string.screen_audio_content_detail_report_reason_required),
Toast.LENGTH_LONG Toast.LENGTH_LONG

View File

@@ -16,7 +16,7 @@ class PurchaseCommunityPostDialog(
activity: Activity, activity: Activity,
layoutInflater: LayoutInflater, layoutInflater: LayoutInflater,
can: Int, can: Int,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog

View File

@@ -7,5 +7,5 @@ import com.google.gson.annotations.SerializedName
data class PurchasePostRequest( data class PurchasePostRequest(
@SerializedName("postId") val postId: Long, @SerializedName("postId") val postId: Long,
@SerializedName("timezone") val timezone: String, @SerializedName("timezone") val timezone: String,
@SerializedName("container") val container: String = "aos", @SerializedName("container") val container: String = "aos"
) )

View File

@@ -127,9 +127,7 @@ class CreatorCommunityCommentReplyItemViewHolder(
private val context: Context, private val context: Context,
private val creatorId: Long, private val creatorId: Long,
private val binding: ItemCommunityPostCommentReplyBinding, private val binding: ItemCommunityPostCommentReplyBinding,
private val showOptionMenu: ( private val showOptionMenu: (Context, View, Long, Long, Long, onClickModify: () -> Unit) -> Unit,
Context, View, Long, Long, Long, onClickModify: () -> Unit
) -> Unit,
private val modifyComment: (Long, String) -> Unit, private val modifyComment: (Long, String) -> Unit,
private val onClickProfile: (Long) -> Unit private val onClickProfile: (Long) -> Unit
) : CreatorCommunityCommentReplyViewHolder(binding) { ) : CreatorCommunityCommentReplyViewHolder(binding) {
@@ -178,5 +176,4 @@ class CreatorCommunityCommentReplyItemViewHolder(
binding.ivMenu.visibility = View.GONE binding.ivMenu.visibility = View.GONE
} }
} }
} }

View File

@@ -1,7 +1,6 @@
package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify package kr.co.vividnext.sodalive.explorer.profile.creator_community.modify
import android.Manifest import android.Manifest
import android.annotation.SuppressLint
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
@@ -76,7 +75,8 @@ class CreatorCommunityModifyActivity : BaseActivity<ActivityCreatorCommunityModi
context = this, context = this,
isEnabledFreeStyleCrop = true, isEnabledFreeStyleCrop = true,
config = ImagePickerCropper.Config( config = ImagePickerCropper.Config(
aspectX = 1f, aspectY = 1f, aspectX = 1f,
aspectY = 1f,
compressFormat = Bitmap.CompressFormat.JPEG, compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90 compressQuality = 90
), ),

View File

@@ -7,6 +7,7 @@ import com.google.gson.annotations.SerializedName
enum class DonationRankingPeriod { enum class DonationRankingPeriod {
@SerializedName("WEEKLY") @SerializedName("WEEKLY")
WEEKLY, WEEKLY,
@SerializedName("CUMULATIVE") @SerializedName("CUMULATIVE")
CUMULATIVE CUMULATIVE
} }

View File

@@ -19,5 +19,5 @@ data class GetDonationAllResponse(
@SerializedName("donationRankingPeriod") @SerializedName("donationRankingPeriod")
val donationRankingPeriod: DonationRankingPeriod? = null, val donationRankingPeriod: DonationRankingPeriod? = null,
@SerializedName("userDonationRanking") @SerializedName("userDonationRanking")
val userDonationRanking: List<UserDonationRankingResponse>, val userDonationRanking: List<UserDonationRankingResponse>
) )

View File

@@ -103,7 +103,7 @@ class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantal
viewModel.modifyCheers( viewModel.modifyCheers(
cheersId = cheersId, cheersId = cheersId,
creatorId = userId, creatorId = userId,
cheersContent = content, cheersContent = content
) )
} }
}, },

View File

@@ -13,7 +13,6 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityUserFollowerListBinding import kr.co.vividnext.sodalive.databinding.ActivityUserFollowerListBinding
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject

View File

@@ -1,8 +1,6 @@
package kr.co.vividnext.sodalive.following package kr.co.vividnext.sodalive.following
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
import kr.co.vividnext.sodalive.user.UserApi
class FollowingCreatorRepository(private val api: LiveRecommendApi) { class FollowingCreatorRepository(private val api: LiveRecommendApi) {
fun getFollowedCreatorAllList( fun getFollowedCreatorAllList(

View File

@@ -66,7 +66,6 @@ class CreatorRankingAdapter(
binding.tvFollow.text = context.getString(R.string.screen_home_following) binding.tvFollow.text = context.getString(R.string.screen_home_following)
binding.tvFollow.setBackgroundResource(R.drawable.bg_round_corner_999_455a64) binding.tvFollow.setBackgroundResource(R.drawable.bg_round_corner_999_455a64)
binding.tvFollow.setTextColor(context.getColor(R.color.white)) binding.tvFollow.setTextColor(context.getColor(R.color.white))
} else { } else {
binding.tvFollow.text = context.getString(R.string.screen_home_follow) binding.tvFollow.text = context.getString(R.string.screen_home_follow)
binding.tvFollow.setBackgroundResource(R.drawable.bg_round_corner_999_white) binding.tvFollow.setBackgroundResource(R.drawable.bg_round_corner_999_white)

View File

@@ -10,8 +10,8 @@ import kr.co.vividnext.sodalive.databinding.ItemDayOfWeekBinding
import java.util.Calendar import java.util.Calendar
class DayOfWeekAdapter( class DayOfWeekAdapter(
private val context: Context, context: Context,
private val onClickItem: (SeriesPublishedDaysOfWeek) -> Unit, private val onClickItem: (SeriesPublishedDaysOfWeek) -> Unit
) : RecyclerView.Adapter<DayOfWeekAdapter.ViewHolder>() { ) : RecyclerView.Adapter<DayOfWeekAdapter.ViewHolder>() {
inner class ViewHolder( inner class ViewHolder(
@@ -40,7 +40,7 @@ class DayOfWeekAdapter(
DayOfWeek(dayOfWeekStr = context.getString(R.string.day_fri_short), dayOfWeek = SeriesPublishedDaysOfWeek.FRI), DayOfWeek(dayOfWeekStr = context.getString(R.string.day_fri_short), dayOfWeek = SeriesPublishedDaysOfWeek.FRI),
DayOfWeek(dayOfWeekStr = context.getString(R.string.day_sat_short), dayOfWeek = SeriesPublishedDaysOfWeek.SAT), DayOfWeek(dayOfWeekStr = context.getString(R.string.day_sat_short), dayOfWeek = SeriesPublishedDaysOfWeek.SAT),
DayOfWeek(dayOfWeekStr = context.getString(R.string.day_sun_short), dayOfWeek = SeriesPublishedDaysOfWeek.SUN), DayOfWeek(dayOfWeekStr = context.getString(R.string.day_sun_short), dayOfWeek = SeriesPublishedDaysOfWeek.SUN),
DayOfWeek(dayOfWeekStr = context.getString(R.string.day_random), dayOfWeek = SeriesPublishedDaysOfWeek.RANDOM), DayOfWeek(dayOfWeekStr = context.getString(R.string.day_random), dayOfWeek = SeriesPublishedDaysOfWeek.RANDOM)
) )
// 요일 숫자에 맞춰 배열 // 요일 숫자에 맞춰 배열

View File

@@ -13,7 +13,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
class HomeContentAdapter( class HomeContentAdapter(
private val itemSquareSizePx: Int? = null, private val itemSquareSizePx: Int? = null,
private val onClickItem: (Long) -> Unit, private val onClickItem: (Long) -> Unit
) : RecyclerView.Adapter<HomeContentAdapter.ViewHolder>() { ) : RecyclerView.Adapter<HomeContentAdapter.ViewHolder>() {
private val items = mutableListOf<AudioContentMainItem>() private val items = mutableListOf<AudioContentMainItem>()

View File

@@ -149,7 +149,6 @@ class LiveViewModel(
fun getSummary() { fun getSummary() {
if (!_isLoading.value!!) { if (!_isLoading.value!!) {
if (SharedPreferenceManager.token.isNotBlank()) { if (SharedPreferenceManager.token.isNotBlank()) {
getFollowedChannelList() getFollowedChannelList()
getLatestPostListFromCreatorsYouFollow() getLatestPostListFromCreatorsYouFollow()

View File

@@ -1,38 +0,0 @@
package kr.co.vividnext.sodalive.live.event_banner
import android.content.Context
import android.widget.ImageView
import coil.load
import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.bannerview.BaseViewHolder
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.settings.event.EventItem
class EventBannerAdapter(
private val context: Context,
private val itemClick: (EventItem) -> Unit
) : BaseBannerAdapter<EventItem>() {
override fun bindData(
holder: BaseViewHolder<EventItem>,
data: EventItem,
position: Int,
pageSize: Int
) {
val ivThumbnail = holder.findViewById<ImageView>(R.id.iv_thumbnail)
ivThumbnail.load(data.thumbnailImageUrl) {
crossfade(true)
val layoutParams = ivThumbnail.layoutParams
val screenWidth = context.resources.displayMetrics.widthPixels
layoutParams.width = screenWidth
layoutParams.height = (screenWidth * 300) / 1000
ivThumbnail.layoutParams = layoutParams
}
ivThumbnail.setOnClickListener { itemClick(data) }
}
override fun getLayoutId(viewType: Int): Int {
return R.layout.item_event_slider
}
}

View File

@@ -14,7 +14,7 @@ import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.GetRoomListResponse import kr.co.vividnext.sodalive.live.GetRoomListResponse
class LiveNowAdapter( class LiveNowAdapter(
private val onClick: (GetRoomListResponse) -> Unit, private val onClick: (GetRoomListResponse) -> Unit
) : RecyclerView.Adapter<LiveNowAdapter.ViewHolder>() { ) : RecyclerView.Adapter<LiveNowAdapter.ViewHolder>() {
var items = mutableListOf<GetRoomListResponse>() var items = mutableListOf<GetRoomListResponse>()

View File

@@ -14,7 +14,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
class LiveRecommendChannelAdapter( class LiveRecommendChannelAdapter(
private val onClick: (Long) -> Unit, private val onClick: (Long) -> Unit,
private val onClickMore: () -> Unit, private val onClickMore: () -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items = mutableListOf<GetRecommendChannelResponse>() private val items = mutableListOf<GetRecommendChannelResponse>()

View File

@@ -15,5 +15,5 @@ data class GetLiveReservationResponse(
@SerializedName("price") val price: Int, @SerializedName("price") val price: Int,
@SerializedName("masterNickname") val masterNickname: String, @SerializedName("masterNickname") val masterNickname: String,
@SerializedName("beginDateTimeUtc") val beginDateTimeUtc: String, @SerializedName("beginDateTimeUtc") val beginDateTimeUtc: String,
@SerializedName("cancelable") val cancelable: Boolean, @SerializedName("cancelable") val cancelable: Boolean
) : Parcelable ) : Parcelable

View File

@@ -126,9 +126,7 @@ class LiveReservationCancelActivity : BaseActivity<ActivityLiveReservationCancel
binding.tvCancel.setOnClickListener { binding.tvCancel.setOnClickListener {
viewModel.cancelReservation { viewModel.cancelReservation {
if (binding.tvPrice.text == SodaLiveApplicationHolder.get() if (binding.tvPrice.text == SodaLiveApplicationHolder.get().getString(R.string.live_reservation_free)) {
.getString(R.string.live_reservation_free)
) {
binding.tvCancelComplete.visibility = View.GONE binding.tvCancelComplete.visibility = View.GONE
} else { } else {
binding.tvCancelComplete.visibility = View.VISIBLE binding.tvCancelComplete.visibility = View.VISIBLE

View File

@@ -6,10 +6,10 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load import coil.load
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemLiveReservationStatusBinding import kr.co.vividnext.sodalive.databinding.ItemLiveReservationStatusBinding
import kr.co.vividnext.sodalive.extensions.convertDateFormat import kr.co.vividnext.sodalive.extensions.convertDateFormat
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.settings.language.LanguageManager import kr.co.vividnext.sodalive.settings.language.LanguageManager
import kr.co.vividnext.sodalive.settings.language.LocaleHelper import kr.co.vividnext.sodalive.settings.language.LocaleHelper
import java.util.Locale import java.util.Locale
@@ -22,7 +22,7 @@ class LiveReservationStatusAdapter(
val items = mutableListOf<GetLiveReservationResponse>() val items = mutableListOf<GetLiveReservationResponse>()
inner class ViewHolder( inner class ViewHolder(
private val binding: ItemLiveReservationStatusBinding, private val binding: ItemLiveReservationStatusBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetLiveReservationResponse) { fun bind(item: GetLiveReservationResponse) {

View File

@@ -90,7 +90,6 @@ class LiveReservationStatusViewModel(
_isLoading.value = false _isLoading.value = false
}, },
{ {
_isLoading.value = false _isLoading.value = false
it.message?.let { message -> Logger.e(message) } it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue( _toastLiveData.postValue(

View File

@@ -3,7 +3,12 @@ package kr.co.vividnext.sodalive.live.room
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class GenderRestriction { enum class GenderRestriction {
@SerializedName("ALL") ALL, @SerializedName("ALL")
@SerializedName("MALE_ONLY") MALE_ONLY, ALL,
@SerializedName("FEMALE_ONLY") FEMALE_ONLY
@SerializedName("MALE_ONLY")
MALE_ONLY,
@SerializedName("FEMALE_ONLY")
FEMALE_ONLY
} }

View File

@@ -481,8 +481,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
context = this, context = this,
excludeGif = true, excludeGif = true,
config = ImagePickerCropper.Config( config = ImagePickerCropper.Config(
aspectX = 2f, aspectY = 3.8f, aspectX = 2f,
maxWidth = 1080, maxHeight = 2052, aspectY = 3.8f,
maxWidth = 1080,
maxHeight = 2052,
compressFormat = Bitmap.CompressFormat.JPEG, compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90 compressQuality = 90
), ),
@@ -640,7 +642,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
userId, userId,
nickname, nickname,
isBlock, isBlock,
view, view
) )
} }
) )
@@ -1208,7 +1210,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl) roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl)
roomInfoEditDialog.setMenuPreset(it) roomInfoEditDialog.setMenuPreset(it)
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageFile, isActivateMenu, menuId, menu, isAdult, isEntryMessageEnabled -> roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageFile,
isActivateMenu, menuId, menu, isAdult, isEntryMessageEnabled ->
if (isEntryMessageEnabled != null) { if (isEntryMessageEnabled != null) {
this.isEntryMessageEnabled = isEntryMessageEnabled this.isEntryMessageEnabled = isEntryMessageEnabled
} }
@@ -1337,7 +1340,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
hasInvokedJoinChannel = true hasInvokedJoinChannel = true
joinChannel(response) joinChannel(response)
} else { } else {
Logger.e("joinChannel - skip (rtcConnected=$rtcConnected, rtmLoggedIn=$rtmLoggedIn, hasInvokedJoinChannel=$hasInvokedJoinChannel)") Logger.e(
"joinChannel - skip (rtcConnected=$rtcConnected, " +
"rtmLoggedIn=$rtmLoggedIn, hasInvokedJoinChannel=$hasInvokedJoinChannel)"
)
} }
} }
@@ -3027,8 +3033,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val elapsed = System.currentTimeMillis() - pressStartTime val elapsed = System.currentTimeMillis() - pressStartTime
// 경과 시간 기준으로 물 채우기(progress) 계산 (0..100) // 경과 시간 기준으로 물 채우기(progress) 계산 (0..100)
val progressFraction = (elapsed.coerceAtMost(longPressDurationMs) val progressFraction = (
.toFloat() / longPressDurationMs.toFloat()) elapsed.coerceAtMost(longPressDurationMs)
.toFloat() / longPressDurationMs.toFloat()
)
val progress = (progressFraction * 100f).toInt() val progress = (progressFraction * 100f).toInt()
longPressCenterHeart?.let { heartView -> longPressCenterHeart?.let { heartView ->
try { try {
@@ -3131,8 +3139,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
heart.setFrontWaveColor("#ff959a".toColorInt()) heart.setFrontWaveColor("#ff959a".toColorInt())
heart.setBehindWaveColor("#ff959a".toColorInt()) heart.setBehindWaveColor("#ff959a".toColorInt())
val elapsed = System.currentTimeMillis() - pressStartTime val elapsed = System.currentTimeMillis() - pressStartTime
val progress = ((elapsed.coerceAtMost(longPressDurationMs) val progress = (
.toFloat() / longPressDurationMs.toFloat()) * 100f).toInt() (
elapsed.coerceAtMost(longPressDurationMs).toFloat() / longPressDurationMs.toFloat()
) * 100f
).toInt()
try { try {
heart.progress = progress heart.progress = progress
} catch (_: Throwable) { } catch (_: Throwable) {
@@ -3589,14 +3600,20 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val s = 0.9f val s = 0.9f
moveTo(0f, -0.45f * s) moveTo(0f, -0.45f * s)
cubicTo( cubicTo(
0.62f * s, -1.02f * s, 0.62f * s,
1.22f * s, -0.04f * s, -1.02f * s,
0f, 0.65f * s 1.22f * s,
-0.04f * s,
0f,
0.65f * s
) )
cubicTo( cubicTo(
-1.22f * s, -0.04f * s, -1.22f * s,
-0.62f * s, -1.02f * s, -0.04f * s,
0f, -0.45f * s -0.62f * s,
-1.02f * s,
0f,
-0.45f * s
) )
close() close()
} }
@@ -3784,14 +3801,20 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val s = 0.9f val s = 0.9f
moveTo(0f, -0.45f * s) moveTo(0f, -0.45f * s)
cubicTo( cubicTo(
0.62f * s, -1.02f * s, 0.62f * s,
1.22f * s, -0.04f * s, -1.02f * s,
0f, 0.65f * s 1.22f * s,
-0.04f * s,
0f,
0.65f * s
) )
cubicTo( cubicTo(
-1.22f * s, -0.04f * s, -1.22f * s,
-0.62f * s, -1.02f * s, -0.04f * s,
0f, -0.45f * s -0.62f * s,
-1.02f * s,
0f,
-0.45f * s
) )
close() close()
} }
@@ -3899,14 +3922,20 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val s = 0.9f val s = 0.9f
moveTo(0f, -0.45f * s) moveTo(0f, -0.45f * s)
cubicTo( cubicTo(
0.62f * s, -1.02f * s, 0.62f * s,
1.22f * s, -0.04f * s, -1.02f * s,
0f, 0.65f * s 1.22f * s,
-0.04f * s,
0f,
0.65f * s
) )
cubicTo( cubicTo(
-1.22f * s, -0.04f * s, -1.22f * s,
-0.62f * s, -1.02f * s, -0.04f * s,
0f, -0.45f * s -0.62f * s,
-1.02f * s,
0f,
-0.45f * s
) )
close() close()
} }
@@ -3946,7 +3975,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
if (rotateEnabled) 300f * Math.random().toFloat() else 0f // deg/s if (rotateEnabled) 300f * Math.random().toFloat() else 0f // deg/s
val rotation0 = (-180f + 360f * Math.random().toFloat()) val rotation0 = (-180f + 360f * Math.random().toFloat())
val fadeStartRatio = 0.80f + 0.15f * Math.random().toFloat() // 0.80..0.95 val fadeStartRatio = 0.80f + 0.15f * Math.random().toFloat() // 0.80..0.95
val fadeStartY = h * fadeStartRatio val fadeStartY = h * fadeStartRatio
@@ -3991,7 +4019,9 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val fadeAlpha = if (y >= d.fadeStartY) { val fadeAlpha = if (y >= d.fadeStartY) {
val denom = (h - d.fadeStartY).coerceAtLeast(1f) val denom = (h - d.fadeStartY).coerceAtLeast(1f)
(1f - (y - d.fadeStartY) / denom).coerceIn(0f, 1f) (1f - (y - d.fadeStartY) / denom).coerceIn(0f, 1f)
} else 1f } else {
1f
}
val alpha = fadeAlpha.coerceIn(0f, 1f) val alpha = fadeAlpha.coerceIn(0f, 1f)
paint.alpha = (alpha * 255).toInt().coerceIn(0, 255) paint.alpha = (alpha * 255).toInt().coerceIn(0, 255)
@@ -4139,7 +4169,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
return false return false
} }
}) })
.into(binding.ivSignature) .into(binding.ivSignature)
} }
@@ -4205,7 +4234,6 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
} }
} }
} else { } else {
binding.flRoulette.visibility = View.GONE binding.flRoulette.visibility = View.GONE
} }
@@ -4221,7 +4249,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
type = LiveRoomChatRawMessageType.ROULETTE_DONATION, type = LiveRoomChatRawMessageType.ROULETTE_DONATION,
message = randomItem, message = randomItem,
can = can, can = can,
donationMessage = "", donationMessage = ""
) )
) )
@@ -4269,7 +4297,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
.subscribe( .subscribe(
{ response -> { response ->
Logger.e("성공: $response") Logger.e("성공: $response")
}, { error -> },
{ error ->
Logger.e("실패: ${error.message}") Logger.e("실패: ${error.message}")
} }
) )

View File

@@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.live.room
import android.app.Activity import android.app.Activity
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -10,12 +9,13 @@ import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.graphics.drawable.toDrawable
import kr.co.vividnext.sodalive.databinding.DialogLiveRoomBinding import kr.co.vividnext.sodalive.databinding.DialogLiveRoomBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
class LiveRoomDialog( class LiveRoomDialog(
activity: Activity, activity: Activity,
layoutInflater: LayoutInflater, layoutInflater: LayoutInflater
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
@@ -27,7 +27,7 @@ class LiveRoomDialog(
dialogBuilder.setView(dialogView.root) dialogBuilder.setView(dialogView.root)
alertDialog = dialogBuilder.create() alertDialog = dialogBuilder.create()
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) alertDialog.window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
} }
fun show(width: Int) { fun show(width: Int) {

View File

@@ -2,10 +2,10 @@ package kr.co.vividnext.sodalive.live.room
import android.app.Activity import android.app.Activity
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.graphics.drawable.toDrawable
import coil.load import coil.load
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
@@ -17,7 +17,7 @@ class LiveRoomNoChattingDialog(
layoutInflater: LayoutInflater, layoutInflater: LayoutInflater,
nickname: String, nickname: String,
profileUrl: String, profileUrl: String,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
@@ -30,7 +30,7 @@ class LiveRoomNoChattingDialog(
alertDialog = dialogBuilder.create() alertDialog = dialogBuilder.create()
alertDialog.setCancelable(false) alertDialog.setCancelable(false)
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) alertDialog.window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
dialogView.tvCancel.setOnClickListener { dialogView.tvCancel.setOnClickListener {
alertDialog.dismiss() alertDialog.dismiss()

View File

@@ -3,10 +3,21 @@ package kr.co.vividnext.sodalive.live.room
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class LiveRoomRequestType { enum class LiveRoomRequestType {
@SerializedName("INVITE_SPEAKER") INVITE_SPEAKER, @SerializedName("INVITE_SPEAKER")
@SerializedName("CHANGE_LISTENER") CHANGE_LISTENER, INVITE_SPEAKER,
@SerializedName("KICK_OUT") KICK_OUT,
@SerializedName("SET_MANAGER") SET_MANAGER, @SerializedName("CHANGE_LISTENER")
@SerializedName("RELEASE_MANAGER") RELEASE_MANAGER, CHANGE_LISTENER,
@SerializedName("NO_CHATTING") NO_CHATTING,
@SerializedName("KICK_OUT")
KICK_OUT,
@SerializedName("SET_MANAGER")
SET_MANAGER,
@SerializedName("RELEASE_MANAGER")
RELEASE_MANAGER,
@SerializedName("NO_CHATTING")
NO_CHATTING
} }

View File

@@ -3,6 +3,9 @@ package kr.co.vividnext.sodalive.live.room
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class LiveRoomStatus { enum class LiveRoomStatus {
@SerializedName("NOW") NOW, @SerializedName("NOW")
@SerializedName("RESERVATION") RESERVATION NOW,
@SerializedName("RESERVATION")
RESERVATION
} }

View File

@@ -3,6 +3,9 @@ package kr.co.vividnext.sodalive.live.room
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class LiveRoomType { enum class LiveRoomType {
@SerializedName("OPEN") OPEN, @SerializedName("OPEN")
@SerializedName("PRIVATE") PRIVATE, OPEN,
@SerializedName("PRIVATE")
PRIVATE
} }

View File

@@ -7,5 +7,5 @@ import java.util.TimeZone
@Keep @Keep
data class StartLiveRequest( data class StartLiveRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("timezone") val timezone: String = TimeZone.getDefault().id, @SerializedName("timezone") val timezone: String = TimeZone.getDefault().id
) )

View File

@@ -61,7 +61,7 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
"%d-%02d-%02d", "%d-%02d-%02d",
year, year,
monthOfYear + 1, monthOfYear + 1,
dayOfMonth, dayOfMonth
) )
viewModel.setReservationDate( viewModel.setReservationDate(
String.format( String.format(
@@ -136,8 +136,10 @@ class LiveRoomCreateActivity : BaseActivity<ActivityLiveRoomCreateBinding>(
context = this, context = this,
excludeGif = true, excludeGif = true,
config = ImagePickerCropper.Config( config = ImagePickerCropper.Config(
aspectX = 2f, aspectY = 3.8f, aspectX = 2f,
maxWidth = 1080, maxHeight = 2052, aspectY = 3.8f,
maxWidth = 1080,
maxHeight = 2052,
compressFormat = Bitmap.CompressFormat.JPEG, compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90 compressQuality = 90
), ),

View File

@@ -1,12 +1,12 @@
package kr.co.vividnext.sodalive.live.room.create package kr.co.vividnext.sodalive.live.room.create
import android.net.Uri
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.google.gson.Gson import com.google.gson.Gson
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.UiText import kr.co.vividnext.sodalive.common.UiText
@@ -16,7 +16,6 @@ import kr.co.vividnext.sodalive.live.LiveRepository
import kr.co.vividnext.sodalive.live.room.GenderRestriction import kr.co.vividnext.sodalive.live.room.GenderRestriction
import kr.co.vividnext.sodalive.live.room.LiveRoomType import kr.co.vividnext.sodalive.live.room.LiveRoomType
import kr.co.vividnext.sodalive.live.room.menu.GetMenuPresetResponse import kr.co.vividnext.sodalive.live.room.menu.GetMenuPresetResponse
import kr.co.vividnext.sodalive.R
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.asRequestBody

View File

@@ -20,7 +20,7 @@ class LiveCancelDialog(
confirmButtonTitle: String, confirmButtonTitle: String,
confirmButtonClick: (String) -> Unit, confirmButtonClick: (String) -> Unit,
cancelButtonTitle: String = "", cancelButtonTitle: String = "",
cancelButtonClick: (() -> Unit)? = null, cancelButtonClick: (() -> Unit)? = null
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
private val dialogView = DialogLiveInputBinding.inflate(layoutInflater) private val dialogView = DialogLiveInputBinding.inflate(layoutInflater)

View File

@@ -21,7 +21,7 @@ class LivePaymentDialog(
confirmButtonTitle: String, confirmButtonTitle: String,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit,
cancelButtonTitle: String = "", cancelButtonTitle: String = "",
cancelButtonClick: (() -> Unit)? = null, cancelButtonClick: (() -> Unit)? = null
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
private val dialogView = DialogLivePaymentBinding.inflate(layoutInflater) private val dialogView = DialogLivePaymentBinding.inflate(layoutInflater)

View File

@@ -20,7 +20,7 @@ class LiveRoomPasswordDialog(
activity: Activity, activity: Activity,
layoutInflater: LayoutInflater, layoutInflater: LayoutInflater,
can: Int, can: Int,
confirmButtonClick: (String) -> Unit, confirmButtonClick: (String) -> Unit
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog

View File

@@ -7,5 +7,5 @@ import com.google.gson.annotations.SerializedName
data class LiveRoomLikeHeartRequest( data class LiveRoomLikeHeartRequest(
@SerializedName("roomId") val roomId: Long, @SerializedName("roomId") val roomId: Long,
@SerializedName("container") val container: String, @SerializedName("container") val container: String,
@SerializedName("heartCount") val heartCount: Int = 1, @SerializedName("heartCount") val heartCount: Int = 1
) )

View File

@@ -15,7 +15,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityMenuConfigBinding import kr.co.vividnext.sodalive.databinding.ActivityMenuConfigBinding
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel

View File

@@ -195,19 +195,19 @@ abstract class LiveRoomProfileViewHolder(binding: ViewBinding) :
} }
class LiveRoomProfileSpeakerTitleViewHolder( class LiveRoomProfileSpeakerTitleViewHolder(
private val binding: ItemLiveRoomProfileHeaderBinding, private val binding: ItemLiveRoomProfileHeaderBinding
) : LiveRoomProfileViewHolder(binding) { ) : LiveRoomProfileViewHolder(binding) {
override fun bind(item: LiveRoomProfileItem) = item.bind(binding) override fun bind(item: LiveRoomProfileItem) = item.bind(binding)
} }
class LiveRoomProfileListenerTitleViewHolder( class LiveRoomProfileListenerTitleViewHolder(
private val binding: ItemLiveRoomProfileHeaderBinding, private val binding: ItemLiveRoomProfileHeaderBinding
) : LiveRoomProfileViewHolder(binding) { ) : LiveRoomProfileViewHolder(binding) {
override fun bind(item: LiveRoomProfileItem) = item.bind(binding) override fun bind(item: LiveRoomProfileItem) = item.bind(binding)
} }
class LiveRoomProfileManagerTitleViewHolder( class LiveRoomProfileManagerTitleViewHolder(
private val binding: ItemLiveRoomProfileHeaderBinding, private val binding: ItemLiveRoomProfileHeaderBinding
) : LiveRoomProfileViewHolder(binding) { ) : LiveRoomProfileViewHolder(binding) {
override fun bind(item: LiveRoomProfileItem) = item.bind(binding) override fun bind(item: LiveRoomProfileItem) = item.bind(binding)
} }

View File

@@ -28,7 +28,7 @@ class LiveRoomUserProfileDialog(
private val onClickChangeListener: (Long) -> Unit, private val onClickChangeListener: (Long) -> Unit,
private val onClickKickOut: (Long) -> Unit, private val onClickKickOut: (Long) -> Unit,
private val onClickNoChatting: (Long, String, String) -> Unit, private val onClickNoChatting: (Long, String, String) -> Unit,
private val onClickPopupMenu: (Long, String, Boolean, View) -> Unit, private val onClickPopupMenu: (Long, String, Boolean, View) -> Unit
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
private val dialogView = DialogLiveRoomUserProfileBinding.inflate(layoutInflater) private val dialogView = DialogLiveRoomUserProfileBinding.inflate(layoutInflater)

View File

@@ -24,8 +24,6 @@ class LiveTagFragment(
private val selectedTags: Set<String>, private val selectedTags: Set<String>,
private val onItemClick: (String, Boolean) -> Boolean private val onItemClick: (String, Boolean) -> Boolean
) : BottomSheetDialogFragment() { ) : BottomSheetDialogFragment() {
private val viewModel: LiveTagViewModel by inject() private val viewModel: LiveTagViewModel by inject()
private lateinit var adapter: LiveTagAdapter private lateinit var adapter: LiveTagAdapter

View File

@@ -190,12 +190,12 @@ class LiveRoomEditViewModel(
beginDate = date.convertDateFormat( beginDate = date.convertDateFormat(
from = "yyyy.MM.dd", from = "yyyy.MM.dd",
to = "yyyy-MM-dd", to = "yyyy-MM-dd"
) )
beginTime = time.convertDateFormat( beginTime = time.convertDateFormat(
from = "a hh:mm", from = "a hh:mm",
to = "HH:mm", to = "HH:mm"
) )
beginDateTimeStr = "$beginDate $beginTime" beginDateTimeStr = "$beginDate $beginTime"

View File

@@ -132,9 +132,12 @@ class RouletteView @JvmOverloads constructor(
val targetAngle = 0 - (getAngleForOption(option) + 360 * 10) val targetAngle = 0 - (getAngleForOption(option) + 360 * 10)
val rotateAnimation = RotateAnimation( val rotateAnimation = RotateAnimation(
0f, targetAngle, 0f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f, targetAngle,
RotateAnimation.RELATIVE_TO_SELF, 0.5f RotateAnimation.RELATIVE_TO_SELF,
0.5f,
RotateAnimation.RELATIVE_TO_SELF,
0.5f
) )
rotateAnimation.duration = 2000 rotateAnimation.duration = 2000
rotateAnimation.fillAfter = true rotateAnimation.fillAfter = true

View File

@@ -67,15 +67,17 @@ class RouletteConfigActivity : BaseActivity<ActivityRouletteConfigBinding>(
Service.INPUT_METHOD_SERVICE Service.INPUT_METHOD_SERVICE
) as InputMethodManager ) as InputMethodManager
binding.etSetPrice.filters = arrayOf(InputFilter { source, start, end, _, _, _ -> binding.etSetPrice.filters = arrayOf(
// Only allow numeric input InputFilter { source, start, end, _, _, _ ->
for (i in start until end) { // Only allow numeric input
if (!Character.isDigit(source[i])) { for (i in start until end) {
return@InputFilter "" if (!Character.isDigit(source[i])) {
return@InputFilter ""
}
} }
null
} }
null )
})
binding.ivRouletteIsActive.setOnClickListener { viewModel.toggleIsActive() } binding.ivRouletteIsActive.setOnClickListener { viewModel.toggleIsActive() }
binding.ivAddOption.setOnClickListener { addOption() } binding.ivAddOption.setOnClickListener { addOption() }

View File

@@ -5,19 +5,22 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.localbroadcastmanager.content.LocalBroadcastManager
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailActivity
import kr.co.vividnext.sodalive.app.SodaLiveApp import kr.co.vividnext.sodalive.app.SodaLiveApp
import kr.co.vividnext.sodalive.audition.AuditionActivity import kr.co.vividnext.sodalive.audition.AuditionActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.message.MessageActivity import kr.co.vividnext.sodalive.message.MessageActivity
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentActivity
import kr.co.vividnext.sodalive.splash.SplashActivity import kr.co.vividnext.sodalive.splash.SplashActivity
import kr.co.vividnext.sodalive.v2.creator.channel.CreatorChannelActivity import kr.co.vividnext.sodalive.v2.chat.action.ChatActionCommand
import kr.co.vividnext.sodalive.v2.chat.action.handleChatAction
import kr.co.vividnext.sodalive.v2.community.action.CommunityActionCommand
import kr.co.vividnext.sodalive.v2.community.action.handleCommunityAction
import kr.co.vividnext.sodalive.v2.content.action.ContentActionCommand
import kr.co.vividnext.sodalive.v2.content.action.handleContentAction
import kr.co.vividnext.sodalive.v2.creator.action.CreatorActionCommand
import kr.co.vividnext.sodalive.v2.creator.action.handleCreatorAction
import kr.co.vividnext.sodalive.v2.main.MainV2Activity import kr.co.vividnext.sodalive.v2.main.MainV2Activity
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
import java.util.Locale import java.util.Locale
class DeepLinkActivity : AppCompatActivity() { class DeepLinkActivity : AppCompatActivity() {
@@ -276,7 +279,7 @@ class DeepLinkActivity : AppCompatActivity() {
?: bundle.getLong(Constants.EXTRA_COMMUNITY_POST_ID).takeIf { it > 0 } ?: bundle.getLong(Constants.EXTRA_COMMUNITY_POST_ID).takeIf { it > 0 }
if (isDmChatDeepLink(bundle) && roomId != null && roomId > 0) { if (isDmChatDeepLink(bundle) && roomId != null && roomId > 0) {
startActivity(DmChatRoomActivity.newIntentByRoomId(applicationContext, roomId)) handleChatAction(ChatActionCommand.DmRoom(roomId))
return true return true
} }
@@ -286,36 +289,29 @@ class DeepLinkActivity : AppCompatActivity() {
return true return true
} }
communityPostId != null && communityPostId > 0 -> {
handleCommunityAction(CommunityActionCommand.PostDetail(communityPostId))
return true
}
channelId != null && channelId > 0 -> { channelId != null && channelId > 0 -> {
startActivity( handleCreatorAction(CreatorActionCommand.Profile(channelId))
CreatorChannelActivity.newIntent(applicationContext, channelId)
)
return true return true
} }
contentId != null && contentId > 0 -> { contentId != null && contentId > 0 -> {
startActivity( handleContentAction(ContentActionCommand.AudioDetail(contentId))
Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, contentId)
}
)
return true return true
} }
messageId != null && messageId > 0 -> { messageId != null && messageId > 0 -> {
// messageId는 DM room ID가 아니므로 과거 알림 수신 호환만 유지한다.
startActivity(Intent(applicationContext, MessageActivity::class.java)) startActivity(Intent(applicationContext, MessageActivity::class.java))
return true return true
} }
communityCreatorId != null && communityCreatorId > 0 -> { communityCreatorId != null && communityCreatorId > 0 -> {
startActivity( handleCreatorAction(CreatorActionCommand.Profile(communityCreatorId))
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply {
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, communityCreatorId)
if (communityPostId != null && communityPostId > 0) {
putExtra(Constants.EXTRA_COMMUNITY_POST_ID, communityPostId)
}
}
)
return true return true
} }
@@ -345,11 +341,7 @@ class DeepLinkActivity : AppCompatActivity() {
return false return false
} }
startActivity( handleContentAction(ContentActionCommand.SeriesDetail(deepLinkValueId))
Intent(applicationContext, SeriesDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_SERIES_ID, deepLinkValueId)
}
)
true true
} }
@@ -358,11 +350,7 @@ class DeepLinkActivity : AppCompatActivity() {
return false return false
} }
startActivity( handleContentAction(ContentActionCommand.AudioDetail(deepLinkValueId))
Intent(applicationContext, AudioContentDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, deepLinkValueId)
}
)
true true
} }
@@ -371,9 +359,7 @@ class DeepLinkActivity : AppCompatActivity() {
return false return false
} }
startActivity( handleCreatorAction(CreatorActionCommand.Profile(deepLinkValueId))
CreatorChannelActivity.newIntent(applicationContext, deepLinkValueId)
)
true true
} }
@@ -391,15 +377,13 @@ class DeepLinkActivity : AppCompatActivity() {
return false return false
} }
startActivity( // deepLinkValueId는 legacy creatorId이며 postId는 routeForegroundDeepLink에서 먼저 처리한다.
Intent(applicationContext, CreatorCommunityAllActivity::class.java).apply { handleCreatorAction(CreatorActionCommand.Profile(deepLinkValueId))
putExtra(Constants.EXTRA_COMMUNITY_CREATOR_ID, deepLinkValueId)
}
)
true true
} }
"message" -> { "message" -> {
// 현재 DM은 chat/{roomId} 계약을 사용하며 message는 legacy fallback이다.
startActivity(Intent(applicationContext, MessageActivity::class.java)) startActivity(Intent(applicationContext, MessageActivity::class.java))
true true
} }

View File

@@ -5,8 +5,8 @@ import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.ToastMessage import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.mypage.auth.AuthRepository import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
@@ -15,7 +15,6 @@ import kr.co.vividnext.sodalive.settings.ContentType
import kr.co.vividnext.sodalive.settings.notice.NoticeItem import kr.co.vividnext.sodalive.settings.notice.NoticeItem
import kr.co.vividnext.sodalive.settings.notice.NoticeRepository import kr.co.vividnext.sodalive.settings.notice.NoticeRepository
import kr.co.vividnext.sodalive.user.UserRepository import kr.co.vividnext.sodalive.user.UserRepository
import kr.co.vividnext.sodalive.R
class MyPageViewModel( class MyPageViewModel(
private val userRepository: UserRepository, private val userRepository: UserRepository,

View File

@@ -11,7 +11,6 @@ import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import com.orhanobut.logger.Logger
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
@@ -211,7 +210,7 @@ class AddAlarmActivity : BaseActivity<ActivityAddAlarmBinding>(
contentTitle = selectedContentTitle, contentTitle = selectedContentTitle,
contentCreatorNickname = selectedContentCreatorNickname, contentCreatorNickname = selectedContentCreatorNickname,
volume = binding.sbVolume.progress, volume = binding.sbVolume.progress,
days = selectedDays.toList(), days = selectedDays.toList()
) )
if (alarmId > 0) { if (alarmId > 0) {

View File

@@ -95,7 +95,7 @@ class AlarmActivity : BaseActivity<ActivityAlarmBinding>(
} }
private fun getContent(contentId: Long) { private fun getContent(contentId: Long) {
contentViewModel.getAudioContentDetail(contentId, {},) contentViewModel.getAudioContentDetail(contentId) {}
} }
private fun bindData() { private fun bindData() {

View File

@@ -5,7 +5,6 @@ import android.annotation.SuppressLint
import android.app.AlarmManager import android.app.AlarmManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
@@ -15,7 +14,7 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.NotificationManagerCompat import androidx.core.net.toUri
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.gun0912.tedpermission.PermissionListener import com.gun0912.tedpermission.PermissionListener
import com.gun0912.tedpermission.normal.TedPermission import com.gun0912.tedpermission.normal.TedPermission
@@ -28,7 +27,6 @@ import kr.co.vividnext.sodalive.databinding.ActivityAlarmListBinding
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.mypage.alarm.db.Alarm import kr.co.vividnext.sodalive.mypage.alarm.db.Alarm
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import androidx.core.net.toUri
class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>( class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>(
ActivityAlarmListBinding::inflate ActivityAlarmListBinding::inflate
@@ -156,7 +154,6 @@ class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>(
binding.tvEmptyAlarms.visibility = binding.tvEmptyAlarms.visibility =
if (it.isEmpty()) View.VISIBLE else View.GONE if (it.isEmpty()) View.VISIBLE else View.GONE
viewModel.getSlotQuantityAndPrice() viewModel.getSlotQuantityAndPrice()
} }
} }
@@ -236,7 +233,7 @@ class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>(
).show() ).show()
adapterRefresh() adapterRefresh()
}, },
cancelButtonTitle = getString(R.string.cancel), cancelButtonTitle = getString(R.string.cancel)
).show(screenWidth) ).show(screenWidth)
} }
@@ -248,7 +245,7 @@ class AlarmListActivity : BaseActivity<ActivityAlarmListBinding>(
desc = getString(R.string.alarm_list_buy_desc), desc = getString(R.string.alarm_list_buy_desc),
confirmButtonTitle = getString(R.string.alarm_list_buy_confirm), confirmButtonTitle = getString(R.string.alarm_list_buy_confirm),
confirmButtonClick = { viewModel.buyExtraSlot() }, confirmButtonClick = { viewModel.buyExtraSlot() },
cancelButtonTitle = getString(R.string.cancel), cancelButtonTitle = getString(R.string.cancel)
).show(screenWidth) ).show(screenWidth)
} }
} }

View File

@@ -1,14 +1,12 @@
package kr.co.vividnext.sodalive.mypage.alarm.select_audio_content package kr.co.vividnext.sodalive.mypage.alarm.select_audio_content
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load import coil.load
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListItem
import kr.co.vividnext.sodalive.audio_content.order.OrderType
import kr.co.vividnext.sodalive.databinding.ItemAudioContentOrderListBinding import kr.co.vividnext.sodalive.databinding.ItemAudioContentOrderListBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat

View File

@@ -15,6 +15,6 @@ data class BootpayResponse(
@SerializedName("receipt_id") @SerializedName("receipt_id")
val receiptId: String, val receiptId: String,
@SerializedName("order_id") @SerializedName("order_id")
val orderId: String, val orderId: String
) )
} }

View File

@@ -98,12 +98,10 @@ class BlockMemberActivity : BaseActivity<ActivityBlockMemberBinding>(
} }
viewModel.blockedMemberTotalCountLiveData.observe(this) { viewModel.blockedMemberTotalCountLiveData.observe(this) {
binding.tvTotalCount.text = " ${ binding.tvTotalCount.text = getString(
getString( R.string.screen_block_member_total_count,
R.string.screen_block_member_total_count, it
it )
)
} "
if (it > 0) { if (it > 0) {
binding.tvNone.visibility = View.GONE binding.tvNone.visibility = View.GONE

View File

@@ -7,10 +7,10 @@ import com.android.billingclient.api.Purchase
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.mypage.can.CanRepository import kr.co.vividnext.sodalive.mypage.can.CanRepository
class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewModel() { class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewModel() {
@@ -38,8 +38,8 @@ class CanChargeIapViewModel(private val repository: CanRepository) : BaseViewMod
title = title, title = title,
chargeCan = selectedProductDetails.description.toInt(), chargeCan = selectedProductDetails.description.toInt(),
price = ( price = (
selectedProductDetails.oneTimePurchaseOfferDetails?.priceAmountMicros selectedProductDetails.oneTimePurchaseOfferDetails?.priceAmountMicros ?: 0L
?: 0L).toDouble() / 1000000, ).toDouble() / 1000000,
currencyCode = selectedProductDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode currencyCode = selectedProductDetails.oneTimePurchaseOfferDetails?.priceCurrencyCode
?: "KRW", ?: "KRW",
productId = purchase.products[0], productId = purchase.products[0],

View File

@@ -3,13 +3,12 @@ package kr.co.vividnext.sodalive.mypage.can.coupon
import android.os.Bundle import android.os.Bundle
import android.text.InputFilter import android.text.InputFilter
import android.widget.Toast import android.widget.Toast
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.R 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.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityCanCouponBinding import kr.co.vividnext.sodalive.databinding.ActivityCanCouponBinding
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
class CanCouponActivity : BaseActivity<ActivityCanCouponBinding>( class CanCouponActivity : BaseActivity<ActivityCanCouponBinding>(
ActivityCanCouponBinding::inflate ActivityCanCouponBinding::inflate
) { ) {

View File

@@ -5,10 +5,10 @@ import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.ToastMessage
import kr.co.vividnext.sodalive.mypage.can.CanRepository import kr.co.vividnext.sodalive.mypage.can.CanRepository
class CanCouponViewModel(private val repository: CanRepository) : BaseViewModel() { class CanCouponViewModel(private val repository: CanRepository) : BaseViewModel() {
@@ -49,7 +49,6 @@ class CanCouponViewModel(private val repository: CanRepository) : BaseViewModel(
_toastLiveData.value = it.message?.let { message -> _toastLiveData.value = it.message?.let { message ->
ToastMessage(message = message) ToastMessage(message = message)
} ?: ToastMessage(resId = R.string.msg_can_coupon_unknown_error) } ?: ToastMessage(resId = R.string.msg_can_coupon_unknown_error)
} }
) )
) )

View File

@@ -3,6 +3,9 @@ package kr.co.vividnext.sodalive.mypage.can.payment
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
enum class PaymentGateway { enum class PaymentGateway {
@SerializedName("PG") PG, @SerializedName("PG")
@SerializedName("GOOGLE_IAP") GOOGLE_IAP PG,
@SerializedName("GOOGLE_IAP")
GOOGLE_IAP
} }

View File

@@ -220,7 +220,8 @@ class ProfileUpdateActivity : BaseActivity<ActivityProfileUpdateBinding>(
excludeGif = true, excludeGif = true,
isEnabledFreeStyleCrop = false, isEnabledFreeStyleCrop = false,
config = ImagePickerCropper.Config( config = ImagePickerCropper.Config(
aspectX = 1f, aspectY = 1f, aspectX = 1f,
aspectY = 1f,
compressFormat = Bitmap.CompressFormat.JPEG, compressFormat = Bitmap.CompressFormat.JPEG,
compressQuality = 90 compressQuality = 90
), ),

View File

@@ -212,8 +212,10 @@ class ProfileUpdateViewModel(private val repository: UserRepository) : BaseViewM
} }
) )
) )
} else run { } else {
onSuccess() run {
onSuccess()
}
} }
} }

View File

@@ -68,28 +68,28 @@ class NicknameUpdateViewModel(private val repository: UserRepository) : BaseView
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ {
_isLoading.value = false _isLoading.value = false
if (it.success) { if (it.success) {
isCheckedNickname = true isCheckedNickname = true
_toastLiveData.postValue( _toastLiveData.postValue(
ToastMessage(resId = R.string.msg_nickname_update_available) ToastMessage(resId = R.string.msg_nickname_update_available)
) )
} else { } else {
_toastLiveData.postValue( _toastLiveData.postValue(
it.message?.let { message -> it.message?.let { message ->
ToastMessage(message = message) ToastMessage(message = message)
} ?: ToastMessage(resId = R.string.common_error_unknown) } ?: ToastMessage(resId = R.string.common_error_unknown)
) )
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(ToastMessage(resId = R.string.common_error_unknown))
} }
}, )
{ )
_isLoading.value = false } else {
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(ToastMessage(resId = R.string.common_error_unknown))
}
)
)
} else {
_toastLiveData.postValue( _toastLiveData.postValue(
ToastMessage(resId = R.string.msg_nickname_update_input_required) ToastMessage(resId = R.string.msg_nickname_update_input_required)
) )
@@ -111,29 +111,29 @@ class NicknameUpdateViewModel(private val repository: UserRepository) : BaseView
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe( .subscribe(
{ {
_isLoading.value = false _isLoading.value = false
if (it.success) { if (it.success) {
_toastLiveData.postValue( _toastLiveData.postValue(
ToastMessage(resId = R.string.msg_nickname_update_success) ToastMessage(resId = R.string.msg_nickname_update_success)
) )
SharedPreferenceManager.nickname = nickname SharedPreferenceManager.nickname = nickname
onSuccess() onSuccess()
} else { } else {
_toastLiveData.postValue( _toastLiveData.postValue(
it.message?.let { message -> it.message?.let { message ->
ToastMessage(message = message) ToastMessage(message = message)
} ?: ToastMessage(resId = R.string.common_error_unknown) } ?: ToastMessage(resId = R.string.common_error_unknown)
) )
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(ToastMessage(resId = R.string.common_error_unknown))
} }
}, )
{ )
_isLoading.value = false } else {
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(ToastMessage(resId = R.string.common_error_unknown))
}
)
)
} else {
_toastLiveData.postValue( _toastLiveData.postValue(
ToastMessage(resId = R.string.msg_nickname_update_check_required) ToastMessage(resId = R.string.msg_nickname_update_check_required)
) )

View File

@@ -20,7 +20,9 @@ interface RecentContentDao {
@Query("SELECT COUNT(*) FROM recent_contents") @Query("SELECT COUNT(*) FROM recent_contents")
fun getCount(): Flow<Int> fun getCount(): Flow<Int>
@Query("DELETE FROM recent_contents WHERE contentId NOT IN (SELECT contentId FROM recent_contents ORDER BY listenedAt DESC LIMIT :limit)") @Query(
"DELETE FROM recent_contents WHERE contentId NOT IN (SELECT contentId FROM recent_contents ORDER BY listenedAt DESC LIMIT :limit)"
)
suspend fun keepMostRecent(limit: Int) suspend fun keepMostRecent(limit: Int)
@Query("DELETE FROM recent_contents") @Query("DELETE FROM recent_contents")

Some files were not shown because too many files have changed in this diff Show More