크리에이터 채널 페이지 추가

This commit is contained in:
klaus 2023-08-01 15:10:33 +09:00
parent 662ef64696
commit 14b652d38e
65 changed files with 4185 additions and 12 deletions

View File

@ -41,6 +41,10 @@
<activity android:name=".live.reservation.complete.LiveReservationCompleteActivity" />
<activity android:name=".live.room.LiveRoomActivity" />
<activity android:name=".explorer.profile.UserProfileActivity" />
<activity android:name=".explorer.profile.donation.UserProfileDonationAllViewActivity" />
<activity android:name=".explorer.profile.fantalk.UserProfileFantalkAllViewActivity" />
<activity android:name=".explorer.profile.CreatorNoticeWriteActivity" />
<activity android:name=".explorer.profile.follow.UserFollowerListActivity" />
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"

View File

@ -7,6 +7,8 @@ import kr.co.vividnext.sodalive.common.ApiBuilder
import kr.co.vividnext.sodalive.explorer.ExplorerApi
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
import kr.co.vividnext.sodalive.live.LiveApi
import kr.co.vividnext.sodalive.live.LiveRepository
import kr.co.vividnext.sodalive.live.LiveViewModel
@ -112,6 +114,8 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { LiveRoomViewModel(get(), get(), get()) }
viewModel { LiveRoomDonationMessageViewModel(get()) }
viewModel { ExplorerViewModel(get()) }
viewModel { UserProfileViewModel(get(), get(), get()) }
viewModel { UserFollowerListViewModel(get(), get()) }
}
private val repositoryModule = module {

View File

@ -2,9 +2,18 @@ package kr.co.vividnext.sodalive.explorer
import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.explorer.profile.GetCreatorProfileResponse
import kr.co.vividnext.sodalive.explorer.profile.PostCreatorNoticeRequest
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.follow.GetFollowerListResponse
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Path
import retrofit2.http.Query
interface ExplorerApi {
@ -18,4 +27,37 @@ interface ExplorerApi {
@Query("channel") channel: String,
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetRoomDetailUser>>>
@GET("/explorer/profile/{id}")
fun getCreatorProfile(
@Path("id") id: Long,
@Query("timezone") timezone: String,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetCreatorProfileResponse>>
@POST("/explorer/profile/cheers")
fun writeCheers(
@Body request: PostWriteCheersRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
@PUT("/explorer/profile/cheers")
fun modifyCheers(
@Body request: PutModifyCheersRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
@POST("/explorer/profile/notice")
fun writeCreatorNotice(
@Body request: PostCreatorNoticeRequest,
@Header("Authorization") authHeader: String
): Single<ApiResponse<Any>>
@GET("/explorer/profile/{id}/follower-list")
fun getFollowerList(
@Path("id") userId: Long,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetFollowerListResponse>>
}

View File

@ -1,5 +1,10 @@
package kr.co.vividnext.sodalive.explorer
import kr.co.vividnext.sodalive.explorer.profile.PostCreatorNoticeRequest
import kr.co.vividnext.sodalive.explorer.profile.cheers.PostWriteCheersRequest
import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
import java.util.TimeZone
class ExplorerRepository(
private val api: ExplorerApi
) {
@ -9,4 +14,53 @@ class ExplorerRepository(
channel = channel,
authHeader = token
)
fun getCreatorProfile(id: Long, token: String) = api.getCreatorProfile(
id = id,
timezone = TimeZone.getDefault().id,
authHeader = token
)
fun writeCheers(
parentCheersId: Long?,
creatorId: Long,
content: String,
token: String
) = api.writeCheers(
request = PostWriteCheersRequest(
parentId = parentCheersId,
creatorId = creatorId,
content = content
),
authHeader = token
)
fun modifyCheers(
cheersId: Long,
content: String,
token: String
) = api.modifyCheers(
request = PutModifyCheersRequest(
cheersId = cheersId,
content = content
),
authHeader = token
)
fun writeCreatorNotice(notice: String, token: String) = api.writeCreatorNotice(
request = PostCreatorNoticeRequest(notice),
authHeader = token
)
fun getFollowerList(
userId: Long,
page: Int,
size: Int,
token: String
) = api.getFollowerList(
userId = userId,
page = page - 1,
size = size,
authHeader = token
)
}

View File

@ -0,0 +1,73 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.content.Intent
import android.widget.Toast
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityCreatorNoticeWriteBinding
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import org.koin.android.ext.android.inject
class CreatorNoticeWriteActivity : BaseActivity<ActivityCreatorNoticeWriteBinding>(
ActivityCreatorNoticeWriteBinding::inflate
) {
private val repository: ExplorerRepository by inject()
private lateinit var loadingDialog: LoadingDialog
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "공지사항 쓰기"
binding.toolbar.tvBack.setOnClickListener { finish() }
val notice = intent.getStringExtra("notice")
binding.etContent.setText(notice)
binding.tvSave.setOnClickListener {
loadingDialog.show(screenWidth)
val writtenNotice = binding.etContent.text.toString()
compositeDisposable.add(
repository.writeCreatorNotice(
notice = writtenNotice,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
loadingDialog.dismiss()
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
Toast.makeText(
applicationContext,
message,
Toast.LENGTH_LONG
).show()
if (it.success) {
val dataIntent = Intent()
dataIntent.putExtra("notice", writtenNotice)
setResult(RESULT_OK, dataIntent)
finish()
}
},
{
loadingDialog.dismiss()
it.message?.let { message -> Logger.e(message) }
Toast.makeText(
applicationContext,
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.",
Toast.LENGTH_LONG
).show()
}
)
)
}
}
}

View File

@ -0,0 +1,17 @@
package kr.co.vividnext.sodalive.explorer.profile
import com.google.gson.annotations.SerializedName
data class GetCheersResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("cheers") val cheers: List<GetCheersResponseItem>
)
data class GetCheersResponseItem(
@SerializedName("cheersId") val cheersId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileUrl") val profileUrl: String,
@SerializedName("content") val content: String,
@SerializedName("date") val date: String,
@SerializedName("replyList") val replyList: List<GetCheersResponseItem>
)

View File

@ -0,0 +1,95 @@
package kr.co.vividnext.sodalive.explorer.profile
import com.google.gson.annotations.SerializedName
data class GetCreatorProfileResponse(
@SerializedName("creator")
val creator: CreatorResponse,
@SerializedName("userDonationRanking")
val userDonationRanking: List<UserDonationRankingResponse>,
@SerializedName("similarCreatorList")
val similarCreatorList: List<SimilarCreatorResponse>,
@SerializedName("liveRoomList")
val liveRoomList: List<LiveRoomResponse>,
@SerializedName("audioContentList")
val audioContentList: List<GetAudioContentListItem>,
@SerializedName("notice")
val notice: String,
@SerializedName("cheers")
val cheers: GetCheersResponse,
@SerializedName("activitySummary")
val activitySummary: GetCreatorActivitySummary,
@SerializedName("isBlock")
val isBlock: Boolean
)
data class CreatorResponse(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("profileUrl") val profileUrl: String,
@SerializedName("nickname") val nickname: String,
@SerializedName("tags") val tags: List<String>,
@SerializedName("introduce") val introduce: String = "",
@SerializedName("instagramUrl") val instagramUrl: String? = null,
@SerializedName("youtubeUrl") val youtubeUrl: String? = null,
@SerializedName("websiteUrl") val websiteUrl: String? = null,
@SerializedName("blogUrl") val blogUrl: String? = null,
@SerializedName("isAvailableChat") val isAvailableChat: Boolean = true,
@SerializedName("isNotification") val isNotification: Boolean,
@SerializedName("notificationRecipientCount") val notificationRecipientCount: Int
)
data class UserDonationRankingResponse(
@SerializedName("userId") val userId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImage") val profileImage: String,
@SerializedName("donationCoin") val donationCoin: Int
)
data class SimilarCreatorResponse(
@SerializedName("userId") val userId: Long,
@SerializedName("nickname") val nickname: String,
@SerializedName("profileImage") val profileImage: String,
@SerializedName("tags") val tags: List<String>
)
data class LiveRoomResponse(
@SerializedName("roomId") val roomId: Long,
@SerializedName("title") val title: String,
@SerializedName("content") val content: String,
@SerializedName("isPaid") val isPaid: Boolean,
@SerializedName("beginDateTime") val beginDateTime: String,
@SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("price") val price: Int,
@SerializedName("channelName") val channelName: String?,
@SerializedName("managerNickname") val managerNickname: String,
@SerializedName("isReservation") val isReservation: Boolean,
@SerializedName("isActive") val isActive: Boolean,
@SerializedName("isPrivateRoom") val isPrivateRoom: Boolean
)
data class GetAudioContentListResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentListItem>
)
data class GetAudioContentListItem(
@SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("title") val title: String,
@SerializedName("price") val price: Int,
@SerializedName("themeStr") val themeStr: String,
@SerializedName("duration") val duration: String?,
@SerializedName("likeCount") val likeCount: Int,
@SerializedName("commentCount") val commentCount: Int,
@SerializedName("isAdult") val isAdult: Boolean
)
data class GetCreatorActivitySummary(
@SerializedName("liveCount") val liveCount: Int,
@SerializedName("liveTime") val liveTime: Int,
@SerializedName("liveContributorCount") val liveContributorCount: Int,
@SerializedName("contentCount") val contentCount: Int
)

View File

@ -0,0 +1,8 @@
package kr.co.vividnext.sodalive.explorer.profile
import com.google.gson.annotations.SerializedName
data class PostCreatorNoticeRequest(
@SerializedName("notice")
val notice: String
)

View File

@ -1,11 +1,773 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.webkit.URLUtil
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileBinding
import kr.co.vividnext.sodalive.explorer.profile.cheers.UserProfileCheersAdapter
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAdapter
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewActivity
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewActivity
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
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.LiveRoomPasswordDialog
import kr.co.vividnext.sodalive.report.CheersReportDialog
import kr.co.vividnext.sodalive.report.ProfileReportDialog
import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.report.UserReportDialog
import org.koin.android.ext.android.inject
class UserProfileActivity: BaseActivity<ActivityUserProfileBinding>(
class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
ActivityUserProfileBinding::inflate
) {
private val viewModel: UserProfileViewModel by inject()
private val liveViewModel: LiveViewModel by inject()
private lateinit var imm: InputMethodManager
private lateinit var loadingDialog: LoadingDialog
private lateinit var liveAdapter: UserProfileLiveAdapter
private lateinit var donationAdapter: UserProfileDonationAdapter
private lateinit var similarCreatorAdapter: UserProfileSimilarCreatorAdapter
private lateinit var cheersAdapter: UserProfileCheersAdapter
private lateinit var noticeWriteLauncher: ActivityResultLauncher<Intent>
private val handler = Handler(Looper.getMainLooper())
private var userId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
super.onCreate(savedInstanceState)
imm = getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
noticeWriteLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
val writtenNotice = it.data?.getStringExtra("notice")
binding.tvNotice.text = writtenNotice?.ifBlank {
"공지사항이 없습니다."
}
}
}
if (userId <= 0) {
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
finish()
}
bindData()
}
override fun onResume() {
super.onResume()
viewModel.getCreatorProfile(userId) { finish() }
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.tvBack.text = "채널"
binding.tvBack.setOnClickListener { finish() }
binding.ivMenu.setOnClickListener {
showOptionMenu(
this,
binding.ivMenu,
)
}
binding.layoutUserProfile.ivShare.setOnClickListener {
viewModel.shareChannel(userId = userId) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TEXT, it)
val shareIntent = Intent.createChooser(intent, "채널 공유")
startActivity(shareIntent)
}
}
setupLiveView()
setupDonationView()
setupSimilarCreatorView()
setupFanTalkView()
}
private fun hideKeyboard(onAfterExecute: () -> Unit) {
handler.postDelayed({
imm.hideSoftInputFromWindow(
window.decorView.applicationWindowToken,
InputMethodManager.HIDE_NOT_ALWAYS
)
onAfterExecute()
}, 100)
}
private fun showOptionMenu(context: Context, v: View) {
val popup = PopupMenu(context, v)
val inflater = popup.menuInflater
if (viewModel.creatorProfileLiveData.value!!.isBlock) {
inflater.inflate(R.menu.user_profile_option_menu_2, popup.menu)
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_user_block -> {
viewModel.userUnBlock(userId)
}
R.id.menu_user_report -> {
showUserReportDialog()
}
R.id.menu_profile_report -> {
showProfileReportDialog()
}
}
true
}
} else {
inflater.inflate(R.menu.user_profile_option_menu, popup.menu)
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_user_block -> {
showUserBlockDialog()
}
R.id.menu_user_report -> {
showUserReportDialog()
}
R.id.menu_profile_report -> {
showProfileReportDialog()
}
}
true
}
}
popup.show()
}
private fun showUserBlockDialog() {
val dialog = AlertDialog.Builder(this)
dialog.setTitle("사용자 차단")
dialog.setMessage(
"${binding.layoutUserProfile.tvNickname.text}님을 차단하시겠습니까?\n\n" +
"사용자를 차단하면 사용자는 아래 기능이 제한됩니다.\n" +
"- 내가 개설한 라이브 입장 불가\n" +
"- 나에게 메시지 보내기 불가\n" +
"- 내 채널의 팬Talk 작성불가"
)
dialog.setPositiveButton("차단") { _, _ ->
viewModel.userBlock(userId)
}
dialog.setNegativeButton("취소") { _, _ -> }
dialog.show()
}
private fun showUserReportDialog() {
val dialog = UserReportDialog(this, layoutInflater) {
viewModel.report(
type = ReportType.USER,
userId = userId,
reason = it
)
}
dialog.show(screenWidth)
}
private fun showProfileReportDialog() {
val dialog = ProfileReportDialog(this, layoutInflater) {
viewModel.report(
type = ReportType.PROFILE,
userId = userId
)
}
dialog.show(screenWidth)
}
private fun setupLiveView() {
val recyclerView = binding.layoutUserProfileLive.rvLive
liveAdapter = UserProfileLiveAdapter(
onClickParticipant = { enterLiveRoom(roomId = it.roomId) },
onClickReservation = { reservationRoom(roomId = it.roomId) }
)
recyclerView.layoutManager = LinearLayoutManager(
applicationContext,
LinearLayoutManager.VERTICAL,
false
)
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
when (parent.getChildAdapterPosition(view)) {
liveAdapter.itemCount - 1 -> {
outRect.bottom = 0
}
else -> {
outRect.bottom = 13.3f.dpToPx().toInt()
}
}
}
})
recyclerView.adapter = liveAdapter
}
private fun setupDonationView() {
binding.layoutUserProfileDonation.tvAll.setOnClickListener {
val intent = Intent(applicationContext, UserProfileDonationAllViewActivity::class.java)
intent.putExtra(Constants.EXTRA_USER_ID, userId)
startActivity(intent)
}
val recyclerView = binding.layoutUserProfileDonation.rvDonation
donationAdapter = UserProfileDonationAdapter()
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 = 0
outRect.right = 6.7f.dpToPx().toInt()
}
donationAdapter.itemCount - 1 -> {
outRect.left = 6.7f.dpToPx().toInt()
outRect.right = 0
}
else -> {
outRect.left = 6.7f.dpToPx().toInt()
outRect.right = 6.7f.dpToPx().toInt()
}
}
}
})
recyclerView.adapter = donationAdapter
}
private fun setupSimilarCreatorView() {
val recyclerView = binding.layoutUserProfileSimilarCreator.rvSimilarCreator
similarCreatorAdapter = UserProfileSimilarCreatorAdapter {
val intent = Intent(applicationContext, UserProfileActivity::class.java)
intent.putExtra(Constants.EXTRA_USER_ID, it.userId)
startActivity(intent)
}
recyclerView.layoutManager = LinearLayoutManager(
applicationContext,
LinearLayoutManager.VERTICAL,
false
)
recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
when (parent.getChildAdapterPosition(view)) {
0 -> {
outRect.top = 0
outRect.bottom = 10f.dpToPx().toInt()
}
similarCreatorAdapter.itemCount - 1 -> {
outRect.top = 10f.dpToPx().toInt()
outRect.bottom = 0
}
else -> {
outRect.top = 10f.dpToPx().toInt()
outRect.bottom = 10f.dpToPx().toInt()
}
}
}
})
recyclerView.adapter = similarCreatorAdapter
}
private fun setupFanTalkView() {
binding.layoutUserProfileFanTalk.tvAll.setOnClickListener {
val intent = Intent(
applicationContext,
UserProfileFantalkAllViewActivity::class.java
)
intent.putExtra(Constants.EXTRA_USER_ID, userId)
startActivity(intent)
}
setupCheersView()
}
private fun setupCheersView() {
binding.layoutUserProfileFanTalk.ivSend.setOnClickListener {
hideKeyboard {
viewModel.writeCheers(
creatorId = userId,
cheersContent = binding.layoutUserProfileFanTalk.etCheer.text.toString()
)
}
}
val rvCheers = binding.layoutUserProfileFanTalk.rvCheers
cheersAdapter = UserProfileCheersAdapter(
userId = userId,
enterReply = { cheersId, content ->
hideKeyboard {
viewModel.writeCheers(
parentCheersId = cheersId,
creatorId = userId,
cheersContent = content
)
}
},
modifyReply = { cheersId, content ->
hideKeyboard {
viewModel.modifyCheers(
cheersId = cheersId,
creatorId = userId,
cheersContent = content
)
}
},
onClickReport = { showCheersReportPopup(it) }
)
rvCheers.layoutManager = LinearLayoutManager(
applicationContext,
LinearLayoutManager.VERTICAL,
false
)
rvCheers.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.bottom = 0
when (parent.getChildAdapterPosition(view)) {
0 -> {
outRect.top = 0
}
cheersAdapter.itemCount - 1 -> {
outRect.top = 10.dpToPx().toInt()
outRect.bottom = 10.dpToPx().toInt()
}
else -> {
outRect.top = 10.dpToPx().toInt()
}
}
}
})
rvCheers.adapter = cheersAdapter
}
private fun showCheersReportPopup(cheersId: Long) {
val dialog = CheersReportDialog(this, layoutInflater) {
if (it.isBlank()) {
Toast.makeText(
applicationContext,
"신고 이유를 선택해 주세요.",
Toast.LENGTH_LONG
).show()
} else {
viewModel.cheersReport(cheersId, reason = it)
}
}
dialog.show(screenWidth)
}
private fun bindData() {
liveViewModel.toastLiveData.observe(this) {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
}
liveViewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth, "")
} else {
loadingDialog.dismiss()
}
}
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.creatorProfileLiveData.observe(this) {
setCheers(it.cheers)
setCreatorProfile(it.creator)
setCreatorNotice(it.notice, it.creator.creatorId)
setLiveRoomList(it.liveRoomList)
setSimilarCreatorList(it.similarCreatorList)
setUserDonationRanking(it.userDonationRanking)
setActivitySummary(it.activitySummary)
}
viewModel.isExpandNotice.observe(this) {
if (it) {
binding.tvNotice.maxLines = Int.MAX_VALUE
} else {
binding.tvNotice.maxLines = 1
}
}
}
private fun setActivitySummary(activitySummary: GetCreatorActivitySummary) {
binding.tvLiveCount.text = activitySummary.liveCount.moneyFormat()
binding.tvLiveContributorCount.text = activitySummary.liveContributorCount.moneyFormat()
binding.tvLiveTime.text = activitySummary.liveTime.moneyFormat()
binding.tvContentCount.text = activitySummary.contentCount.moneyFormat()
}
@SuppressLint("NotifyDataSetChanged")
private fun setCheers(cheers: GetCheersResponse) {
binding.layoutUserProfileFanTalk.etCheer.setText("")
cheersAdapter.items.clear()
binding.layoutUserProfileFanTalk.tvCheersCount.text = cheers.totalCount.toString()
cheersAdapter.items.addAll(cheers.cheers)
cheersAdapter.notifyDataSetChanged()
if (cheersAdapter.itemCount <= 0) {
binding.layoutUserProfileFanTalk.rvCheers.visibility = View.GONE
binding.layoutUserProfileFanTalk.tvNoCheers.visibility = View.VISIBLE
} else {
binding.layoutUserProfileFanTalk.rvCheers.visibility = View.VISIBLE
binding.layoutUserProfileFanTalk.tvNoCheers.visibility = View.GONE
}
}
@SuppressLint("SetTextI18n")
private fun setCreatorProfile(creator: CreatorResponse) {
val layoutUserProfile = binding.layoutUserProfile
if (creator.creatorId == SharedPreferenceManager.userId) {
layoutUserProfile.tvFollowerList.visibility = View.VISIBLE
layoutUserProfile.llNotification.visibility = View.GONE
layoutUserProfile.tvFollowerList.setOnClickListener {
val intent = Intent(applicationContext, UserFollowerListActivity::class.java)
intent.putExtra(Constants.EXTRA_USER_ID, creator.creatorId)
startActivity(intent)
}
} else {
layoutUserProfile.llNotification.visibility = View.VISIBLE
layoutUserProfile.tvFollowerList.visibility = View.GONE
}
layoutUserProfile.ivProfile.load(creator.profileUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation())
}
binding.tvBack.text = "${creator.nickname}님의 채널"
layoutUserProfile.tvNickname.text = creator.nickname
layoutUserProfile.tvTags.text = creator.tags.joinToString(" ") { "#$it" }
if (creator.websiteUrl.isNullOrBlank() || !URLUtil.isValidUrl(creator.websiteUrl)) {
layoutUserProfile.ivWebsite.visibility = View.GONE
} else {
layoutUserProfile.ivWebsite.visibility = View.VISIBLE
layoutUserProfile.ivWebsite.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(creator.websiteUrl)))
}
}
if (creator.blogUrl.isNullOrBlank() || !URLUtil.isValidUrl(creator.blogUrl)) {
layoutUserProfile.ivBlog.visibility = View.GONE
} else {
layoutUserProfile.ivBlog.visibility = View.VISIBLE
layoutUserProfile.ivBlog.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(creator.blogUrl)))
}
}
if (creator.instagramUrl.isNullOrBlank() || !URLUtil.isValidUrl(creator.instagramUrl)) {
layoutUserProfile.ivInstagram.visibility = View.GONE
} else {
layoutUserProfile.ivInstagram.visibility = View.VISIBLE
layoutUserProfile.ivInstagram.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(creator.instagramUrl)))
}
}
if (creator.youtubeUrl.isNullOrBlank() || !URLUtil.isValidUrl(creator.youtubeUrl)) {
layoutUserProfile.ivYoutube.visibility = View.GONE
} else {
layoutUserProfile.ivYoutube.visibility = View.VISIBLE
layoutUserProfile.ivYoutube.setOnClickListener {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(creator.youtubeUrl)))
}
}
if (creator.isNotification) {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_notification_selected)
layoutUserProfile.ivNotification.setOnClickListener {
viewModel.unFollow(creator.creatorId)
}
} else {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_notification)
layoutUserProfile.ivNotification.setOnClickListener {
viewModel.follow(creator.creatorId)
}
}
layoutUserProfile
.tvNotificationCount
.text = "팔로워 ${creator.notificationRecipientCount.moneyFormat()}"
val introduce = creator.introduce.ifBlank {
"채널 소개내용이 없습니다."
}
binding.layoutUserProfileIntroduce.tvIntroduce.text = introduce
}
private fun setCreatorNotice(notice: String, creatorId: Long) {
binding.tvNotice.text = notice.ifBlank {
"공지사항이 없습니다."
}
binding.rlNotice.setOnClickListener {
if (creatorId == SharedPreferenceManager.userId) {
val intent = Intent(applicationContext, CreatorNoticeWriteActivity::class.java)
intent.putExtra("notice", notice)
noticeWriteLauncher.launch(intent)
} else {
viewModel.toggleExpandNotice()
}
}
binding.ivWrite.visibility = if (creatorId == SharedPreferenceManager.userId) {
View.VISIBLE
} else {
View.GONE
}
}
@SuppressLint("NotifyDataSetChanged")
private fun setLiveRoomList(liveRoomList: List<LiveRoomResponse>) {
if (liveRoomList.isEmpty()) {
binding.layoutUserProfileLive.root.visibility = View.GONE
} else {
binding.layoutUserProfileLive.root.visibility = View.VISIBLE
liveAdapter.items.clear()
liveAdapter.items.addAll(liveRoomList)
liveAdapter.notifyDataSetChanged()
}
}
@SuppressLint("NotifyDataSetChanged")
private fun setSimilarCreatorList(similarCreatorList: List<SimilarCreatorResponse>) {
if (similarCreatorList.isEmpty()) {
binding.llUserProfileSimilarCreator.visibility = View.GONE
} else {
binding.llUserProfileSimilarCreator.visibility = View.VISIBLE
similarCreatorAdapter.items.clear()
similarCreatorAdapter.items.addAll(similarCreatorList)
similarCreatorAdapter.notifyDataSetChanged()
}
}
@SuppressLint("NotifyDataSetChanged")
private fun setUserDonationRanking(userDonationRanking: List<UserDonationRankingResponse>) {
if (userDonationRanking.isEmpty()) {
binding.llUserProfileDonation.visibility = View.GONE
} else {
binding.llUserProfileDonation.visibility = View.VISIBLE
donationAdapter.items.clear()
donationAdapter.items.addAll(userDonationRanking)
donationAdapter.notifyDataSetChanged()
}
}
private fun reservationRoom(roomId: Long) {
liveViewModel.getRoomDetail(roomId) {
if (it.manager.id == SharedPreferenceManager.userId) {
showToast("내가 만든 라이브는 예약할 수 없습니다.")
} else {
if (it.isPrivateRoom) {
LiveRoomPasswordDialog(
activity = this,
layoutInflater = layoutInflater,
can = if (it.isPaid) 0 else it.price,
confirmButtonClick = { password ->
handler.postDelayed({
processLiveReservation(roomId, password)
}, 300)
}
).show(screenWidth)
} else {
if (it.price == 0 || it.isPaid) {
processLiveReservation(roomId)
} else {
LivePaymentDialog(
activity = this,
layoutInflater = layoutInflater,
title = "${it.price.moneyFormat()}캔으로 예약",
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
confirmButtonTitle = "예약하기",
confirmButtonClick = { processLiveReservation(roomId) },
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
}
}
}
}
}
private fun processLiveReservation(roomId: Long, password: String? = null) {
liveViewModel.reservationRoom(roomId, password) {
val intent = Intent(
applicationContext,
LiveReservationCompleteActivity::class.java
)
intent.putExtra(Constants.EXTRA_LIVE_RESERVATION_RESPONSE, it)
startActivity(intent)
}
}
private fun enterLiveRoom(roomId: Long) {
val onEnterRoomSuccess = {
runOnUiThread {
val intent = Intent(applicationContext, LiveRoomActivity::class.java)
intent.putExtra(Constants.EXTRA_ROOM_ID, roomId)
startActivity(intent)
}
}
liveViewModel.getRoomDetail(roomId) {
if (it.channelName != null) {
if (it.manager.id == SharedPreferenceManager.userId) {
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
} else if (it.price == 0 || it.isPaid) {
if (it.isPrivateRoom) {
LiveRoomPasswordDialog(
activity = this,
layoutInflater = layoutInflater,
can = 0,
confirmButtonClick = { password ->
liveViewModel.enterRoom(
roomId = roomId,
onSuccess = onEnterRoomSuccess,
password = password
)
}
).show(screenWidth)
} else {
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
}
} else {
if (it.isPrivateRoom) {
LiveRoomPasswordDialog(
activity = this,
layoutInflater = layoutInflater,
can = it.price,
confirmButtonClick = { password ->
liveViewModel.enterRoom(
roomId = roomId,
onSuccess = onEnterRoomSuccess,
password = password
)
}
).show(screenWidth)
} else {
LivePaymentDialog(
activity = this,
layoutInflater = layoutInflater,
title = "${it.price.moneyFormat()}캔으로 입장",
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
confirmButtonTitle = "결제 후 입장",
confirmButtonClick = {
liveViewModel.enterRoom(roomId, onEnterRoomSuccess)
},
cancelButtonTitle = "취소",
cancelButtonClick = {}
).show(screenWidth)
}
}
}
}
}
}

