feat(profile): 채널 후원 영역과 전체보기 흐름을 추가한다
This commit is contained in:
@@ -134,6 +134,7 @@
|
|||||||
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
|
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" />
|
||||||
<activity android:name=".explorer.profile.UserProfileActivity" />
|
<activity android:name=".explorer.profile.UserProfileActivity" />
|
||||||
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
|
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
|
||||||
|
<activity android:name=".explorer.profile.channel_donation.UserProfileChannelDonationAllViewActivity" />
|
||||||
<activity android:name=".explorer.profile.fantalk.UserProfileFantalkAllViewActivity" />
|
<activity android:name=".explorer.profile.fantalk.UserProfileFantalkAllViewActivity" />
|
||||||
<activity android:name=".explorer.profile.follow.UserFollowerListActivity" />
|
<activity android:name=".explorer.profile.follow.UserFollowerListActivity" />
|
||||||
<activity android:name=".explorer.profile.creator_community.all.CreatorCommunityAllActivity" />
|
<activity android:name=".explorer.profile.creator_community.all.CreatorCommunityAllActivity" />
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import kr.co.vividnext.sodalive.common.ApiBuilder
|
|||||||
import kr.co.vividnext.sodalive.explorer.ExplorerApi
|
import kr.co.vividnext.sodalive.explorer.ExplorerApi
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
|
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.UserProfileChannelDonationAllViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
|
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityApi
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityApi
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
|
||||||
@@ -317,6 +318,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
|
|||||||
viewModel { LiveRoomDonationMessageViewModel(get()) }
|
viewModel { LiveRoomDonationMessageViewModel(get()) }
|
||||||
viewModel { ExplorerViewModel(get()) }
|
viewModel { ExplorerViewModel(get()) }
|
||||||
viewModel { UserProfileViewModel(get(), get(), get()) }
|
viewModel { UserProfileViewModel(get(), get(), get()) }
|
||||||
|
viewModel { UserProfileChannelDonationAllViewModel(get()) }
|
||||||
viewModel { UserFollowerListViewModel(get(), get()) }
|
viewModel { UserFollowerListViewModel(get(), get()) }
|
||||||
viewModel { TextMessageViewModel(get()) }
|
viewModel { TextMessageViewModel(get()) }
|
||||||
viewModel { TextMessageWriteViewModel(get()) }
|
viewModel { TextMessageWriteViewModel(get()) }
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import kr.co.vividnext.sodalive.explorer.profile.GetCreatorProfileResponse
|
|||||||
import kr.co.vividnext.sodalive.explorer.profile.detail.GetCreatorDetailResponse
|
import kr.co.vividnext.sodalive.explorer.profile.detail.GetCreatorDetailResponse
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PostWriteCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PostWriteCheersRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.GetChannelDonationListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.PostChannelDonationRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.GetDonationAllResponse
|
import kr.co.vividnext.sodalive.explorer.profile.donation.GetDonationAllResponse
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.follow.GetFollowerListResponse
|
import kr.co.vividnext.sodalive.explorer.profile.follow.GetFollowerListResponse
|
||||||
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
|
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
|
||||||
@@ -80,6 +82,18 @@ interface ExplorerApi {
|
|||||||
@Header("Authorization") authHeader: String
|
@Header("Authorization") authHeader: String
|
||||||
): Single<ApiResponse<Any>>
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@POST("/explorer/profile/channel-donation")
|
||||||
|
fun postChannelDonation(
|
||||||
|
@Body request: PostChannelDonationRequest,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<Any>>
|
||||||
|
|
||||||
|
@GET("/explorer/profile/channel-donation")
|
||||||
|
fun getChannelDonationList(
|
||||||
|
@Query("creatorId") creatorId: Long,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<GetChannelDonationListResponse>>
|
||||||
|
|
||||||
@GET("/explorer/profile/{id}/follower-list")
|
@GET("/explorer/profile/{id}/follower-list")
|
||||||
fun getFollowerList(
|
fun getFollowerList(
|
||||||
@Path("id") userId: Long,
|
@Path("id") userId: Long,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
|||||||
import kr.co.vividnext.sodalive.explorer.profile.GetCheersResponse
|
import kr.co.vividnext.sodalive.explorer.profile.GetCheersResponse
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PostWriteCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PostWriteCheersRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.GetChannelDonationListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.PostChannelDonationRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.donation.GetDonationAllResponse
|
import kr.co.vividnext.sodalive.explorer.profile.donation.GetDonationAllResponse
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
|
|
||||||
@@ -69,6 +71,22 @@ class ExplorerRepository(
|
|||||||
authHeader = token
|
authHeader = token
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun postChannelDonation(
|
||||||
|
request: PostChannelDonationRequest,
|
||||||
|
token: String
|
||||||
|
) = api.postChannelDonation(
|
||||||
|
request = request,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getChannelDonationList(
|
||||||
|
creatorId: Long,
|
||||||
|
token: String
|
||||||
|
): Single<ApiResponse<GetChannelDonationListResponse>> = api.getChannelDonationList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
authHeader = token
|
||||||
|
)
|
||||||
|
|
||||||
fun getFollowerList(
|
fun getFollowerList(
|
||||||
userId: Long,
|
userId: Long,
|
||||||
page: Int,
|
page: Int,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.explorer.profile
|
|||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.google.gson.annotations.SerializedName
|
import com.google.gson.annotations.SerializedName
|
||||||
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
import kr.co.vividnext.sodalive.audio_content.series.GetSeriesListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.GetChannelDonationListItem
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
@@ -25,10 +26,10 @@ data class GetCreatorProfileResponse(
|
|||||||
val notice: String,
|
val notice: String,
|
||||||
@SerializedName("communityPostList")
|
@SerializedName("communityPostList")
|
||||||
val communityPostList: List<GetCommunityPostListResponse>,
|
val communityPostList: List<GetCommunityPostListResponse>,
|
||||||
|
@SerializedName("channelDonationList")
|
||||||
|
val channelDonationList: List<GetChannelDonationListItem>,
|
||||||
@SerializedName("cheers")
|
@SerializedName("cheers")
|
||||||
val cheers: GetCheersResponse,
|
val cheers: GetCheersResponse,
|
||||||
@SerializedName("activitySummary")
|
|
||||||
val activitySummary: GetCreatorActivitySummary,
|
|
||||||
@SerializedName("seriesList")
|
@SerializedName("seriesList")
|
||||||
val seriesList: List<GetSeriesListResponse.SeriesListItem>,
|
val seriesList: List<GetSeriesListResponse.SeriesListItem>,
|
||||||
@SerializedName("isBlock")
|
@SerializedName("isBlock")
|
||||||
|
|||||||
@@ -46,6 +46,9 @@ import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
|||||||
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
|
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
|
||||||
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
import kr.co.vividnext.sodalive.databinding.ItemCreatorCommunityBinding
|
||||||
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
|
import kr.co.vividnext.sodalive.dialog.MemberProfileDialog
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.GetChannelDonationListItem
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.UserProfileChannelDonationAdapter
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.UserProfileChannelDonationAllViewActivity
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllActivity
|
||||||
@@ -65,6 +68,7 @@ import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationComplet
|
|||||||
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
|
||||||
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
|
||||||
|
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationDialog
|
||||||
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigActivity
|
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigActivity
|
||||||
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
import kr.co.vividnext.sodalive.live.roulette.config.RouletteConfigActivity
|
||||||
import kr.co.vividnext.sodalive.report.CheersReportDialog
|
import kr.co.vividnext.sodalive.report.CheersReportDialog
|
||||||
@@ -92,6 +96,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||||||
private lateinit var audioContentAdapter: AudioContentAdapter
|
private lateinit var audioContentAdapter: AudioContentAdapter
|
||||||
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
private lateinit var seriesAdapter: UserProfileSeriesListAdapter
|
||||||
private lateinit var donationAdapter: UserProfileDonationAdapter
|
private lateinit var donationAdapter: UserProfileDonationAdapter
|
||||||
|
private lateinit var channelDonationAdapter: UserProfileChannelDonationAdapter
|
||||||
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
private lateinit var cheersAdapter: UserProfileCheersAdapter
|
||||||
|
|
||||||
private val handler = Handler(Looper.getMainLooper())
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
@@ -137,6 +142,7 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||||||
|
|
||||||
setupLiveView()
|
setupLiveView()
|
||||||
setupDonationView()
|
setupDonationView()
|
||||||
|
setupChannelDonationView()
|
||||||
setupFanTalkView()
|
setupFanTalkView()
|
||||||
setupSeriesListView()
|
setupSeriesListView()
|
||||||
setupAudioContentListView()
|
setupAudioContentListView()
|
||||||
@@ -338,6 +344,68 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||||||
setupCheersView()
|
setupCheersView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupChannelDonationView() {
|
||||||
|
binding.layoutUserProfileChannelDonation.tvAll.setOnClickListener {
|
||||||
|
val intent = Intent(applicationContext, UserProfileChannelDonationAllViewActivity::class.java)
|
||||||
|
intent.putExtra(Constants.EXTRA_USER_ID, userId)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.layoutUserProfileChannelDonation.llChannelDonation.setOnClickListener {
|
||||||
|
val dialog = LiveRoomDonationDialog(
|
||||||
|
this,
|
||||||
|
LayoutInflater.from(this),
|
||||||
|
isLiveDonation = true,
|
||||||
|
messageMaxLength = 100
|
||||||
|
) { can, message, isSecret ->
|
||||||
|
viewModel.postChannelDonation(
|
||||||
|
creatorId = userId,
|
||||||
|
can = can,
|
||||||
|
isSecret = isSecret,
|
||||||
|
message = message
|
||||||
|
) {
|
||||||
|
viewModel.getCreatorProfile(userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dialog.show(screenWidth - 26.7f.dpToPx().toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
val recyclerView = binding.layoutUserProfileChannelDonation.rvChannelDonation
|
||||||
|
channelDonationAdapter = UserProfileChannelDonationAdapter()
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.HORIZONTAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
when (parent.getChildAdapterPosition(view)) {
|
||||||
|
0 -> {
|
||||||
|
outRect.left = 13.3f.dpToPx().toInt()
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
channelDonationAdapter.itemCount - 1 -> {
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 13.3f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
outRect.left = 6.7f.dpToPx().toInt()
|
||||||
|
outRect.right = 6.7f.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
recyclerView.adapter = channelDonationAdapter
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupCheersView() {
|
private fun setupCheersView() {
|
||||||
binding.layoutUserProfileFanTalk.ivSend.setOnClickListener {
|
binding.layoutUserProfileFanTalk.ivSend.setOnClickListener {
|
||||||
hideKeyboard {
|
hideKeyboard {
|
||||||
@@ -616,9 +684,12 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||||||
it.totalContentCount,
|
it.totalContentCount,
|
||||||
it.ownedContentCount
|
it.ownedContentCount
|
||||||
)
|
)
|
||||||
|
setChannelDonationList(it.channelDonationList)
|
||||||
setLiveRoomList(it.liveRoomList)
|
setLiveRoomList(it.liveRoomList)
|
||||||
setUserDonationRanking(it.userDonationRanking)
|
setUserDonationRanking(it.userDonationRanking)
|
||||||
setCommunityPostList(it.communityPostList)
|
setCommunityPostList(it.communityPostList)
|
||||||
|
} else {
|
||||||
|
binding.layoutUserProfileChannelDonation.root.visibility = View.GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -968,6 +1039,21 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun setChannelDonationList(channelDonationItems: List<GetChannelDonationListItem>) {
|
||||||
|
binding.layoutUserProfileChannelDonation.root.visibility = View.VISIBLE
|
||||||
|
binding.layoutUserProfileChannelDonation.tvNoChannelDonation.visibility =
|
||||||
|
if (channelDonationItems.isEmpty()) View.VISIBLE else View.GONE
|
||||||
|
binding.layoutUserProfileChannelDonation.rvChannelDonation.visibility =
|
||||||
|
if (channelDonationItems.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
binding.layoutUserProfileChannelDonation.tvAll.visibility =
|
||||||
|
if (channelDonationItems.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
|
||||||
|
channelDonationAdapter.items.clear()
|
||||||
|
channelDonationAdapter.items.addAll(channelDonationItems)
|
||||||
|
channelDonationAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
private fun setCommunityPost(
|
private fun setCommunityPost(
|
||||||
layout: ItemCreatorCommunityBinding,
|
layout: ItemCreatorCommunityBinding,
|
||||||
item: GetCommunityPostListResponse,
|
item: GetCommunityPostListResponse,
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
|||||||
import kr.co.vividnext.sodalive.common.Utils
|
import kr.co.vividnext.sodalive.common.Utils
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.GetChannelDonationListResponse
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.channel_donation.PostChannelDonationRequest
|
||||||
import kr.co.vividnext.sodalive.explorer.profile.detail.GetCreatorDetailResponse
|
import kr.co.vividnext.sodalive.explorer.profile.detail.GetCreatorDetailResponse
|
||||||
import kr.co.vividnext.sodalive.report.ReportRepository
|
import kr.co.vividnext.sodalive.report.ReportRepository
|
||||||
import kr.co.vividnext.sodalive.report.ReportRequest
|
import kr.co.vividnext.sodalive.report.ReportRequest
|
||||||
@@ -35,6 +37,10 @@ class UserProfileViewModel(
|
|||||||
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
|
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
|
||||||
get() = _creatorProfileLiveData
|
get() = _creatorProfileLiveData
|
||||||
|
|
||||||
|
private val _channelDonationLiveData = MutableLiveData<GetChannelDonationListResponse>()
|
||||||
|
val channelDonationLiveData: LiveData<GetChannelDonationListResponse>
|
||||||
|
get() = _channelDonationLiveData
|
||||||
|
|
||||||
fun cheersReport(cheersId: Long, reason: String) {
|
fun cheersReport(cheersId: Long, reason: String) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
|
|
||||||
@@ -356,6 +362,89 @@ class UserProfileViewModel(
|
|||||||
onSuccess("보이스온 ${nickname}님의 채널입니다.\n$shareUrl")
|
onSuccess("보이스온 ${nickname}님의 채널입니다.\n$shareUrl")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getChannelDonationList(creatorId: Long) {
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getChannelDonationList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_channelDonationLiveData.postValue(it.data)
|
||||||
|
} else {
|
||||||
|
if (it.message != null) {
|
||||||
|
_toastLiveData.postValue(it.message)
|
||||||
|
} else {
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
SodaLiveApplicationHolder.get()
|
||||||
|
.getString(R.string.common_error_unknown)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
it.message?.let { message -> Logger.e(message) }
|
||||||
|
_toastLiveData.postValue(
|
||||||
|
SodaLiveApplicationHolder.get()
|
||||||
|
.getString(R.string.common_error_unknown)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postChannelDonation(
|
||||||
|
creatorId: Long,
|
||||||
|
can: Int,
|
||||||
|
isSecret: Boolean,
|
||||||
|
message: String,
|
||||||
|
onSuccess: () -> Unit
|
||||||
|
) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.postChannelDonation(
|
||||||
|
request = PostChannelDonationRequest(
|
||||||
|
creatorId = creatorId,
|
||||||
|
can = can,
|
||||||
|
isSecret = isSecret,
|
||||||
|
message = message
|
||||||
|
),
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success) {
|
||||||
|
SharedPreferenceManager.can -= can
|
||||||
|
onSuccess()
|
||||||
|
} 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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun userBlock(userId: Long) {
|
fun userBlock(userId: Long) {
|
||||||
_isLoading.value = true
|
_isLoading.value = true
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
fun GetChannelDonationListItem.relativeTimeText(context: Context): String {
|
||||||
|
val pastMillis = parseServerUtcToMillis(createdAt)
|
||||||
|
?: return context.getString(R.string.character_comment_time_just_now)
|
||||||
|
|
||||||
|
val nowMillis = System.currentTimeMillis()
|
||||||
|
var diff = nowMillis - pastMillis
|
||||||
|
if (diff < 0) diff = 0
|
||||||
|
|
||||||
|
val minute = 60_000L
|
||||||
|
val hour = 60 * minute
|
||||||
|
val day = 24 * hour
|
||||||
|
|
||||||
|
if (diff < minute) {
|
||||||
|
return context.getString(R.string.character_comment_time_just_now)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff < hour) {
|
||||||
|
val minutes = (diff / minute).toInt()
|
||||||
|
return context.getString(R.string.character_comment_time_minutes, minutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff < day) {
|
||||||
|
val hours = (diff / hour).toInt()
|
||||||
|
return context.getString(R.string.character_comment_time_hours, hours)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diff < 30 * day) {
|
||||||
|
val days = (diff / day).toInt()
|
||||||
|
return context.getString(R.string.character_comment_time_days, days)
|
||||||
|
}
|
||||||
|
|
||||||
|
val tz = TimeZone.getDefault()
|
||||||
|
val calNow = Calendar.getInstance(tz, Locale.getDefault())
|
||||||
|
val calPast = Calendar.getInstance(tz, Locale.getDefault())
|
||||||
|
calPast.timeInMillis = pastMillis
|
||||||
|
|
||||||
|
var years = calNow.get(Calendar.YEAR) - calPast.get(Calendar.YEAR)
|
||||||
|
val nowMonth = calNow.get(Calendar.MONTH)
|
||||||
|
val pastMonth = calPast.get(Calendar.MONTH)
|
||||||
|
val nowDay = calNow.get(Calendar.DAY_OF_MONTH)
|
||||||
|
val pastDay = calPast.get(Calendar.DAY_OF_MONTH)
|
||||||
|
if (nowMonth < pastMonth || (nowMonth == pastMonth && nowDay < pastDay)) {
|
||||||
|
years -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (years < 1) {
|
||||||
|
var months = (calNow.get(Calendar.YEAR) - calPast.get(Calendar.YEAR)) * 12 + (nowMonth - pastMonth)
|
||||||
|
if (nowDay < pastDay) months -= 1
|
||||||
|
if (months < 1) months = 1
|
||||||
|
return context.getString(R.string.character_comment_time_months, months)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.getString(R.string.character_comment_time_years, years)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseServerUtcToMillis(dateUtc: String?): Long? {
|
||||||
|
if (dateUtc.isNullOrBlank()) return null
|
||||||
|
val value = dateUtc.trim()
|
||||||
|
|
||||||
|
if (value.all { it.isDigit() }) {
|
||||||
|
return try { value.toLong() } catch (_: NumberFormatException) { null }
|
||||||
|
}
|
||||||
|
|
||||||
|
val patterns = listOf(
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss",
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy/MM/dd HH:mm:ss"
|
||||||
|
)
|
||||||
|
|
||||||
|
for (pattern in patterns) {
|
||||||
|
try {
|
||||||
|
val sdf = SimpleDateFormat(pattern, Locale.US)
|
||||||
|
sdf.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
val parsed: Date? = sdf.parse(value)
|
||||||
|
if (parsed != null) return parsed.time
|
||||||
|
} catch (_: ParseException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.SpannableString
|
||||||
|
import android.text.Spanned
|
||||||
|
import android.text.style.ForegroundColorSpan
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
|
||||||
|
@DrawableRes
|
||||||
|
fun GetChannelDonationListItem.chatDonationBackgroundRes(): Int {
|
||||||
|
if (isSecret) return R.drawable.bg_round_corner_6_7_cc59548f
|
||||||
|
return when {
|
||||||
|
can >= 10000 -> R.drawable.bg_round_corner_6_7_ccc25264
|
||||||
|
can >= 5000 -> R.drawable.bg_round_corner_6_7_ccd85e37
|
||||||
|
can >= 1000 -> R.drawable.bg_round_corner_6_7_ccd38c38
|
||||||
|
can >= 500 -> R.drawable.bg_round_corner_6_7_cc59548f
|
||||||
|
can >= 100 -> R.drawable.bg_round_corner_6_7_cc4d6aa4
|
||||||
|
can >= 50 -> R.drawable.bg_round_corner_6_7_cc2d7390
|
||||||
|
else -> R.drawable.bg_round_corner_6_7_cc548f7d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun GetChannelDonationListItem.channelDonationContentText(
|
||||||
|
context: Context,
|
||||||
|
maxLength: Int? = null
|
||||||
|
) =
|
||||||
|
run {
|
||||||
|
val contentText = if (maxLength != null && message.length > maxLength) {
|
||||||
|
"${message.take(maxLength)}..."
|
||||||
|
} else {
|
||||||
|
message
|
||||||
|
}
|
||||||
|
val canRange = Regex("[0-9,]+\\s*캔").find(contentText)?.range
|
||||||
|
SpannableString(contentText).apply {
|
||||||
|
setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
ContextCompat.getColor(context, R.color.color_cfd8dc)
|
||||||
|
),
|
||||||
|
0,
|
||||||
|
contentText.length,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
if (canRange != null) {
|
||||||
|
setSpan(
|
||||||
|
ForegroundColorSpan(
|
||||||
|
ContextCompat.getColor(context, R.color.color_fdca2f)
|
||||||
|
),
|
||||||
|
canRange.first,
|
||||||
|
canRange.last + 1,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class GetChannelDonationListResponse(
|
||||||
|
@SerializedName("totalCount") val totalCount: Int,
|
||||||
|
@SerializedName("items") val items: List<GetChannelDonationListItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class GetChannelDonationListItem(
|
||||||
|
@SerializedName("id") val id: Long,
|
||||||
|
@SerializedName("memberId") val memberId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileUrl") val profileUrl: String,
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("isSecret") val isSecret: Boolean,
|
||||||
|
@SerializedName("message") val message: String,
|
||||||
|
@SerializedName("createdAt") val createdAt: String
|
||||||
|
)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class PostChannelDonationRequest(
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("isSecret") val isSecret: Boolean = false,
|
||||||
|
@SerializedName("message") val message: String = "",
|
||||||
|
@SerializedName("container") val container: String = "aos"
|
||||||
|
)
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemUserProfileChannelDonationBinding
|
||||||
|
|
||||||
|
class UserProfileChannelDonationAdapter : RecyclerView.Adapter<UserProfileChannelDonationAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetChannelDonationListItem>()
|
||||||
|
|
||||||
|
class ViewHolder(
|
||||||
|
private val binding: ItemUserProfileChannelDonationBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: GetChannelDonationListItem) {
|
||||||
|
binding.ivProfile.load(item.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvNickname.text = item.nickname
|
||||||
|
binding.tvDate.text = item.relativeTimeText(binding.root.context)
|
||||||
|
binding.tvContent.text = item.channelDonationContentText(
|
||||||
|
context = binding.root.context,
|
||||||
|
maxLength = 30
|
||||||
|
)
|
||||||
|
binding.root.setBackgroundResource(item.chatDonationBackgroundRes())
|
||||||
|
binding.root.setOnClickListener(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
ItemUserProfileChannelDonationBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ItemUserProfileChannelDonationAllBinding
|
||||||
|
|
||||||
|
class UserProfileChannelDonationAllAdapter : RecyclerView.Adapter<UserProfileChannelDonationAllAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
val items = mutableListOf<GetChannelDonationListItem>()
|
||||||
|
private val expandedItemIds = mutableSetOf<Long>()
|
||||||
|
|
||||||
|
inner class ViewHolder(
|
||||||
|
private val binding: ItemUserProfileChannelDonationAllBinding
|
||||||
|
) : RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: GetChannelDonationListItem) {
|
||||||
|
binding.ivProfile.load(item.profileUrl) {
|
||||||
|
crossfade(true)
|
||||||
|
placeholder(R.drawable.ic_place_holder)
|
||||||
|
transformations(CircleCropTransformation())
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvNickname.text = item.nickname
|
||||||
|
binding.tvDate.text = item.relativeTimeText(binding.root.context)
|
||||||
|
val isExpanded = expandedItemIds.contains(item.id)
|
||||||
|
binding.tvContent.text = item.channelDonationContentText(
|
||||||
|
context = binding.root.context,
|
||||||
|
maxLength = if (isExpanded) null else 30
|
||||||
|
)
|
||||||
|
binding.root.setBackgroundResource(item.chatDonationBackgroundRes())
|
||||||
|
binding.tvContent.setOnClickListener {
|
||||||
|
if (!isExpanded && item.message.length > 30) {
|
||||||
|
expandedItemIds.add(item.id)
|
||||||
|
val position = bindingAdapterPosition
|
||||||
|
if (position != RecyclerView.NO_POSITION) {
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
return ViewHolder(
|
||||||
|
ItemUserProfileChannelDonationAllBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
holder.bind(items[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Rect
|
||||||
|
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.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.Constants
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileChannelDonationAllBinding
|
||||||
|
import kr.co.vividnext.sodalive.extensions.dpToPx
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class UserProfileChannelDonationAllViewActivity : BaseActivity<ActivityUserProfileChannelDonationAllBinding>(
|
||||||
|
ActivityUserProfileChannelDonationAllBinding::inflate
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val viewModel: UserProfileChannelDonationAllViewModel by inject()
|
||||||
|
|
||||||
|
private lateinit var loadingDialog: LoadingDialog
|
||||||
|
private lateinit var adapter: UserProfileChannelDonationAllAdapter
|
||||||
|
|
||||||
|
private var userId: Long = 0
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
if (userId > 0) {
|
||||||
|
bindData()
|
||||||
|
viewModel.getChannelDonationList(userId)
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
applicationContext,
|
||||||
|
getString(R.string.error_invalid_request),
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
loadingDialog = LoadingDialog(this, layoutInflater)
|
||||||
|
binding.toolbar.tvBack.setText(R.string.screen_user_profile_channel_donation_all_title)
|
||||||
|
binding.toolbar.tvBack.setOnClickListener { finish() }
|
||||||
|
|
||||||
|
val recyclerView = binding.rvChannelDonation
|
||||||
|
adapter = UserProfileChannelDonationAllAdapter()
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(
|
||||||
|
applicationContext,
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
super.getItemOffsets(outRect, view, parent, state)
|
||||||
|
outRect.bottom = 10.dpToPx().toInt()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun bindData() {
|
||||||
|
viewModel.toastLiveData.observe(this) {
|
||||||
|
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.isLoading.observe(this) {
|
||||||
|
if (it) {
|
||||||
|
loadingDialog.show(screenWidth, "")
|
||||||
|
} else {
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.channelDonationLiveData.observe(this) {
|
||||||
|
binding.tvTotalCount.text = it.totalCount.toString()
|
||||||
|
adapter.items.clear()
|
||||||
|
adapter.items.addAll(it.items)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
binding.tvNoChannelDonation.visibility = if (it.items.isEmpty()) View.VISIBLE else View.GONE
|
||||||
|
binding.rvChannelDonation.visibility = if (it.items.isEmpty()) View.GONE else View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package kr.co.vividnext.sodalive.explorer.profile.channel_donation
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import com.orhanobut.logger.Logger
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseViewModel
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaLiveApplicationHolder
|
||||||
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
|
|
||||||
|
class UserProfileChannelDonationAllViewModel(
|
||||||
|
private val repository: ExplorerRepository
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
private val _toastLiveData = MutableLiveData<String?>()
|
||||||
|
val toastLiveData: LiveData<String?>
|
||||||
|
get() = _toastLiveData
|
||||||
|
|
||||||
|
private val _isLoading = MutableLiveData(false)
|
||||||
|
val isLoading: LiveData<Boolean>
|
||||||
|
get() = _isLoading
|
||||||
|
|
||||||
|
private val _channelDonationLiveData = MutableLiveData<GetChannelDonationListResponse>()
|
||||||
|
val channelDonationLiveData: LiveData<GetChannelDonationListResponse>
|
||||||
|
get() = _channelDonationLiveData
|
||||||
|
|
||||||
|
fun getChannelDonationList(creatorId: Long) {
|
||||||
|
_isLoading.value = true
|
||||||
|
compositeDisposable.add(
|
||||||
|
repository.getChannelDonationList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
_isLoading.value = false
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
_channelDonationLiveData.postValue(it.data)
|
||||||
|
} 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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.text.InputFilter
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
@@ -26,6 +27,7 @@ class LiveRoomDonationDialog(
|
|||||||
private val activity: AppCompatActivity,
|
private val activity: AppCompatActivity,
|
||||||
layoutInflater: LayoutInflater,
|
layoutInflater: LayoutInflater,
|
||||||
isLiveDonation: Boolean = false,
|
isLiveDonation: Boolean = false,
|
||||||
|
messageMaxLength: Int = 1000,
|
||||||
onClickDonation: (Int, String, Boolean) -> Unit
|
onClickDonation: (Int, String, Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -47,11 +49,17 @@ class LiveRoomDonationDialog(
|
|||||||
bottomSheetBehavior.skipCollapsed = true
|
bottomSheetBehavior.skipCollapsed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialogView.etDonationMessage.filters = arrayOf(InputFilter.LengthFilter(messageMaxLength))
|
||||||
|
dialogView.etDonationMessage.hint = activity.getString(
|
||||||
|
R.string.screen_live_room_donation_message_hint_format,
|
||||||
|
messageMaxLength
|
||||||
|
)
|
||||||
|
|
||||||
dialogView.tvCancel.setOnClickListener { bottomSheetDialog.dismiss() }
|
dialogView.tvCancel.setOnClickListener { bottomSheetDialog.dismiss() }
|
||||||
dialogView.tvDonation.setOnClickListener {
|
dialogView.tvDonation.setOnClickListener {
|
||||||
try {
|
try {
|
||||||
val can = dialogView.etDonationCan.text.toString().toInt()
|
val can = dialogView.etDonationCan.text.toString().toInt()
|
||||||
val message = dialogView.etDonationMessage.text.toString().prefix(1000)
|
val message = dialogView.etDonationMessage.text.toString().prefix(messageMaxLength)
|
||||||
|
|
||||||
if (isLiveDonation) {
|
if (isLiveDonation) {
|
||||||
val isSecret = dialogView.tvSecret.isSelected
|
val isSecret = dialogView.tvSecret.isSelected
|
||||||
@@ -99,9 +107,15 @@ class LiveRoomDonationDialog(
|
|||||||
val isSelected = dialogView.tvSecret.isSelected
|
val isSelected = dialogView.tvSecret.isSelected
|
||||||
dialogView.tvSecret.isSelected = !isSelected
|
dialogView.tvSecret.isSelected = !isSelected
|
||||||
dialogView.etDonationMessage.hint = if (!isSelected) {
|
dialogView.etDonationMessage.hint = if (!isSelected) {
|
||||||
activity.getString(R.string.screen_live_room_secret_mission_hint)
|
activity.getString(
|
||||||
|
R.string.screen_live_room_secret_mission_hint_format,
|
||||||
|
messageMaxLength
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
activity.getString(R.string.screen_live_room_donation_message_hint)
|
activity.getString(
|
||||||
|
R.string.screen_live_room_donation_message_hint_format,
|
||||||
|
messageMaxLength
|
||||||
|
)
|
||||||
}
|
}
|
||||||
dialogView.etDonationCan.hint = if (!isSelected) {
|
dialogView.etDonationCan.hint = if (!isSelected) {
|
||||||
activity.getString(R.string.screen_live_room_secret_mission_input_min)
|
activity.getString(R.string.screen_live_room_secret_mission_input_min)
|
||||||
|
|||||||
8
app/src/main/res/drawable/bg_round_corner_16_525252.xml
Normal file
8
app/src/main/res/drawable/bg_round_corner_16_525252.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/color_525252" />
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="1dp"
|
||||||
|
android:color="@color/color_525252" />
|
||||||
|
</shape>
|
||||||
@@ -277,6 +277,15 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/layout_user_profile_channel_donation"
|
||||||
|
layout="@layout/layout_user_profile_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/layout_user_profile_live"
|
android:id="@+id/layout_user_profile_live"
|
||||||
layout="@layout/layout_user_profile_live"
|
layout="@layout/layout_user_profile_live"
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
layout="@layout/detail_toolbar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="13.3dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:text="@string/screen_user_profile_donation_total_label"
|
||||||
|
android:textColor="@color/color_eeeeee"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_total_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6.7dp"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:textColor="@color/color_80d8ff"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:text="@string/screen_user_profile_donation_total_unit"
|
||||||
|
android:textColor="@color/color_777777"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginHorizontal="13.3dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="@color/color_595959" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_no_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="13.3dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:fontFamily="@font/light"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/screen_user_profile_channel_donation_empty"
|
||||||
|
android:textColor="@color/color_bbbbbb"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:padding="13.3dp" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="280dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_round_corner_10_232323"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="14dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_profile"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_nickname"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/bold"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:textColor="#78909C"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:textColor="@color/color_cfd8dc"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_round_corner_10_232323"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="14dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_profile"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_nickname"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/bold"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_date"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:textColor="#78909C"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:fontFamily="@font/medium"
|
||||||
|
android:textColor="@color/color_cfd8dc"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/bold"
|
||||||
|
android:text="@string/screen_user_profile_channel_donation_title"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="26sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:fontFamily="@font/light"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/view_all"
|
||||||
|
android:textColor="#78909C"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="14dp"
|
||||||
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_no_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:fontFamily="@font/light"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/screen_user_profile_channel_donation_empty"
|
||||||
|
android:textColor="@color/color_bbbbbb"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_channel_donation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@drawable/bg_round_corner_16_525252"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:fontFamily="@font/bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/screen_user_profile_channel_donation_button"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:drawableStartCompat="@drawable/ic_donation_white" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -477,6 +477,8 @@
|
|||||||
<string name="screen_live_room_listener_label">Listener</string>
|
<string name="screen_live_room_listener_label">Listener</string>
|
||||||
<string name="screen_live_room_secret_mission_hint">Enter a secret mission (up to 1000 chars)</string>
|
<string name="screen_live_room_secret_mission_hint">Enter a secret mission (up to 1000 chars)</string>
|
||||||
<string name="screen_live_room_donation_message_hint">Enter a message to send (up to 1000 chars)</string>
|
<string name="screen_live_room_donation_message_hint">Enter a message to send (up to 1000 chars)</string>
|
||||||
|
<string name="screen_live_room_secret_mission_hint_format">Enter a secret mission (up to %1$d chars)</string>
|
||||||
|
<string name="screen_live_room_donation_message_hint_format">Enter a message to send (up to %1$d chars)</string>
|
||||||
<string name="screen_live_room_secret_mission_input_min">Enter 10 or more cans</string>
|
<string name="screen_live_room_secret_mission_input_min">Enter 10 or more cans</string>
|
||||||
<string name="screen_live_room_donation_input_min">Enter at least 1 can</string>
|
<string name="screen_live_room_donation_input_min">Enter at least 1 can</string>
|
||||||
<string name="screen_live_room_free">Free</string>
|
<string name="screen_live_room_free">Free</string>
|
||||||
@@ -794,6 +796,10 @@
|
|||||||
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s items</string>
|
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s items</string>
|
||||||
<string name="screen_user_profile_fan_talk_title">Fan Talk</string>
|
<string name="screen_user_profile_fan_talk_title">Fan Talk</string>
|
||||||
<string name="screen_user_profile_fantalk_all_title">View all Fan Talk</string>
|
<string name="screen_user_profile_fantalk_all_title">View all Fan Talk</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_title">Channel Donation</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_button">Donate to Channel</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_all_title">View all Channel Donations</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_empty">No channel donations yet.</string>
|
||||||
<string name="screen_user_profile_cheer_label">Cheer</string>
|
<string name="screen_user_profile_cheer_label">Cheer</string>
|
||||||
<string name="screen_user_profile_cheer_hint">Leave a cheer comment!</string>
|
<string name="screen_user_profile_cheer_hint">Leave a cheer comment!</string>
|
||||||
<string name="screen_user_profile_cheer_reply_hint">Leave a reply to this cheer!</string>
|
<string name="screen_user_profile_cheer_reply_hint">Leave a reply to this cheer!</string>
|
||||||
|
|||||||
@@ -476,6 +476,8 @@
|
|||||||
<string name="screen_live_room_listener_label">リスナー</string>
|
<string name="screen_live_room_listener_label">リスナー</string>
|
||||||
<string name="screen_live_room_secret_mission_hint">シークレットミッションを入力(最大1000文字)</string>
|
<string name="screen_live_room_secret_mission_hint">シークレットミッションを入力(最大1000文字)</string>
|
||||||
<string name="screen_live_room_donation_message_hint">一緒に送るメッセージを入力(最大1000文字)</string>
|
<string name="screen_live_room_donation_message_hint">一緒に送るメッセージを入力(最大1000文字)</string>
|
||||||
|
<string name="screen_live_room_secret_mission_hint_format">シークレットミッションを入力(最大%1$d文字)</string>
|
||||||
|
<string name="screen_live_room_donation_message_hint_format">一緒に送るメッセージを入力(最大%1$d文字)</string>
|
||||||
<string name="screen_live_room_secret_mission_input_min">10CAN以上入力してください</string>
|
<string name="screen_live_room_secret_mission_input_min">10CAN以上入力してください</string>
|
||||||
<string name="screen_live_room_donation_input_min">1CAN以上入力してください</string>
|
<string name="screen_live_room_donation_input_min">1CAN以上入力してください</string>
|
||||||
<string name="screen_live_room_free">無料</string>
|
<string name="screen_live_room_free">無料</string>
|
||||||
@@ -794,6 +796,10 @@
|
|||||||
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s個</string>
|
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s個</string>
|
||||||
<string name="screen_user_profile_fan_talk_title">ファンTalk</string>
|
<string name="screen_user_profile_fan_talk_title">ファンTalk</string>
|
||||||
<string name="screen_user_profile_fantalk_all_title">ファンTalkをすべて見る</string>
|
<string name="screen_user_profile_fantalk_all_title">ファンTalkをすべて見る</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_title">チャンネルギフト</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_button">チャンネルにギフトする</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_all_title">チャンネルギフトをすべて見る</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_empty">チャンネルギフトがありません。</string>
|
||||||
<string name="screen_user_profile_cheer_label">応援</string>
|
<string name="screen_user_profile_cheer_label">応援</string>
|
||||||
<string name="screen_user_profile_cheer_hint">応援コメントを残してみましょう!</string>
|
<string name="screen_user_profile_cheer_hint">応援コメントを残してみましょう!</string>
|
||||||
<string name="screen_user_profile_cheer_reply_hint">応援コメントに返信してみましょう!</string>
|
<string name="screen_user_profile_cheer_reply_hint">応援コメントに返信してみましょう!</string>
|
||||||
|
|||||||
@@ -137,4 +137,5 @@
|
|||||||
<color name="color_b0bec5">#B0BEC5</color>
|
<color name="color_b0bec5">#B0BEC5</color>
|
||||||
<color name="color_7c7c80">#7C7C80</color>
|
<color name="color_7c7c80">#7C7C80</color>
|
||||||
<color name="color_37474f">#37474F</color>
|
<color name="color_37474f">#37474F</color>
|
||||||
|
<color name="color_cfd8dc">#CFD8DC</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -476,6 +476,8 @@
|
|||||||
<string name="screen_live_room_listener_label">리스너</string>
|
<string name="screen_live_room_listener_label">리스너</string>
|
||||||
<string name="screen_live_room_secret_mission_hint">비밀 미션을 입력하세요(최대 1000자)</string>
|
<string name="screen_live_room_secret_mission_hint">비밀 미션을 입력하세요(최대 1000자)</string>
|
||||||
<string name="screen_live_room_donation_message_hint">함께 보낼 메시지 입력(최대 1000자)</string>
|
<string name="screen_live_room_donation_message_hint">함께 보낼 메시지 입력(최대 1000자)</string>
|
||||||
|
<string name="screen_live_room_secret_mission_hint_format">비밀 미션을 입력하세요(최대 %1$d자)</string>
|
||||||
|
<string name="screen_live_room_donation_message_hint_format">함께 보낼 메시지 입력(최대 %1$d자)</string>
|
||||||
<string name="screen_live_room_secret_mission_input_min">10캔 이상 입력하세요</string>
|
<string name="screen_live_room_secret_mission_input_min">10캔 이상 입력하세요</string>
|
||||||
<string name="screen_live_room_donation_input_min">1캔 이상 입력하세요</string>
|
<string name="screen_live_room_donation_input_min">1캔 이상 입력하세요</string>
|
||||||
<string name="screen_live_room_free">무료</string>
|
<string name="screen_live_room_free">무료</string>
|
||||||
@@ -793,6 +795,10 @@
|
|||||||
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s개</string>
|
<string name="screen_user_profile_audio_ratio_detail">%1$s / %2$s개</string>
|
||||||
<string name="screen_user_profile_fan_talk_title">팬 Talk</string>
|
<string name="screen_user_profile_fan_talk_title">팬 Talk</string>
|
||||||
<string name="screen_user_profile_fantalk_all_title">팬 Talk 전체보기</string>
|
<string name="screen_user_profile_fantalk_all_title">팬 Talk 전체보기</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_title">채널 후원</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_button">채널 후원하기</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_all_title">채널 후원 전체보기</string>
|
||||||
|
<string name="screen_user_profile_channel_donation_empty">채널 후원이 없습니다.</string>
|
||||||
<string name="screen_user_profile_cheer_label">응원</string>
|
<string name="screen_user_profile_cheer_label">응원</string>
|
||||||
<string name="screen_user_profile_cheer_hint">응원댓글을 남겨보세요!</string>
|
<string name="screen_user_profile_cheer_hint">응원댓글을 남겨보세요!</string>
|
||||||
<string name="screen_user_profile_cheer_reply_hint">응원댓글에 답글을 남겨보세요!</string>
|
<string name="screen_user_profile_cheer_reply_hint">응원댓글에 답글을 남겨보세요!</string>
|
||||||
|
|||||||
70
docs/20260225_채널후원영역및전체보기구현.md
Normal file
70
docs/20260225_채널후원영역및전체보기구현.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# 20260225 채널 후원 영역 및 전체보기 구현
|
||||||
|
|
||||||
|
## 작업 목표
|
||||||
|
- 크리에이터 채널에 채널 후원 섹션을 추가한다.
|
||||||
|
- 채널 후원하기 UI는 라이브 후원하기 UI와 동일한 흐름/스타일을 따른다.
|
||||||
|
- 채널 후원 전체보기 페이지를 별도로 추가한다.
|
||||||
|
- API 연동은 `/explorer/profile/channel-donation`의 POST/GET 요구사항을 반영한다.
|
||||||
|
|
||||||
|
## 구현 체크리스트
|
||||||
|
- [x] 기존 라이브 후원 다이얼로그/아이콘/문구 스타일 재사용 지점 확인
|
||||||
|
- [x] `ExplorerApi`/`ExplorerRepository`에 채널 후원 POST/GET API 추가
|
||||||
|
- [x] `UserProfileViewModel`에 채널 후원 조회/후원하기 액션 추가
|
||||||
|
- [x] `kr.co.vividnext.sodalive.explorer.profile.channel_donation` 패키지에 전체보기 Activity/ViewModel/Adapter 생성
|
||||||
|
- [x] 크리에이터 채널(`UserProfileActivity`)에 채널 후원 섹션 UI 추가
|
||||||
|
- [x] 섹션 상단 `제목 - 전체보기` 및 총 개수 노출
|
||||||
|
- [x] 가로 아이템 리스트 폭을 줄여 좌/우 아이템 일부가 보이도록 구성
|
||||||
|
- [x] `채널 후원하기` 텍스트 버튼 스타일 적용(배경 `#525252`, radius `16dp`, 흰색 텍스트, 선물 아이콘)
|
||||||
|
- [x] 아이템 UI 적용(프로필 이미지, 닉네임, 시간, 내용)
|
||||||
|
- [x] `createdAt(UTC)`을 기기 타임존으로 변환해 `OO분전/OO시간전/OO일전` 표시
|
||||||
|
- [x] 내용 텍스트에서 `OO캔` 색상 `#FDCA2F`, 나머지 `#CFD8DC`, 글자 크기 `16sp` 적용
|
||||||
|
- [x] 문자열/리소스 추가 및 기존 다국어 리소스 반영
|
||||||
|
- [x] LSP 진단, 테스트/빌드 실행 및 결과 확인
|
||||||
|
|
||||||
|
## 검증 기록
|
||||||
|
- 2026-02-25
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 API(POST/GET) 연동, 프로필 채널 후원 섹션 및 후원 버튼(라이브 후원 다이얼로그 재사용), 채널 후원 전체보기 페이지를 추가하고 아이템 시간/문구 스타일을 요구사항대로 반영했다.
|
||||||
|
- 실행 명령: `./gradlew :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 신규 변경으로 인한 테스트 실패 없음.
|
||||||
|
- 실행 명령: `./gradlew :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
|
- 참고: 현재 실행 환경의 LSP 도구는 `.kt` 확장 LSP 서버가 구성되어 있지 않아 LSP 진단 대신 Gradle 컴파일/테스트로 정합성을 검증했다.
|
||||||
|
|
||||||
|
- 2026-02-25 (후속 요구사항 반영)
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 섹션 위치를 최신 콘텐츠 아래로 이동하고, 프로필 페이지는 `GetCreatorProfileResponse.channelDonationList`만 사용하도록 변경했다. 후원 0건 시 빈 문구 노출/전체보기 숨김, 프로필 페이지 개수 제거, 비밀후원 전달, 채널 후원 메시지 100자 제한, `OO캔을 후원했습니다.` 문구 강조, 라이브룸 채팅 후원과 동일한 배경색 규칙을 적용했다.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 단위 테스트 통과.
|
||||||
|
- 참고: 일반 daemon 모드에서 Kotlin incremental cache 충돌로 실패가 발생해 `--no-daemon`으로 재검증했다.
|
||||||
|
|
||||||
|
- 2026-02-25 (힌트 최대 글자수/국제화 및 중복 문구 수정)
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 UI에서는 메시지 힌트를 최대 100자로 표시하도록 변경하고(라이브는 기존 1000 유지), 힌트 문자열을 `%d` 포맷 기반 국제화 리소스로 분리했다. 또한 채널 후원 리스트 문구는 서버 `message` 원문을 그대로 표시하도록 바꿔 `OO캔을 후원했습니다.` 중복이 생기지 않게 수정하고, 원문 안의 `OO캔` 구간만 색상 강조하도록 반영했다.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 단위 테스트 통과.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
|
- 참고: 1회 실행에서 리소스 패키징 일시 오류(`NoSuchFileException`)가 있었으나 재실행 시 정상 통과했다.
|
||||||
|
|
||||||
|
- 2026-02-25 (채널 후원 아이템 길이 제한/전체보기 터치 동작)
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 아이템에서 긴 메시지로 인한 UI 깨짐을 막기 위해 `message`를 최대 30자 + `...`로 표시하도록 변경했다. 크리에이터 채널 페이지 아이템에는 터치 이벤트를 추가하지 않았고, 채널 후원 전체보기 페이지 아이템은 터치 시 전체 `message`를 다이얼로그로 확인할 수 있게 적용했다.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 단위 테스트 통과.
|
||||||
|
- 참고: 테스트/빌드를 병렬 실행한 1회에서 매니페스트 입력 파일 검증 오류가 발생해 테스트를 단독 재실행하여 통과 확인했다.
|
||||||
|
|
||||||
|
- 2026-02-25 (전체보기 아이템 확장 방식 변경)
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 전체 리스트 페이지에서 말줄임표가 붙은 텍스트를 터치했을 때 AlertDialog를 띄우지 않고, 해당 아이템 내부 텍스트를 전체 내용으로 확장해서 표시하도록 변경했다. 크리에이터 채널 페이지는 기존처럼 터치 이벤트를 추가하지 않았다.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 단위 테스트 통과.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
|
- 참고: 테스트/빌드 병렬 실행 시 1회 manifest 중간 산출물 누락 오류가 발생해 각각 재실행하여 최종 성공을 확인했다.
|
||||||
|
|
||||||
|
- 2026-02-25 (채널 후원 시간 표시 보정)
|
||||||
|
- 무엇/왜/어떻게: 채널 후원 아이템의 상대 시간 표시가 커뮤니티 포스트와 다르게 계산되던 문제를 수정하기 위해 `GetCommunityPostListResponse.relativeTimeText`와 동일한 계산 규칙(방금 전/분/시간/일/개월/년, UTC 파싱 및 로컬 타임존 기준 계산)으로 동기화했다.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:testDebugUnitTest`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 단위 테스트 통과.
|
||||||
|
- 실행 명령: `./gradlew --no-daemon :app:assembleDebug`
|
||||||
|
- 결과: 성공(BUILD SUCCESSFUL), 디버그 빌드 정상 완료.
|
||||||
Reference in New Issue
Block a user