View File

@ -0,0 +1,139 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemUserProfileLiveBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class UserProfileLiveAdapter(
private val onClickParticipant: (LiveRoomResponse) -> Unit,
private val onClickReservation: (LiveRoomResponse) -> Unit
) : RecyclerView.Adapter<UserProfileLiveAdapter.ViewHolder>() {
val items = mutableListOf<LiveRoomResponse>()
inner class ViewHolder(
private val context: Context,
private val binding: ItemUserProfileLiveBinding
) : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: LiveRoomResponse) {
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
}
binding.iv19.visibility = if (item.isAdult) {
View.VISIBLE
} else {
View.GONE
}
binding.tvDate.text = item.beginDateTime
binding.tvNickname.text = item.managerNickname
binding.tvTitle.text = item.title
if (item.isActive && !item.channelName.isNullOrBlank()) {
binding.bgCover.visibility = View.GONE
binding.tvStatus.text = "LIVE"
binding.tvStatus.setTextColor(ContextCompat.getColor(context, R.color.color_ff5c49))
binding.tvStatus.setBackgroundResource(
R.drawable.bg_round_corner_3_3_transparent_ff5c49
)
binding.tvParticipate.text = if (!item.isPaid && item.price > 0) {
"${item.price}캔으로 지금 참여하기"
} else {
"지금 참여하기"
}
binding.tvParticipate.setOnClickListener { onClickParticipant(item) }
binding.tvParticipate.setTextColor(
ContextCompat.getColor(
context,
R.color.white
)
)
binding.tvParticipate.setBackgroundResource(
R.drawable.bg_round_corner_5_3_dd4500
)
} else if (item.isActive && item.channelName.isNullOrBlank()) {
binding.bgCover.visibility = View.GONE
binding.tvStatus.text = "예정"
binding.tvStatus.setTextColor(ContextCompat.getColor(context, R.color.color_fdca2f))
binding.tvStatus.setBackgroundResource(
R.drawable.bg_round_corner_3_3_transparent_fdca2f
)
if (item.isReservation) {
binding.tvParticipate.text = "예약완료"
binding.tvParticipate.setTextColor(
ContextCompat.getColor(context, R.color.color_777777)
)
binding.tvParticipate.setBackgroundResource(
R.drawable.bg_round_corner_5_3_525252
)
} else {
binding.tvParticipate.text = if (item.price > 0) {
"${item.price}캔으로 예약하기"
} else {
"예약하기"
}
binding.tvParticipate.setOnClickListener { onClickReservation(item) }
binding.tvParticipate.setTextColor(
ContextCompat.getColor(
context,
R.color.black
)
)
binding.tvParticipate.setBackgroundResource(
R.drawable.bg_round_corner_5_3_fdca2f
)
}
} else {
binding.bgCover.visibility = View.VISIBLE
binding.tvStatus.text = "종료"
binding.tvStatus.setTextColor(ContextCompat.getColor(context, R.color.color_777777))
binding.tvStatus.setBackgroundResource(
R.drawable.bg_round_corner_3_3_transparent_777777
)
binding.tvParticipate.text = "다시듣기를 지원하지 않습니다"
binding.tvParticipate.setTextColor(
ContextCompat.getColor(context, R.color.color_777777)
)
binding.tvParticipate.setBackgroundResource(
R.drawable.bg_round_corner_5_3_525252
)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
parent.context,
ItemUserProfileLiveBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.count()
}

View File

@ -0,0 +1,46 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemUserProfileSimilarCreatorBinding
class UserProfileSimilarCreatorAdapter(
private val onClickItem: (SimilarCreatorResponse) -> Unit
) : RecyclerView.Adapter<UserProfileSimilarCreatorAdapter.ViewHolder>() {
val items = mutableListOf<SimilarCreatorResponse>()
inner class ViewHolder(
private val binding: ItemUserProfileSimilarCreatorBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: SimilarCreatorResponse) {
binding.ivProfile.load(item.profileImage) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation())
}
binding.tvNickname.text = item.nickname
binding.tvTags.text = item.tags.joinToString(" ") { "#$it" }
binding.root.setOnClickListener { onClickItem(item) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
ItemUserProfileSimilarCreatorBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.count()
}

View File

@ -0,0 +1,375 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.google.firebase.dynamiclinks.ShortDynamicLink
import com.google.firebase.dynamiclinks.ktx.androidParameters
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
import com.google.firebase.dynamiclinks.ktx.iosParameters
import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
import com.google.firebase.ktx.Firebase
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.user.UserRepository
class UserProfileViewModel(
private val repository: ExplorerRepository,
private val reportRepository: ReportRepository,
private val userRepository: UserRepository
) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private var _creatorProfileLiveData = MutableLiveData<GetCreatorProfileResponse>()
val creatorProfileLiveData: LiveData<GetCreatorProfileResponse>
get() = _creatorProfileLiveData
private val _isExpandNotice = MutableLiveData(false)
val isExpandNotice: LiveData<Boolean>
get() = _isExpandNotice
private var creatorNickname = ""
fun cheersReport(cheersId: Long, reason: String) {
_isLoading.value = true
val request = ReportRequest(ReportType.CHEERS, reason, cheersId = cheersId)
compositeDisposable.add(
reportRepository.report(
request = request,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"신고가 접수되었습니다."
)
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("신고가 접수되었습니다.")
}
)
)
}
fun report(type: ReportType, userId: Long, reason: String = "프로필 신고") {
_isLoading.value = true
val request = ReportRequest(type, reason, reportedAccountId = userId)
compositeDisposable.add(
reportRepository.report(
request = request,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"신고가 접수되었습니다."
)
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("신고가 접수되었습니다.")
}
)
)
}
fun getCreatorProfile(userId: Long, onFailure: (() -> Unit)? = null) {
_isLoading.value = true
compositeDisposable.add(
repository.getCreatorProfile(
id = userId,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
val data = it.data
_creatorProfileLiveData.postValue(data!!)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
if (onFailure != null) {
onFailure()
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
if (onFailure != null) {
onFailure()
}
}
)
)
}
fun follow(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
getCreatorProfile(creatorId)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unFollow(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
getCreatorProfile(creatorId)
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun toggleExpandNotice() {
_isExpandNotice.value = !isExpandNotice.value!!
}
fun writeCheers(parentCheersId: Long? = null, creatorId: Long, cheersContent: String) {
if (cheersContent.isBlank()) {
_toastLiveData.postValue("내용을 입력하세요")
return
}
_isLoading.value = true
compositeDisposable.add(
repository.writeCheers(
parentCheersId = parentCheersId,
creatorId = creatorId,
content = cheersContent,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
getCreatorProfile(creatorId)
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun modifyCheers(cheersId: Long, creatorId: Long, cheersContent: String) {
if (cheersContent.isBlank()) {
_toastLiveData.postValue("내용을 입력하세요")
return
}
_isLoading.value = true
compositeDisposable.add(
repository.modifyCheers(
cheersId = cheersId,
content = cheersContent,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
getCreatorProfile(creatorId)
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun shareChannel(userId: Long, onSuccess: (String) -> Unit) {
_isLoading.value = true
Firebase.dynamicLinks.shortLinkAsync(ShortDynamicLink.Suffix.SHORT) {
link = Uri.parse("https://yozm.day/?channel_id=$userId")
domainUriPrefix = "https://yozm.page.link"
androidParameters { }
iosParameters("kr.co.vividnext.yozm") {
appStoreId = "1630284226"
}
}.addOnSuccessListener {
val uri = it.shortLink
if (uri != null) {
onSuccess("요즘라이브 ${creatorNickname}님의 채널입니다.\n$uri")
}
}.addOnFailureListener {
_toastLiveData.postValue("공유링크를 생성하지 못했습니다.\n다시 시도해 주세요.")
}.addOnCompleteListener {
_isLoading.value = false
}
}
fun userBlock(userId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.memberBlock(
userId = userId,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
getCreatorProfile(userId)
_toastLiveData.postValue("차단하였습니다.")
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun userUnBlock(userId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.memberUnBlock(
userId = userId,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success) {
getCreatorProfile(userId)
_toastLiveData.postValue("차단이 해제 되었습니다.")
} else {
val message = it.message ?: "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
_toastLiveData.postValue(message)
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}

View File

@ -0,0 +1,9 @@
package kr.co.vividnext.sodalive.explorer.profile.cheers
import com.google.gson.annotations.SerializedName
data class PostWriteCheersRequest(
@SerializedName("parentId") val parentId: Long? = null,
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("content") val content: String
)

View File

@ -0,0 +1,8 @@
package kr.co.vividnext.sodalive.explorer.profile.cheers
import com.google.gson.annotations.SerializedName
data class PutModifyCheersRequest(
@SerializedName("cheersId") val cheersId: Long,
@SerializedName("content") val content: String
)

View File

@ -0,0 +1,126 @@
package kr.co.vividnext.sodalive.explorer.profile.cheers
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ItemUserProfileCheersBinding
import kr.co.vividnext.sodalive.explorer.profile.GetCheersResponseItem
import kr.co.vividnext.sodalive.extensions.dpToPx
class UserProfileCheersAdapter(
private val userId: Long,
private val enterReply: (Long, String) -> Unit,
private val modifyReply: (Long, String) -> Unit,
private val onClickReport: (Long) -> Unit
) : RecyclerView.Adapter<UserProfileCheersAdapter.ViewHolder>() {
val items = mutableListOf<GetCheersResponseItem>()
inner class ViewHolder(
private val context: Context,
private val binding: ItemUserProfileCheersBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(cheers: GetCheersResponseItem) {
binding.tvWriteReply.visibility = View.GONE
binding.llCheerReply.visibility = View.GONE
binding.rlCheerReply.visibility = View.GONE
binding.ivProfile.load(cheers.profileUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(16.7f.dpToPx()))
}
binding.tvContent.text = cheers.content
binding.tvNickname.text = cheers.nickname
binding.tvDate.text = cheers.date
binding.ivMenu.setOnClickListener {
showOptionMenu(
context,
binding.ivMenu,
cheersId = cheers.cheersId
)
}
if (cheers.replyList.isNotEmpty()) {
binding.tvWriteReply.visibility = View.GONE
binding.llCheerReply.visibility = View.VISIBLE
val reply = cheers.replyList[0]
binding.tvReply.text = reply.content
binding.tvReplyDate.text = reply.date
if (userId == SharedPreferenceManager.userId) {
binding.tvModifyReply.visibility = View.VISIBLE
binding.tvModifyReply.setOnClickListener {
binding.etCheerReply.setText(binding.tvReply.text)
binding.rlCheerReply.visibility = View.VISIBLE
binding.tvSend.setOnClickListener {
val content = binding.etCheerReply.text.toString()
modifyReply(reply.cheersId, content)
}
}
} else {
binding.tvModifyReply.visibility = View.GONE
}
} else {
if (userId == SharedPreferenceManager.userId) {
binding.tvWriteReply.visibility = View.VISIBLE
binding.tvWriteReply.setOnClickListener {
binding.tvWriteReply.visibility = View.GONE
binding.rlCheerReply.visibility = View.VISIBLE
binding.tvSend.setOnClickListener {
val content = binding.etCheerReply.text.toString()
enterReply(cheers.cheersId, content)
}
}
} else {
binding.tvWriteReply.visibility = View.GONE
}
}
binding.tvReply.requestLayout()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
parent.context,
ItemUserProfileCheersBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.count()
private fun showOptionMenu(context: Context, v: View, cheersId: Long) {
val popup = PopupMenu(context, v)
val inflater = popup.menuInflater
inflater.inflate(R.menu.review_option_menu, popup.menu)
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_review_report -> {
onClickReport(cheersId)
}
}
true
}
popup.show()
}
}

View File

@ -0,0 +1,76 @@
package kr.co.vividnext.sodalive.explorer.profile.donation
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemUserProfileDonationBinding
import kr.co.vividnext.sodalive.explorer.profile.UserDonationRankingResponse
class UserProfileDonationAdapter : RecyclerView.Adapter<UserProfileDonationAdapter.ViewHolder>() {
val items = mutableListOf<UserDonationRankingResponse>()
inner class ViewHolder(
private val binding: ItemUserProfileDonationBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: UserDonationRankingResponse, position: Int) {
binding.tvNickname.text = item.nickname
binding.ivProfile.load(item.profileImage) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation())
}
when (position) {
0 -> {
binding.ivBg.setImageResource(R.drawable.bg_circle_ffdc00_ffb600)
binding.ivBg.visibility = View.VISIBLE
binding.ivCrown.setImageResource(R.drawable.ic_crown_1)
binding.ivCrown.visibility = View.VISIBLE
}
1 -> {
binding.ivBg.setImageResource(R.drawable.bg_circle_ffffff_9f9f9f)
binding.ivBg.visibility = View.VISIBLE
binding.ivCrown.setImageResource(R.drawable.ic_crown_2)
binding.ivCrown.visibility = View.VISIBLE
}
2 -> {
binding.ivBg.setImageResource(R.drawable.bg_circle_e6a77a_c67e4a)
binding.ivBg.visibility = View.VISIBLE
binding.ivCrown.setImageResource(R.drawable.ic_crown_3)
binding.ivCrown.visibility = View.VISIBLE
}
else -> {
binding.ivBg.setImageResource(0)
binding.ivBg.visibility = View.GONE
binding.ivCrown.visibility = View.GONE
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
ItemUserProfileDonationBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position], position)
}
override fun getItemCount() = items.count()
}

View File

@ -0,0 +1,10 @@
package kr.co.vividnext.sodalive.explorer.profile.donation
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileLiveAllBinding
class UserProfileDonationAllViewActivity : BaseActivity<ActivityUserProfileLiveAllBinding>(
ActivityUserProfileLiveAllBinding::inflate
) {
override fun setupView() {}
}

View File

@ -0,0 +1,10 @@
package kr.co.vividnext.sodalive.explorer.profile.fantalk
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.databinding.ActivityUserProfileFantalkAllBinding
class UserProfileFantalkAllViewActivity : BaseActivity<ActivityUserProfileFantalkAllBinding>(
ActivityUserProfileFantalkAllBinding::inflate
) {
override fun setupView() {}
}

View File

@ -0,0 +1,15 @@
package kr.co.vividnext.sodalive.explorer.profile.follow
import com.google.gson.annotations.SerializedName
data class GetFollowerListResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetFollowerListResponseItem>
)
data class GetFollowerListResponseItem(
@SerializedName("userId") val userId: Long,
@SerializedName("profileImage") val profileImage: String,
@SerializedName("nickname") val nickname: String,
@SerializedName("isFollow") val isFollow: Boolean?
)

View File

@ -0,0 +1,116 @@
package kr.co.vividnext.sodalive.explorer.profile.follow
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.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityUserFollowerListBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
import org.koin.android.ext.android.inject
class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
ActivityUserFollowerListBinding::inflate
) {
private val viewModel: UserFollowerListViewModel by inject()
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: UserFollowerListAdapter
private var userId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
if (userId <= 0) {
Toast.makeText(
applicationContext,
"잘못된 요청입니다.\n다시 시도해 주세요.",
Toast.LENGTH_LONG
).show()
finish()
}
super.onCreate(savedInstanceState)
bindData()
viewModel.getFollowerList()
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "팔로워 리스트"
binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = UserFollowerListAdapter(
onClickRegisterNotification = { viewModel.registerNotification(it) },
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) }
)
binding.rvFollowerList.layoutManager = LinearLayoutManager(
applicationContext,
LinearLayoutManager.VERTICAL,
false
)
binding.rvFollowerList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as? LinearLayoutManager
if (
layoutManager != null &&
layoutManager.findLastCompletelyVisibleItemPosition() == adapter.itemCount - 1
) {
viewModel.getFollowerList()
}
}
})
binding.rvFollowerList.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.left = 20f.dpToPx().toInt()
outRect.right = 20f.dpToPx().toInt()
}
})
binding.rvFollowerList.adapter = adapter
}
private fun bindData() {
viewModel.userId = userId
viewModel.followerListItemsLiveData.observe(this) {
adapter.addAll(it)
}
viewModel.totalCountLiveData.observe(this) {
binding.tvCount.text = it.moneyFormat()
}
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()
}
}
}
}

View File

@ -0,0 +1,75 @@
package kr.co.vividnext.sodalive.explorer.profile.follow
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class UserFollowerListAdapter(
private val onClickRegisterNotification: (Long) -> Unit,
private val onClickUnRegisterNotification: (Long) -> Unit,
) : RecyclerView.Adapter<UserFollowerListAdapter.ViewHolder>() {
private val items = mutableListOf<GetFollowerListResponseItem>()
inner class ViewHolder(
private val binding: ItemFollowerListBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetFollowerListResponseItem) {
binding.tvNickname.text = item.nickname
binding.ivProfile.load(item.profileImage) {
transformations(CircleCropTransformation())
placeholder(R.drawable.bg_placeholder)
crossfade(true)
}
if (item.isFollow != null) {
binding.ivNotification.visibility = View.VISIBLE
if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_notification_selected)
binding.ivNotification.setOnClickListener {
onClickUnRegisterNotification(item.userId)
clear()
}
} else {
binding.ivNotification.setImageResource(R.drawable.btn_notification)
binding.ivNotification.setOnClickListener {
onClickRegisterNotification(item.userId)
clear()
}
}
} else {
binding.ivNotification.visibility = View.GONE
}
}
}
@SuppressLint("NotifyDataSetChanged")
fun addAll(items: List<GetFollowerListResponseItem>) {
this.items.addAll(items)
notifyDataSetChanged()
}
fun clear() {
this.items.clear()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
ItemFollowerListBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount() = items.size
}

View File

@ -0,0 +1,156 @@
package kr.co.vividnext.sodalive.explorer.profile.follow
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.user.UserRepository
class UserFollowerListViewModel(
private val repository: ExplorerRepository,
private val userRepository: UserRepository
) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?>
get() = _toastLiveData
private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean>
get() = _isLoading
private var _totalCountLiveData = MutableLiveData(0)
val totalCountLiveData: LiveData<Int>
get() = _totalCountLiveData
private var _followerListItemsLiveData = MutableLiveData<List<GetFollowerListResponseItem>>()
val followerListItemsLiveData: LiveData<List<GetFollowerListResponseItem>>
get() = _followerListItemsLiveData
var userId: Long = 0
var page = 1
private var isLast = false
private val pageSize = 10
fun getFollowerList() {
if (!isLast && !_isLoading.value!!) {
_isLoading.value = true
compositeDisposable.add(
repository.getFollowerList(
userId,
page,
pageSize,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
val data = it.data
_totalCountLiveData.value = data.totalCount
if (data.items.isEmpty()) {
isLast = true
} else {
page += 1
_followerListItemsLiveData.value = data.items
}
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
)
)
}
}
fun registerNotification(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
page = 1
isLast = false
getFollowerList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unRegisterNotification(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
page = 1
isLast = false
getFollowerList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}

View File

@ -540,7 +540,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
LivePaymentDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = "${it.price.moneyFormat()}코인으로 예약",
title = "${it.price.moneyFormat()}으로 예약",
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
confirmButtonTitle = "예약하기",
confirmButtonClick = { processLiveReservation(roomId) },
@ -627,7 +627,7 @@ class LiveFragment : BaseFragment<FragmentLiveBinding>(FragmentLiveBinding::infl
LivePaymentDialog(
activity = requireActivity(),
layoutInflater = layoutInflater,
title = "${it.price.moneyFormat()}코인으로 입장",
title = "${it.price.moneyFormat()}으로 입장",
desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
confirmButtonTitle = "결제 후 입장",
confirmButtonClick = {

View File

@ -99,7 +99,7 @@ class LiveReservationAdapter(
binding.tvPrice.text = if (item.price <= 0) {
"무료"
} else {
"${item.price.moneyFormat()}코인"
"${item.price.moneyFormat()}"
}
}

View File

@ -344,7 +344,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
if (can > 0) {
donation(can, message)
} else {
showToast("1코인 이상 후원하실 수 있습니다.")
showToast("1 이상 후원하실 수 있습니다.")
}
}

View File

@ -527,7 +527,7 @@ class LiveRoomViewModel(
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"후원에 실패한 코인이 환불되지 않았습니다\n고객센터로 문의해주세요."
"후원에 실패한 이 환불되지 않았습니다\n고객센터로 문의해주세요."
)
}
}
@ -536,7 +536,7 @@ class LiveRoomViewModel(
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue(
"후원에 실패한 코인이 환불되지 않았습니다\n고객센터로 문의해주세요."
"후원에 실패한 이 환불되지 않았습니다\n고객센터로 문의해주세요."
)
}
)

View File

@ -259,7 +259,7 @@ data class LiveRoomDonationChat(
)
),
0,
chat.indexOf("코인", 0, true) + 2,
chat.indexOf("", 0, true) + 2,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)

View File

@ -39,7 +39,7 @@ class CanStatusActivity : BaseActivity<ActivityCanStatusBinding>(
}
override fun setupView() {
binding.toolbar.tvBack.text = "코인내역"
binding.toolbar.tvBack.text = "내역"
binding.toolbar.tvBack.setOnClickListener { onClickBackButton() }
binding.llChargeCan.setOnClickListener {
startActivity(

View File

@ -0,0 +1,59 @@
package kr.co.vividnext.sodalive.report
import android.app.Activity
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.WindowManager
import android.widget.RadioButton
import androidx.appcompat.app.AlertDialog
import kr.co.vividnext.sodalive.databinding.DialogReviewReportBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class CheersReportDialog(
activity: Activity,
layoutInflater: LayoutInflater,
confirmButtonClick: (String) -> Unit
) {
private val alertDialog: AlertDialog
val dialogView = DialogReviewReportBinding.inflate(layoutInflater)
var reason = ""
init {
val dialogBuilder = AlertDialog.Builder(activity)
dialogBuilder.setView(dialogView.root)
alertDialog = dialogBuilder.create()
alertDialog.setCancelable(false)
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialogView.tvTitle.text = "응원글 신고"
dialogView.tvCancel.setOnClickListener {
alertDialog.dismiss()
}
dialogView.tvReport.setOnClickListener {
alertDialog.dismiss()
confirmButtonClick(reason)
}
dialogView.radioGroup.setOnCheckedChangeListener { radioGroup, checkedId ->
val radioButton = radioGroup.findViewById<RadioButton>(checkedId)
reason = radioButton.text.toString()
}
}
fun show(width: Int) {
alertDialog.show()
val lp = WindowManager.LayoutParams()
lp.copyFrom(alertDialog.window?.attributes)
lp.width = width - (26.7f.dpToPx()).toInt()
lp.height = WindowManager.LayoutParams.WRAP_CONTENT
alertDialog.window?.attributes = lp
}
}

View File

@ -46,4 +46,20 @@ class UserRepository(private val userApi: UserApi) {
userId: Long,
token: String
) = userApi.memberUnBlock(request = MemberBlockRequest(userId), authHeader = token)
fun creatorFollow(
creatorId: Long,
token: String
) = userApi.creatorFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
fun creatorUnFollow(
creatorId: Long,
token: String
) = userApi.creatorUnFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

View 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_232323" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_232323" />
</shape>

View 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_232323" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View 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_4c9970ff" />
<corners android:radius="16.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_4c9970ff" />
</shape>

View 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="@android:color/transparent" />
<corners android:radius="16.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View 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="@android:color/transparent" />
<corners android:radius="3.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_777777" />
</shape>

View 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="@android:color/transparent" />
<corners android:radius="3.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_fdca2f" />
</shape>

View 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="@android:color/transparent" />
<corners android:radius="3.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_ff5c49" />
</shape>

View 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_88909090" />
<corners android:radius="4.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_88909090" />
</shape>

View 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="5.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_525252" />
</shape>

View 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_9970ff" />
<corners android:radius="5.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View 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_dd4500" />
<corners android:radius="5.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_dd4500" />
</shape>

View 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_fdca2f" />
<corners android:radius="5.3dp" />
<stroke
android:width="1dp"
android:color="@color/color_fdca2f" />
</shape>

View 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_222222" />
<corners android:radius="16.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_9970ff" />
</shape>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/et_content"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="20dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="top"
android:hint="공지사항을 입력해 주세요"
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:padding="20dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginVertical="20dp"
android:background="@drawable/bg_round_corner_5_3_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="11.7dp"
android:text="저장"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_marginTop="26.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="전체"
android:textColor="@color/white"
android:textSize="18.3sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<TextView
android:id="@+id/tv_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textSize="18.3sp"
app:layout_constraintStart_toEndOf="@+id/tv_title"
app:layout_constraintTop_toTopOf="@+id/tv_title"
tools:text="1,503" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_follower_list"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingTop="13.3dp"
android:paddingBottom="26.7dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,6 +1,311 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
</androidx.constraintlayout.widget.ConstraintLayout>
<RelativeLayout
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="51.7dp"
android:background="@color/black"
android:paddingHorizontal="13.3dp">
<TextView
android:id="@+id/tv_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/iv_menu"
android:drawablePadding="6.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp"
app:drawableStartCompat="@drawable/ic_back"
tools:ignore="RelativeOverlap"
tools:text="바로, 상담 가능한 요즘친구" />
<ImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:paddingHorizontal="6.7dp"
android:src="@drawable/ic_seemore_vertical" />
</RelativeLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/toolbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/layout_user_profile"
layout="@layout/layout_user_profile" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:background="@drawable/bg_round_corner_8_222222_9970ff"
android:baselineAligned="false"
android:gravity="center"
android:padding="13.3dp">
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/tv_title_live_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="라이브\n횟수"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_live_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title_live_count"
android:layout_centerHorizontal="true"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="10" />
</RelativeLayout>
<FrameLayout
android:layout_width="1dp"
android:layout_height="33.3dp"
android:layout_marginHorizontal="10dp"
android:background="@color/color_9970ff" />
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/tv_title_live_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="라이브\n시간"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_live_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title_live_time"
android:layout_centerHorizontal="true"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="10" />
</RelativeLayout>
<FrameLayout
android:layout_width="1dp"
android:layout_height="33.3dp"
android:layout_marginHorizontal="10dp"
android:background="@color/color_9970ff" />
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/tv_title_live_contributor_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="라이브\n참여자"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_live_contributor_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title_live_contributor_count"
android:layout_centerHorizontal="true"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="10" />
</RelativeLayout>
<FrameLayout
android:layout_width="1dp"
android:layout_height="33.3dp"
android:layout_marginHorizontal="10dp"
android:background="@color/color_9970ff" />
<RelativeLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/tv_title_content_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="등록\n콘텐츠"
android:textColor="@color/color_909090"
android:textSize="12sp"
tools:ignore="SmallSp" />
<TextView
android:id="@+id/tv_content_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_title_content_count"
android:layout_centerHorizontal="true"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="10" />
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_notice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@color/color_fdca2f">
<TextView
android:id="@+id/tv_notice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginEnd="6.7dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="1"
android:paddingHorizontal="26.7dp"
android:paddingVertical="13.3dp"
android:textColor="@color/black"
android:textSize="13.3sp"
tools:text="[공지사항]6.15 휴방공지에요!" />
<ImageView
android:id="@+id/iv_write"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_review"
android:visibility="gone" />
</RelativeLayout>
<include
android:id="@+id/layout_user_profile_live"
layout="@layout/layout_user_profile_live"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="46.7dp"
android:visibility="gone" />
<include
android:id="@+id/layout_user_profile_introduce"
layout="@layout/layout_user_profile_introduce"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="26.7dp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginVertical="26.7dp"
android:background="@color/color_88909090" />
<LinearLayout
android:id="@+id/ll_user_profile_donation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/layout_user_profile_donation"
layout="@layout/layout_user_profile_donation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" />
<View
android:layout_width="match_parent"
android:layout_height="6.7dp"
android:layout_marginVertical="26.7dp"
android:background="@color/color_232323" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_user_profile_similar_creator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include
android:id="@+id/layout_user_profile_similar_creator"
layout="@layout/layout_user_profile_similar_creator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" />
<View
android:layout_width="match_parent"
android:layout_height="6.7dp"
android:layout_marginVertical="26.7dp"
android:background="@color/color_232323" />
</LinearLayout>
<include
android:id="@+id/layout_user_profile_fan_talk"
layout="@layout/layout_user_profile_fan_talk"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</RelativeLayout>

View File

@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:id="@+id/ll_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<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/gmarket_sans_medium"
android:text="응원"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<TextView
android:id="@+id/tv_cheers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
tools:text="3" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:background="@color/color_88909090" />
<RelativeLayout
android:id="@+id/rl_input_cheer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginVertical="20dp">
<EditText
android:id="@+id/et_cheer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_round_corner_10_232323_9970ff"
android:hint="응원댓글을 남겨보세요!"
android:importantForAutofill="no"
android:inputType="text"
android:paddingVertical="17dp"
android:paddingStart="13.3dp"
android:paddingEnd="50.7dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_eeeeee"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<ImageView
android:id="@+id/iv_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="6dp"
android:contentDescription="@null"
android:src="@drawable/btn_message_send" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:background="@color/color_88909090" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="6.7dp"
android:clipToPadding="false"
android:scrollbars="none" />
<TextView
android:id="@+id/tv_no_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="60dp"
android:fontFamily="@font/gmarket_sans_light"
android:gravity="center"
android:visibility="gone"
android:text="응원이 없습니다.\n\n처음으로 응원을 해보세요!"
android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:id="@+id/ll_total"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="13.3dp"
android:background="@drawable/bg_round_corner_8_2b2635"
android:orientation="vertical"
android:paddingHorizontal="16.7dp"
android:paddingVertical="13.3dp"
android:visibility="gone">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="오늘"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_coin_today"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/tv_unit_today"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="12sp"
tools:ignore="RelativeOverlap" />
<TextView
android:id="@+id/tv_unit_today"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@font/gmarket_sans_light"
android:text=" 캔"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="지난주"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_coin_last_week"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/tv_unit_last_week"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="12sp"
tools:ignore="RelativeOverlap" />
<TextView
android:id="@+id/tv_unit_last_week"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@font/gmarket_sans_light"
android:text=" 캔"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="이번 달 어제까지"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_coin_this_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toStartOf="@+id/tv_unit_this_month"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="12sp"
tools:ignore="RelativeOverlap" />
<TextView
android:id="@+id/tv_unit_this_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@font/gmarket_sans_light"
android:text=" 캔"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingHorizontal="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="전체"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<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/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textSize="12sp"
tools:text="56" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="개"
android:textColor="@color/color_777777"
android:textSize="12sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="6.7dp"
android:background="@color/color_88909090" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_live_all"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingVertical="20dp" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</LinearLayout>

View File

@ -0,0 +1,127 @@
<?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="@color/color_1b1b1b"
android:orientation="vertical"
android:padding="16.7dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:text="후기 신고"
android:textColor="@color/color_eeeeee"
android:textSize="16sp" />
<RadioGroup
android:id="@+id/radio_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="16.7dp"
android:orientation="vertical">
<RadioButton
android:id="@+id/radio_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="원치 않는 상업성 콘텐츠 또는 스팸"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="아동 학대"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="증오심 표현 또는 노골적인 폭력"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="테러 조장"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="희롱 또는 괴롭힘"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="자살 또는 자해"
android:textColor="@color/color_909090"
android:textSize="14sp" />
<RadioButton
android:id="@+id/radio_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:buttonTint="@color/color_909090"
android:fontFamily="@font/gmarket_sans_medium"
android:text="잘못된 정보"
android:textColor="@color/color_909090"
android:textSize="14sp" />
</RadioGroup>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16.7dp"
android:layout_toStartOf="@+id/tv_report"
android:fontFamily="@font/gmarket_sans_medium"
android:padding="6.7dp"
android:text="취소"
android:textColor="@color/color_eeeeee"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_report"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:padding="6.7dp"
android:text="신고"
android:textColor="@color/color_9970ff"
android:textSize="14sp" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerVertical="true"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="13.3dp"
android:layout_toStartOf="@+id/iv_notification"
android:layout_toEndOf="@+id/iv_profile"
android:fontFamily="@font/gmarket_sans_medium"
android:textSize="16.7sp"
tools:text="상남자" />
<ImageView
android:id="@+id/iv_notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:visibility="gone" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_below="@+id/iv_profile"
android:layout_marginTop="26.7dp"
android:background="@color/color_88909090" />
</RelativeLayout>

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="33.3dp"
android:layout_height="33.3dp"
android:layout_marginTop="10dp"
android:adjustViewBounds="true"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_launcher_background" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toTopOf="parent"
tools:text="dksoew10" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:layout_marginTop="8.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_525252"
android:textSize="10.7sp"
app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/tv_nickname"
tools:ignore="SmallSp"
tools:text="2021.07.01 10:30" />
<ImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_seemore_vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/iv_profile" />
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/tv_date"
tools:text="내용 읽어보니까 결혼해도 될것 같은데요. 원래 서로 맞춰가며 사는거죠! 응원합니다." />
<FrameLayout
android:id="@+id/fl_reply"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/tv_content">
<LinearLayout
android:id="@+id/ll_cheer_reply"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/tv_reply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_16_7_4c9970ff"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="13.3dp"
android:textColor="@color/white"
tools:text="항상 응원해주셔서 감사합니다." />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8.3dp">
<TextView
android:id="@+id/tv_reply_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_525252"
android:textSize="10.7sp"
tools:ignore="SmallSp"
tools:text="2021.07.01 10:30" />
<TextView
android:id="@+id/tv_modify_reply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:text="답글 수정"
android:textColor="@color/color_9970ff"
android:textSize="10.7sp"
android:visibility="gone"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
<RelativeLayout
android:id="@+id/rl_cheer_reply"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:visibility="gone">
<EditText
android:id="@+id/et_cheer_reply"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginEnd="10dp"
android:layout_toStartOf="@+id/tv_send"
android:background="@drawable/bg_round_corner_10_232323"
android:hint="응원댓글에 답글을 남겨보세요!"
android:importantForAutofill="no"
android:inputType="text"
android:paddingHorizontal="13.3dp"
android:paddingVertical="13dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_eeeeee"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:background="@drawable/bg_round_corner_6_7_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:padding="13dp"
android:text="등록"
android:textColor="@color/white" />
</RelativeLayout>
<TextView
android:id="@+id/tv_write_reply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="답글 쓰기"
android:textColor="@color/color_9970ff"
android:textSize="10.7sp"
tools:ignore="SmallSp" />
</FrameLayout>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginTop="13dp"
android:background="@color/color_88909090"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fl_reply" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="65dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="65dp"
android:layout_height="65dp">
<ImageView
android:id="@+id/iv_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null" />
<ImageView
android:id="@+id/iv_profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/iv_crown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:contentDescription="@null" />
</RelativeLayout>
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6.7dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:lines="1"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
</LinearLayout>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_donation_ranking_root"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_donation_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="UselessParent">
<RelativeLayout
android:id="@+id/rl_profile"
android:layout_width="65dp"
android:layout_height="65dp"
android:layout_centerVertical="true">
<ImageView
android:id="@+id/iv_bg"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null" />
<ImageView
android:id="@+id/iv_profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/iv_crown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:contentDescription="@null" />
</RelativeLayout>
<TextView
android:id="@+id/tv_rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="20dp"
android:layout_marginEnd="13.3dp"
android:layout_toEndOf="@+id/rl_profile"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_bold"
android:maxLength="10"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="1" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/tv_rank"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:lines="1"
android:maxLength="12"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
tools:text="Remix" />
<TextView
android:id="@+id/tv_total_donation_coin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/tv_nickname"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="end"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/rl_cover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="80dp"
android:layout_height="116.7dp"
android:contentDescription="@null" />
<ImageView
android:id="@+id/iv_19"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3.3dp"
android:layout_marginTop="3.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_19"
android:visibility="gone" />
<View
android:id="@+id/bg_cover"
android:layout_width="80dp"
android:layout_height="116.7dp"
android:background="@drawable/bg_round_corner_4_7_88909090" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_room_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:orientation="vertical"
app:layout_constraintStart_toEndOf="@+id/rl_cover"
app:layout_constraintTop_toTopOf="@+id/rl_cover">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_ffd300"
android:textSize="9.3sp"
tools:ignore="SmallSp"
tools:text="2021.06.20 SUN 10:00 PM" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
tools:text="사냥꾼 1004" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4.3dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_e2e2e2"
android:textSize="15.3sp"
tools:text="여자들이 좋아하는 남자 스타일은?" />
</LinearLayout>
<TextView
android:id="@+id/tv_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="9dp"
android:paddingVertical="4dp"
android:textSize="11.3sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/rl_cover" />
<TextView
android:id="@+id/tv_participate"
android:layout_width="0dp"
android:layout_height="36.7dp"
android:layout_marginStart="20dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:textSize="13.3sp"
app:layout_constraintBottom_toBottomOf="@+id/rl_cover"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/rl_cover" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginVertical="13.3dp"
android:background="@color/color_88909090"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/rl_cover" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,38 @@
<?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:gravity="center">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="@null" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="20dp"
android:background="@drawable/bg_round_corner_16_7_222222"
android:orientation="vertical"
android:paddingHorizontal="20dp"
android:paddingTop="20dp"
android:paddingBottom="13.3dp">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="90dp"
android:layout_height="90dp"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/ic_launcher_background" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/iv_profile"
app:layout_constraintTop_toTopOf="@+id/iv_profile">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/iv_share"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_bold"
android:maxLines="1"
android:textColor="@color/color_eeeeee"
android:textSize="18sp"
tools:text="김상담김상담김상담김상담김상담김상담" />
<ImageView
android:id="@+id/iv_share"
android:layout_width="33.3dp"
android:layout_height="33.3dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginStart="6.7dp"
android:contentDescription="@null"
android:src="@drawable/btn_big_share" />
</RelativeLayout>
<TextView
android:id="@+id/tv_follower_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6.7dp"
android:background="@drawable/bg_round_corner_16_7_transparent_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp"
android:text="팔로워 리스트"
android:textColor="@color/white"
android:textSize="12sp"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_notification"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6.7dp"
android:orientation="vertical"
android:visibility="visible"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
tools:src="@drawable/btn_notification_selected" />
<TextView
android:id="@+id/tv_notification_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="@font/gmarket_sans_light"
android:textColor="@color/color_bbbbbb"
android:textSize="10sp"
tools:ignore="SmallSp"
tools:text="팔로워 1,000명" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tv_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="@+id/iv_profile"
app:layout_constraintTop_toBottomOf="@+id/iv_profile"
tools:text="#연애 #연애상담 #소개팅" />
<LinearLayout
android:id="@+id/ll_sns"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_tags">
<ImageView
android:id="@+id/iv_website"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:src="@drawable/ic_website_circle" />
<ImageView
android:id="@+id/iv_blog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_blog_circle" />
<ImageView
android:id="@+id/iv_instagram"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_instagram_circle" />
<ImageView
android:id="@+id/iv_youtube"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
android:src="@drawable/ic_youtube_circle" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="후원랭킹"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_light"
android:gravity="center"
android:text="전체보기"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
app:layout_constraintBottom_toBottomOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_donation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
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:layout_marginHorizontal="13.3dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="팬 Talk"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<TextView
android:id="@+id/tv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:fontFamily="@font/gmarket_sans_light"
android:gravity="center"
android:text="전체보기"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp" />
</RelativeLayout>
<LinearLayout
android:id="@+id/ll_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<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/gmarket_sans_medium"
android:text="응원"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<TextView
android:id="@+id/tv_cheers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="12sp"
tools:text="3" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:background="@color/color_88909090" />
<RelativeLayout
android:id="@+id/rl_input_cheer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginVertical="20dp">
<EditText
android:id="@+id/et_cheer"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_round_corner_10_232323_9970ff"
android:hint="응원댓글을 남겨보세요!"
android:importantForAutofill="no"
android:inputType="text"
android:paddingVertical="17dp"
android:paddingStart="13.3dp"
android:paddingEnd="50.7dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_eeeeee"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="13.3sp"
tools:ignore="LabelFor" />
<ImageView
android:id="@+id/iv_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="6dp"
android:contentDescription="@null"
android:src="@drawable/btn_message_send" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp"
android:background="@color/color_88909090" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="6.7dp"
android:clipToPadding="false"
android:scrollbars="none" />
<TextView
android:id="@+id/tv_no_cheers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="60dp"
android:fontFamily="@font/gmarket_sans_light"
android:gravity="center"
android:visibility="gone"
android:text="응원이 없습니다.\n\n처음으로 응원을 해보세요!"
android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,24 @@
<?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:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="채널 소개"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<TextView
android:id="@+id/tv_introduce"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="13.3sp" />
</LinearLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="라이브"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_live"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingVertical="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="함께 들으면 좋은 채널"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_light"
android:gravity="center"
android:text="전체보기"
android:textColor="@color/color_bbbbbb"
android:textSize="11.3sp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_similar_creator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"
android:clipToPadding="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -67,4 +67,5 @@
<color name="color_e6a77a">#E6A77A</color>
<color name="color_ffb600">#FFB600</color>
<color name="color_99000000">#99000000</color>
<color name="color_4c9970ff">#4C9970FF</color>
</resources>