Compare commits

..

70 Commits

Author SHA1 Message Date
klaus b68b4eb8da version 9 (1.0.8) 2023-10-31 22:13:02 +09:00
klaus d8cc218139 구매 목록 - 구매한 콘텐츠 총 개수 표시 2023-10-31 18:35:07 +09:00
klaus 0226a696d4 라이브 - 방장을 제외한 모든 유저에게 참여자 목록 버튼이 보이지 않도록 수정 2023-10-31 13:56:50 +09:00
klaus c9eb0f0e01 구매 목록 - 페이징을 추가해 이전 구매목록이 추가로 로딩되도록 수정 2023-10-31 12:23:43 +09:00
klaus 5c293e79cf 구매 목록 - 페이징을 추가해 이전 구매목록이 추가로 로딩되도록 수정 2023-10-31 12:23:12 +09:00
klaus 5cdb7426c6 구매 목록 - 페이징을 추가해 이전 구매목록이 추가로 로딩되도록 수정 2023-10-30 22:33:36 +09:00
klaus cc73f471d2 카울리 - 무료 충전 버튼 크기 수정, 캔 내역에 무료 충전 버튼 추가 2023-10-27 22:22:58 +09:00
klaus dc3240f224 카울리 무료 충전 버튼 보이게 수정 2023-10-27 02:06:21 +09:00
klaus 04eda1ffbd 결제수단 - 휴대폰 결제 추가 2023-10-27 02:02:24 +09:00
klaus 39d790c1c3 사용하지 않는 isAdult 제거 2023-10-24 23:22:21 +09:00
klaus 3e3d0de7ca 카울리 PointClick SDK verion 1.0.17로 변경 2023-10-23 16:58:25 +09:00
klaus 165b75487b 콘텐츠 등록 - 유료 콘텐츠의 경우에만 미리듣기 시간설정을 할 수 있도록 수정 2023-10-22 17:59:50 +09:00
klaus 19b351ef2a 콘텐츠 등록 - 대여만 가능한 콘텐츠 등록 기능 추가 2023-10-21 00:56:15 +09:00
klaus 83575aa1eb 콘텐츠 상세 - 대여만 가능한 콘텐츠의 경우 소장 버튼이 보이지 않고 가격의 100%가 보이도록 수정 2023-10-20 23:13:16 +09:00
klaus 26c9a236ec 결제수단 - 휴대폰 결제 숨김 2023-10-20 17:20:03 +09:00
klaus da7f72544f 결제수단 - 휴대폰 결제 추가 2023-10-20 16:24:49 +09:00
klaus 444f031f57 콘텐츠 메인 인기 콘텐츠 - 아이템 width 고정 2023-10-15 07:17:09 +09:00
klaus 3e7d06a2aa 탐색 - 인기 크리에이터 설명 글 UI 수정 2023-10-15 06:53:39 +09:00
klaus e6b8e55966 인기 콘텐츠 전체 보기 페이지 추가 2023-10-15 04:38:07 +09:00
klaus fe1a1cc3cb 콘텐츠 메인 - 인기 콘텐츠 영역 추가 2023-10-15 03:09:47 +09:00
klaus 2f17e04e1e 탐색 - 크리에이터 랭킹 UI 추가 2023-10-14 18:48:02 +09:00
klaus 41d175a19f admob 제거 2023-10-14 17:08:47 +09:00
klaus 8266167c02 탐색 - 섹션 제목 아래에 description 추가 2023-10-14 01:38:00 +09:00
klaus 2cfc4b97f4 채금 다이얼로그 - 취소 버튼 동작 추가 2023-10-11 16:55:19 +09:00
klaus fbad5f9d98 채금 기능 추가 2023-10-11 02:49:52 +09:00
klaus ac6b0c52d0 라이브 방 - 팔로잉 버튼 위치 수정 2023-10-06 20:05:26 +09:00
klaus 413c526a6a 라이브 지금 예약 중 아이템 - 이미지 RoundedCorners 추가 2023-10-06 19:19:14 +09:00
klaus 622021913d 메시지 발송 버튼 색상 변경 2023-10-06 17:45:47 +09:00
klaus 5ed5a86e0d 라이브 예약중 전체보기 - 캘린더 선택된 날짜 배경색 변경 2023-10-06 17:34:47 +09:00
klaus 3bf4f273d2 라이브 지금 예약중 - 라이브 커버 이미지 사이즈가 작게 보이던 버그 수정 2023-10-06 17:31:31 +09:00
klaus 0e6c78a6c0 유료 콘텐츠 미리 듣기 재생 버튼 추가 2023-10-05 23:24:10 +09:00
klaus 71cd52d30a 후원랭킹 전체보기 후원랭킹 활성화 스위치 - 클릭 리스너 추가 2023-10-05 22:31:15 +09:00
klaus d35b920470 후원랭킹 전체보기 - 후원랭킹 활성화 스위치 추가 2023-10-05 19:13:12 +09:00
klaus 5a4355044f 지금 라이브 중 전체 보기 아이템 - 배경 색상 제거 2023-09-27 16:27:42 +09:00
klaus b74d4b18e7 콘텐츠 큐레이션 전체보기 - UI 형태 그리드로 변경 2023-09-27 15:58:30 +09:00
klaus a53b76415b 콘텐츠 큐레이션 전체보기 - UI 형태 그리드로 변경 2023-09-27 15:49:00 +09:00
klaus a286ee760d 콘텐츠 업로드 - 미리듣기 시간 설정 안내 문구 글자 간격 수정 2023-09-27 15:48:02 +09:00
klaus 92b72db25c 콘텐츠 업로드 - 미리듣기 시간 설정 안내 문구 추가 2023-09-27 15:42:59 +09:00
klaus eed7bfa158 예약 라이브 전체 보기 - 라이브 만들기 페이지로 이동하는 기능 제거 2023-09-27 14:59:38 +09:00
klaus 549644a224 콘텐츠 큐레이션 - 너비가 가득 차도록 수정 2023-09-27 14:51:04 +09:00
klaus ecec8be386 새로운 콘텐츠 전체보기 페이지 추가 2023-09-27 14:19:54 +09:00
klaus 46b423e3e6 큐레이션 콘텐츠 전체보기 페이지 추가 2023-09-26 22:04:41 +09:00
klaus 1206977907 콘텐츠 사이 배너광고 제거 2023-09-26 16:07:03 +09:00
klaus b38fd26b77 무료 충전 아이콘 숨김 2023-09-22 22:32:30 +09:00
klaus 302e7d9a45 콘텐츠 업로드 - 미리 듣기 시간 설정 기능 추가 2023-09-22 18:08:31 +09:00
klaus b7a986c33c checkReleaseBuilds 추가 2023-09-21 22:44:21 +09:00
klaus 6fc474cff4 탐색 탭 - 배너 광고 unit id 변경 2023-09-20 18:52:28 +09:00
klaus 4bcc1b2680 point click sdk 추가 2023-09-19 22:42:11 +09:00
klaus 318bae54a1 versionCode 5, versionName 1.0.4 2023-09-19 15:38:36 +09:00
klaus 959d20fe6f 콘텐츠 상세 - 배너 광고 간격 수정 2023-09-16 01:40:36 +09:00
klaus 00277117f1 콘텐츠 상세 - 배너 광고 위치 수정 2023-09-16 01:31:08 +09:00
klaus 42613dfc76 탐색 - 광고 배너 추가 2023-09-16 01:12:31 +09:00
klaus 90df714a44 라이브 메인 - 광고 위치 추천 채널 밑으로 이동 2023-09-15 23:21:36 +09:00
klaus 62fc0e1d59 콘텐츠 메인 - 광고 위치 수정 2023-09-15 23:17:28 +09:00
klaus e3679fd1dc 라이브 방 - 배너 광고 제거 2023-09-15 23:06:35 +09:00
klaus 9626823f0c 라이브 방 - 배너 광고 추가 2023-09-15 21:35:25 +09:00
klaus 9fc795afac binding 버그 수정 2023-09-15 16:33:38 +09:00
klaus 6610f13619 라이브 상세 - 배너 광고 추가 2023-09-15 02:29:53 +09:00
klaus f9401d91c4 메시지 - 배너 광고 추가 2023-09-15 02:22:15 +09:00
klaus 52e6965472 크리에이터 채널 - 배너 광고 추가 2023-09-15 02:06:27 +09:00
klaus 0343c91f1c 라이브 메인, 팔로잉 채널 전체보기, 지금 라이브 중 전체보기 - 배너 광고 추가 2023-09-15 01:54:02 +09:00
klaus cce1b4f446 콘텐츠 메인 - 배너 광고 간격 수정 2023-09-15 01:35:00 +09:00
klaus db1981b5fe 콘텐츠 구매목록 - 배너 광고 추가 2023-09-15 01:32:21 +09:00
klaus cae15b7f39 콘텐츠 메인 - 배너 광고 추가 2023-09-15 01:22:51 +09:00
klaus 26e43bd548 콘텐츠 상세 - 배너 광고 추가 2023-09-14 03:14:48 +09:00
klaus f6cbaffd3b 휴대폰 결제 임시로 숨김 2023-09-13 14:43:05 +09:00
klaus 4d4ddb50ac 메시지 추가 로딩 되지 않는 버그 수정 2023-09-13 14:31:06 +09:00
klaus 9ed175191b 재생수 업데이트 로직 - 10초 이상 연속재생 한 경우 업데이트 하도록 수정 2023-09-13 12:25:41 +09:00
klaus 4d5c3acff5 휴대폰 결제 추가 2023-09-12 01:31:02 +09:00
klaus d791147886 @SerializedName 추가 2023-09-09 01:55:14 +09:00
113 changed files with 3385 additions and 339 deletions

View File

@ -26,6 +26,7 @@ android {
lintOptions { lintOptions {
checkDependencies true checkDependencies true
checkReleaseBuilds false
} }
dependenciesInfo { dependenciesInfo {
@ -39,8 +40,8 @@ android {
applicationId "kr.co.vividnext.sodalive" applicationId "kr.co.vividnext.sodalive"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 3 versionCode 9
versionName "1.0.2" versionName "1.0.8"
} }
buildTypes { buildTypes {
@ -148,4 +149,7 @@ dependencies {
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
implementation "com.michalsvec:single-row-calednar:1.0.0" implementation "com.michalsvec:single-row-calednar:1.0.0"
// PointClick Maven Remote Repo
implementation 'kr.co.pointclick.sdk.offerwall:pointclick-sdk-offerwall:1.0.17'
} }

View File

@ -221,3 +221,10 @@
-keep class androidx.viewpager2.widget.**{*;} -keep class androidx.viewpager2.widget.**{*;}
-keep class kr.co.bootpay.core.** { *; } -keep class kr.co.bootpay.core.** { *; }
-keep class kr.co.pointclick.sdk.offerwall.core.consts.** {*;}
-keep interface kr.co.pointclick.sdk.offerwall.core.consts.** {*;}
-keep class kr.co.pointclick.sdk.offerwall.core.models.** {*;}
-keep interface kr.co.pointclick.sdk.offerwall.core.models.** {*;}
-keep class kr.co.pointclick.sdk.offerwall.core.PointClickAd {*;}
-keep class kr.co.pointclick.sdk.offerwall.core.events.PackageReceiver {*;}

View File

@ -28,6 +28,21 @@
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="com.google.android.gms.permission.AD_ID" /> <uses-permission android:name="com.google.android.gms.permission.AD_ID" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>
</queries>
<application <application
android:name=".app.SodaLiveApp" android:name=".app.SodaLiveApp"
android:allowBackup="true" android:allowBackup="true"
@ -106,6 +121,9 @@
<activity android:name=".mypage.profile.ProfileUpdateActivity" /> <activity android:name=".mypage.profile.ProfileUpdateActivity" />
<activity android:name=".mypage.profile.nickname.NicknameUpdateActivity" /> <activity android:name=".mypage.profile.nickname.NicknameUpdateActivity" />
<activity android:name=".mypage.profile.password.ModifyPasswordActivity" /> <activity android:name=".mypage.profile.password.ModifyPasswordActivity" />
<activity android:name=".audio_content.curation.AudioContentCurationActivity" />
<activity android:name=".audio_content.all.AudioContentNewAllActivity" />
<activity android:name=".audio_content.all.AudioContentRankingAllActivity" />
<activity <activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity" android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"

View File

@ -1,15 +1,18 @@
package kr.co.vividnext.sodalive.audio_content package kr.co.vividnext.sodalive.audio_content
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import kr.co.vividnext.sodalive.audio_content.all.GetNewContentAllResponse
import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListResponse import kr.co.vividnext.sodalive.audio_content.comment.GetAudioContentCommentListResponse
import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest import kr.co.vividnext.sodalive.audio_content.comment.ModifyCommentRequest
import kr.co.vividnext.sodalive.audio_content.comment.RegisterAudioContentCommentRequest import kr.co.vividnext.sodalive.audio_content.comment.RegisterAudioContentCommentRequest
import kr.co.vividnext.sodalive.audio_content.curation.GetCurationContentResponse
import kr.co.vividnext.sodalive.audio_content.detail.GetAudioContentDetailResponse import kr.co.vividnext.sodalive.audio_content.detail.GetAudioContentDetailResponse
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeRequest
import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeResponse import kr.co.vividnext.sodalive.audio_content.detail.PutAudioContentLikeResponse
import kr.co.vividnext.sodalive.audio_content.donation.AudioContentDonationRequest import kr.co.vividnext.sodalive.audio_content.donation.AudioContentDonationRequest
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainResponse import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainResponse
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRanking
import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse import kr.co.vividnext.sodalive.audio_content.order.GetAudioContentOrderListResponse
import kr.co.vividnext.sodalive.audio_content.order.OrderRequest import kr.co.vividnext.sodalive.audio_content.order.OrderRequest
import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse import kr.co.vividnext.sodalive.audio_content.upload.theme.GetAudioContentThemeResponse
@ -133,6 +136,14 @@ interface AudioContentApi {
@Header("Authorization") authHeader: String @Header("Authorization") authHeader: String
): Single<ApiResponse<List<GetAudioContentMainItem>>> ): Single<ApiResponse<List<GetAudioContentMainItem>>>
@GET("/audio-content/main/new/all")
fun getNewContentAllOfTheme(
@Query("theme") theme: String,
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetNewContentAllResponse>>
@POST("/audio-content/donation") @POST("/audio-content/donation")
fun donation( fun donation(
@Body request: AudioContentDonationRequest, @Body request: AudioContentDonationRequest,
@ -144,4 +155,25 @@ interface AudioContentApi {
@Body request: ModifyCommentRequest, @Body request: ModifyCommentRequest,
@Header("Authorization") authHeader: String @Header("Authorization") authHeader: String
): Single<ApiResponse<Any>> ): Single<ApiResponse<Any>>
@GET("/audio-content/curation/{id}")
fun getAudioContentListByCurationId(
@Path("id") id: Long,
@Query("page") page: Int,
@Query("size") size: Int,
@Query("sort-type") sort: AudioContentViewModel.Sort,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetCurationContentResponse>>
@GET("/audio-content/main/theme")
fun getNewContentThemeList(
@Header("Authorization") authHeader: String
): Single<ApiResponse<List<String>>>
@GET("/audio-content/ranking")
fun getContentRanking(
@Query("page") page: Int,
@Query("size") size: Int,
@Header("Authorization") authHeader: String
): Single<ApiResponse<GetAudioContentRanking>>
} }

View File

@ -14,6 +14,20 @@ class AudioContentRepository(
private val api: AudioContentApi, private val api: AudioContentApi,
private val userApi: UserApi private val userApi: UserApi
) { ) {
fun getAudioContentListByCurationId(
curationId: Long,
page: Int,
size: Int,
sort: AudioContentViewModel.Sort = AudioContentViewModel.Sort.NEWEST,
token: String
) = api.getAudioContentListByCurationId(
id = curationId,
page = page - 1,
size = size,
sort = sort,
authHeader = token
)
fun getAudioContentList( fun getAudioContentList(
id: Long, id: Long,
page: Int, page: Int,
@ -122,6 +136,20 @@ class AudioContentRepository(
authHeader = token authHeader = token
) )
fun getNewContentAllOfTheme(
theme: String,
page: Int,
size: Int,
token: String
) = api.getNewContentAllOfTheme(
theme = theme,
page = page - 1,
size = size,
authHeader = token
)
fun getNewContentThemeList(token: String) = api.getNewContentThemeList(authHeader = token)
fun donation( fun donation(
contentId: Long, contentId: Long,
can: Int, can: Int,
@ -135,4 +163,14 @@ class AudioContentRepository(
), ),
authHeader = token authHeader = token
) )
fun getContentRanking(
page: Int,
size: Int,
token: String
) = api.getContentRanking(
page = page - 1,
size = size,
authHeader = token
)
} }

View File

@ -0,0 +1,194 @@
package kr.co.vividnext.sodalive.audio_content.all
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainNewContentThemeAdapter
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.ActivityAudioContentNewAllBinding
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
class AudioContentNewAllActivity : BaseActivity<ActivityAudioContentNewAllBinding>(
ActivityAudioContentNewAllBinding::inflate
) {
private val viewModel: AudioContentNewAllViewModel by inject()
private lateinit var loadingDialog: LoadingDialog
private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter
private lateinit var newContentAdapter: AudioContentNewAllAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
viewModel.getThemeList()
viewModel.getNewContentList()
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = "새로운 콘텐츠"
binding.toolbar.tvBack.setOnClickListener { finish() }
setupNewContentTheme()
setupNewContent()
}
private fun setupNewContentTheme() {
newContentThemeAdapter = AudioContentMainNewContentThemeAdapter {
newContentAdapter.clear()
viewModel.selectTheme(it)
}
binding.rvNewContentTheme.layoutManager = LinearLayoutManager(
this,
LinearLayoutManager.HORIZONTAL,
false
)
binding.rvNewContentTheme.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 = 4f.dpToPx().toInt()
}
newContentThemeAdapter.itemCount - 1 -> {
outRect.left = 4f.dpToPx().toInt()
outRect.right = 0
}
else -> {
outRect.left = 4f.dpToPx().toInt()
outRect.right = 4f.dpToPx().toInt()
}
}
}
})
binding.rvNewContentTheme.adapter = newContentThemeAdapter
}
private fun setupNewContent() {
newContentAdapter = AudioContentNewAllAdapter(
itemWidth = (screenWidth - 40f.dpToPx().toInt()) / 2,
onClickItem = {
startActivity(
Intent(this, AudioContentDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
}
)
},
onClickCreator = {
startActivity(
Intent(this, UserProfileActivity::class.java).apply {
putExtra(Constants.EXTRA_USER_ID, it)
}
)
}
)
binding.rvContent.layoutManager = GridLayoutManager(this, 2)
binding.rvContent.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val position = parent.getChildAdapterPosition(view)
if (position % 2 == 0) {
outRect.left = 13.3f.dpToPx().toInt()
outRect.right = 6.7f.dpToPx().toInt()
} else {
outRect.left = 6.7f.dpToPx().toInt()
outRect.right = 13.3f.dpToPx().toInt()
}
when (position) {
0, 1 -> {
outRect.top = 13.3f.dpToPx().toInt()
outRect.bottom = 6.7f.dpToPx().toInt()
}
newContentAdapter.itemCount - 1, newContentAdapter.itemCount - 2 -> {
outRect.top = 6.7f.dpToPx().toInt()
outRect.bottom = 13.3f.dpToPx().toInt()
}
else -> {
outRect.top = 6.7f.dpToPx().toInt()
outRect.bottom = 6.7f.dpToPx().toInt()
}
}
}
})
binding.rvContent.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
// 스크롤이 끝에 도달했는지 확인
if (!recyclerView.canScrollVertically(1) &&
lastVisibleItemPosition == itemTotalCount
) {
viewModel.getNewContentList()
}
}
})
binding.rvContent.adapter = newContentAdapter
}
private fun bindData() {
viewModel.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.themeListLiveData.observe(this) {
newContentThemeAdapter.addItems(it)
}
viewModel.newContentListLiveData.observe(this) {
newContentAdapter.addItems(it)
}
viewModel.newContentTotalCountLiveData.observe(this) {
binding.tvTotalCount.text = "$it"
}
}
}

View File

@ -0,0 +1,85 @@
package kr.co.vividnext.sodalive.audio_content.all
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.CircleCropTransformation
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
import kr.co.vividnext.sodalive.databinding.ItemAudioContentNewAllBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class AudioContentNewAllAdapter(
private val itemWidth: Int,
private val onClickItem: (Long) -> Unit,
private val onClickCreator: (Long) -> Unit,
) : RecyclerView.Adapter<AudioContentNewAllAdapter.ViewHolder>() {
inner class ViewHolder(
private val binding: ItemAudioContentNewAllBinding,
private val onClickItem: (Long) -> Unit,
private val onClickCreator: (Long) -> Unit
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetAudioContentMainItem) {
binding.ivAudioContentCoverImage.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(RoundedCornersTransformation(2.7f.dpToPx()))
val layoutParams = binding.ivAudioContentCoverImage
.layoutParams as ConstraintLayout.LayoutParams
layoutParams.width = itemWidth
layoutParams.height = itemWidth
binding.ivAudioContentCoverImage.layoutParams = layoutParams
}
binding.ivAudioContentCreator.load(item.creatorProfileImageUrl) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(CircleCropTransformation())
}
binding.tvAudioContentTitle.text = item.title
binding.tvAudioContentCreatorNickname.text = item.creatorNickname
binding.ivAudioContentCreator.setOnClickListener { onClickCreator(item.creatorId) }
binding.root.setOnClickListener { onClickItem(item.contentId) }
}
}
private val items = mutableListOf<GetAudioContentMainItem>()
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = ViewHolder(
ItemAudioContentNewAllBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
),
onClickItem = onClickItem,
onClickCreator = onClickCreator
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: AudioContentNewAllAdapter.ViewHolder, position: Int) {
holder.bind(items[position])
}
@SuppressLint("NotifyDataSetChanged")
fun addItems(items: List<GetAudioContentMainItem>) {
this.items.addAll(items)
notifyDataSetChanged()
}
fun clear() {
this.items.clear()
}
}

View File

@ -0,0 +1,127 @@
package kr.co.vividnext.sodalive.audio_content.all
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
class AudioContentNewAllViewModel(
private val repository: AudioContentRepository
) : 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 _themeListLiveData = MutableLiveData<List<String>>()
val themeListLiveData: LiveData<List<String>>
get() = _themeListLiveData
private var _newContentListLiveData = MutableLiveData<List<GetAudioContentMainItem>>()
val newContentListLiveData: LiveData<List<GetAudioContentMainItem>>
get() = _newContentListLiveData
private var _newContentTotalCountLiveData = MutableLiveData<Int>()
val newContentTotalCountLiveData: LiveData<Int>
get() = _newContentTotalCountLiveData
private var isLast = false
private var page = 1
private val size = 10
private var selectedTheme = ""
fun getNewContentList() {
if (!_isLoading.value!! && !isLast) {
_isLoading.value = true
compositeDisposable.add(
repository.getNewContentAllOfTheme(
theme = if (selectedTheme == "전체") {
""
} else {
selectedTheme
},
page = page,
size = size,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
if (it.data.items.isNotEmpty()) {
page += 1
_newContentListLiveData.postValue(it.data.items)
_newContentTotalCountLiveData.postValue(it.data.totalCount)
} else {
isLast = true
}
} 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 getThemeList() {
compositeDisposable.add(
repository.getNewContentThemeList(token = "Bearer ${SharedPreferenceManager.token}")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
val themeList = listOf("전체").union(it.data).toList()
_themeListLiveData.postValue(themeList)
} 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 selectTheme(theme: String) {
isLast = false
page = 1
selectedTheme = theme
getNewContentList()
}
}

View File

@ -0,0 +1,131 @@
package kr.co.vividnext.sodalive.audio_content.all
import android.annotation.SuppressLint
import android.content.Intent
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.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentRankingAllBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
class AudioContentRankingAllActivity : BaseActivity<ActivityAudioContentRankingAllBinding>(
ActivityAudioContentRankingAllBinding::inflate
) {
private val viewModel: AudioContentRankingAllViewModel by inject()
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: AudioContentRankingAllAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindData()
viewModel.getAudioContentRanking()
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.setOnClickListener { finish() }
binding.toolbar.tvBack.text = "인기 콘텐츠"
adapter = AudioContentRankingAllAdapter {
val intent = Intent(applicationContext, AudioContentDetailActivity::class.java)
.apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
}
startActivity(intent)
}
binding.rvContentRanking.layoutManager = LinearLayoutManager(
applicationContext,
LinearLayoutManager.VERTICAL,
false
)
binding.rvContentRanking.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.left = 13.3f.dpToPx().toInt()
outRect.right = 13.3f.dpToPx().toInt()
when (parent.getChildAdapterPosition(view)) {
0 -> {
outRect.top = 0
outRect.bottom = 10f.dpToPx().toInt()
}
adapter.itemCount - 1 -> {
outRect.top = 10f.dpToPx().toInt()
outRect.bottom = 0
}
else -> {
outRect.top = 10f.dpToPx().toInt()
outRect.bottom = 10f.dpToPx().toInt()
}
}
}
})
binding.rvContentRanking.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
// 스크롤이 끝에 도달했는지 확인
if (!recyclerView.canScrollVertically(1) &&
lastVisibleItemPosition == itemTotalCount
) {
viewModel.getAudioContentRanking()
}
}
})
binding.rvContentRanking.adapter = adapter
}
@SuppressLint("NotifyDataSetChanged")
private fun bindData() {
viewModel.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.dateStringLiveData.observe(this) {
binding.tvDate.text = it
}
viewModel.contentRankingItemsLiveData.observe(this) {
if (viewModel.page == 0) {
adapter.items.clear()
}
adapter.items.addAll(it)
adapter.notifyDataSetChanged()
}
}
}

View File

@ -0,0 +1,83 @@
package kr.co.vividnext.sodalive.audio_content.all
import android.content.Context
import android.view.LayoutInflater
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.audio_content.main.GetAudioContentRankingItem
import kr.co.vividnext.sodalive.databinding.ItemAudioContentRankingAllBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
class AudioContentRankingAllAdapter(
private val onItemClick: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentRankingAllAdapter.ViewHolder>() {
inner class ViewHolder(
private val context: Context,
private val binding: ItemAudioContentRankingAllBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetAudioContentRankingItem, index: Int) {
binding.root.setOnClickListener { onItemClick(item.contentId) }
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(RoundedCornersTransformation(5.3f.dpToPx()))
}
binding.tvTitle.text = item.title
binding.tvRank.text = index.plus(1).toString()
binding.tvTheme.text = item.themeStr
binding.tvDuration.text = item.duration
binding.tvNickname.text = item.creatorNickname
if (item.price < 1) {
binding.tvPrice.text = "무료"
binding.tvPrice.setTextColor(ContextCompat.getColor(context, R.color.white))
binding.tvPrice.setCompoundDrawables(null, null, null, null)
binding.tvPrice.setPadding(
5.3f.dpToPx().toInt(),
2.7f.dpToPx().toInt(),
5.3f.dpToPx().toInt(),
2.7f.dpToPx().toInt()
)
binding.tvPrice.setBackgroundResource(R.drawable.bg_round_corner_2_6_cf5c37)
} else {
binding.tvPrice.text = item.price.moneyFormat()
binding.tvPrice.setTextColor(ContextCompat.getColor(context, R.color.color_909090))
binding.tvPrice.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_can,
0,
0,
0
)
binding.tvPrice.setPadding(0, 0, 0, 0)
binding.tvPrice.setBackgroundResource(0)
}
}
}
val items = mutableListOf<GetAudioContentRankingItem>()
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = ViewHolder(
parent.context,
ItemAudioContentRankingAllBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position], position)
}
}

View File

@ -0,0 +1,80 @@
package kr.co.vividnext.sodalive.audio_content.all
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentRankingItem
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
class AudioContentRankingAllViewModel(
private val repository: AudioContentRepository
) : 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 _dateStringLiveData = MutableLiveData<String>()
val dateStringLiveData: LiveData<String>
get() = _dateStringLiveData
private var _contentRankingItemsLiveData = MutableLiveData<List<GetAudioContentRankingItem>>()
val contentRankingItemsLiveData: LiveData<List<GetAudioContentRankingItem>>
get() = _contentRankingItemsLiveData
var page = 1
private var pageSize = 10
private var isLast = false
fun getAudioContentRanking() {
if (!_isLoading.value!! && !isLast && page <= 5) {
_isLoading.value = true
compositeDisposable.add(
repository.getContentRanking(
page = page,
size = pageSize,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
_isLoading.value = false
_dateStringLiveData.value =
"${it.data.startDate}~${it.data.endDate}"
if (it.data.items.isNotEmpty()) {
page += 1
_contentRankingItemsLiveData.value = it.data.items
} else {
isLast = true
_contentRankingItemsLiveData.value = listOf()
}
} else {
_isLoading.value = false
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}
}

View File

@ -0,0 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.all
import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
data class GetNewContentAllResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentMainItem>
)

View File

@ -1,7 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.comment package kr.co.vividnext.sodalive.audio_content.comment
import com.google.gson.annotations.SerializedName
data class ModifyCommentRequest( data class ModifyCommentRequest(
val commentId: Long, @SerializedName("commentId") val commentId: Long,
var comment: String? = null, @SerializedName("comment") var comment: String? = null,
var isActive: Boolean? = null @SerializedName("isActive") var isActive: Boolean? = null
) )

View File

@ -0,0 +1,211 @@
package kr.co.vividnext.sodalive.audio_content.curation
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllAdapter
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentCurationBinding
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject
class AudioContentCurationActivity : BaseActivity<ActivityAudioContentCurationBinding>(
ActivityAudioContentCurationBinding::inflate
) {
private val viewModel: AudioContentCurationViewModel by inject()
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: AudioContentNewAllAdapter
private var curationId: Long = 0
private lateinit var title: String
override fun onCreate(savedInstanceState: Bundle?) {
title = intent.getStringExtra(Constants.EXTRA_AUDIO_CONTENT_CURATION_TITLE) ?: ""
curationId = intent.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_CURATION_ID, 0)
super.onCreate(savedInstanceState)
if (title.isBlank() || curationId <= 0) {
Toast.makeText(applicationContext, "잘못된 요청입니다.", Toast.LENGTH_LONG).show()
finish()
}
bindData()
viewModel.getContentList(curationId = curationId)
}
override fun setupView() {
loadingDialog = LoadingDialog(this, layoutInflater)
binding.toolbar.tvBack.text = title
binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = AudioContentNewAllAdapter(
itemWidth = (screenWidth - 40f.dpToPx().toInt()) / 2,
onClickItem = {
startActivity(
Intent(this, AudioContentDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
}
)
},
onClickCreator = {
startActivity(
Intent(this, UserProfileActivity::class.java).apply {
putExtra(Constants.EXTRA_USER_ID, it)
}
)
}
)
binding.rvCuration.layoutManager = GridLayoutManager(this, 2)
binding.rvCuration.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val position = parent.getChildAdapterPosition(view)
if (position % 2 == 0) {
outRect.left = 13.3f.dpToPx().toInt()
outRect.right = 6.7f.dpToPx().toInt()
} else {
outRect.left = 6.7f.dpToPx().toInt()
outRect.right = 13.3f.dpToPx().toInt()
}
when (position) {
0, 1 -> {
outRect.top = 13.3f.dpToPx().toInt()
outRect.bottom = 6.7f.dpToPx().toInt()
}
adapter.itemCount - 1, adapter.itemCount - 2 -> {
outRect.top = 6.7f.dpToPx().toInt()
outRect.bottom = 13.3f.dpToPx().toInt()
}
else -> {
outRect.top = 6.7f.dpToPx().toInt()
outRect.bottom = 6.7f.dpToPx().toInt()
}
}
}
})
binding.rvCuration.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
// 스크롤이 끝에 도달했는지 확인
if (!recyclerView.canScrollVertically(1) &&
lastVisibleItemPosition == itemTotalCount
) {
viewModel.getContentList(curationId)
}
}
})
binding.rvCuration.adapter = adapter
binding.tvSortNewest.setOnClickListener {
viewModel.changeSort(AudioContentViewModel.Sort.NEWEST)
}
binding.tvSortPriceLow.setOnClickListener {
viewModel.changeSort(AudioContentViewModel.Sort.PRICE_LOW)
}
binding.tvSortPriceHigh.setOnClickListener {
viewModel.changeSort(AudioContentViewModel.Sort.PRICE_HIGH)
}
}
@SuppressLint("NotifyDataSetChanged")
private fun bindData() {
viewModel.toastLiveData.observe(this) {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
}
viewModel.isLoading.observe(this) {
if (it) {
loadingDialog.show(screenWidth, "")
} else {
loadingDialog.dismiss()
}
}
viewModel.contentListLiveData.observe(this) {
if (viewModel.page - 1 == 1) {
adapter.clear()
binding.rvCuration.scrollToPosition(0)
}
binding.tvTotalCount.text = "${it.totalCount}"
adapter.addItems(it.items)
}
viewModel.sort.observe(this) {
deselectSort()
selectSort(
when (it) {
AudioContentViewModel.Sort.PRICE_HIGH -> {
binding.tvSortPriceHigh
}
AudioContentViewModel.Sort.PRICE_LOW -> {
binding.tvSortPriceLow
}
else -> {
binding.tvSortNewest
}
}
)
viewModel.getContentList(curationId = curationId)
}
}
private fun deselectSort() {
val color = ContextCompat.getColor(
applicationContext,
R.color.color_88e2e2e2
)
binding.tvSortNewest.setTextColor(color)
binding.tvSortPriceLow.setTextColor(color)
binding.tvSortPriceHigh.setTextColor(color)
}
private fun selectSort(view: TextView) {
view.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_e2e2e2
)
)
}
}

View File

@ -0,0 +1,86 @@
package kr.co.vividnext.sodalive.audio_content.curation
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.orhanobut.logger.Logger
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
class AudioContentCurationViewModel(
private val repository: AudioContentRepository
) : 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 _contentListLiveData = MutableLiveData<GetCurationContentResponse>()
val contentListLiveData: LiveData<GetCurationContentResponse>
get() = _contentListLiveData
private val _sort = MutableLiveData(AudioContentViewModel.Sort.NEWEST)
val sort: LiveData<AudioContentViewModel.Sort>
get() = _sort
private var isLast = false
var page = 1
private val size = 10
fun getContentList(curationId: Long) {
if (!_isLoading.value!! && !isLast) {
_isLoading.value = true
compositeDisposable.add(
repository.getAudioContentListByCurationId(
curationId = curationId,
page = page,
size = size,
sort = _sort.value!!,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
if (it.data.items.isNotEmpty()) {
page += 1
_contentListLiveData.postValue(it.data!!)
} else {
isLast = true
}
} 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 changeSort(sort: AudioContentViewModel.Sort) {
page = 1
isLast = false
_sort.postValue(sort)
}
}

View File

@ -0,0 +1,9 @@
package kr.co.vividnext.sodalive.audio_content.curation
import com.google.gson.annotations.SerializedName
import kr.co.vividnext.sodalive.audio_content.main.GetAudioContentMainItem
data class GetCurationContentResponse(
@SerializedName("totalCount") val totalCount: Int,
@SerializedName("items") val items: List<GetAudioContentMainItem>
)

View File

@ -71,7 +71,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
binding.scrollView.scrollTo(0, 0) binding.scrollView.scrollTo(0, 0)
binding.sbProgress.progress = 0 binding.sbProgress.progress = 0
binding.ivPlayOrPause.setImageResource(R.drawable.btn_audio_content_play) binding.ivPlayOrPause.setImageResource(0)
binding.tvTotalDuration.text = " / 00:00:00" binding.tvTotalDuration.text = " / 00:00:00"
binding.tvCurrentDuration.text = "00:00:00" binding.tvCurrentDuration.text = "00:00:00"
binding.rlPreviewAlert.visibility = View.GONE binding.rlPreviewAlert.visibility = View.GONE
@ -104,8 +104,8 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
override fun onPause() { override fun onPause() {
super.onPause()
unregisterReceiver(audioContentReceiver) unregisterReceiver(audioContentReceiver)
super.onPause()
} }
override fun setupView() { override fun setupView() {
@ -390,6 +390,14 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
isAlertPreview = it.creator.creatorId != SharedPreferenceManager.userId && isAlertPreview = it.creator.creatorId != SharedPreferenceManager.userId &&
!it.existOrdered && !it.existOrdered &&
it.price > 0 it.price > 0
binding.ivPlayOrPause.setImageResource(
if (isAlertPreview) {
R.drawable.btn_audio_content_preview_play
} else {
R.drawable.btn_audio_content_play
}
)
} }
viewModel.isContentPlayLoopLiveData.observe(this) { viewModel.isContentPlayLoopLiveData.observe(this) {
@ -496,8 +504,14 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
binding.llPurchase.visibility = View.VISIBLE binding.llPurchase.visibility = View.VISIBLE
binding.tvPrice.text = response.price.toString() binding.tvPrice.text = response.price.toString()
binding.tvStrPurchaseOrRental.text = if (response.isOnlyRental) {
" 대여하기"
} else {
" 구매하기"
}
binding.llPurchase.setOnClickListener { binding.llPurchase.setOnClickListener {
showOrderDialog(audioContent = response) showOrderDialog(audioContent = response, isOnlyRental = response.isOnlyRental)
} }
} else { } else {
binding.llPurchase.visibility = View.GONE binding.llPurchase.visibility = View.GONE
@ -676,11 +690,15 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
} }
} }
private fun showOrderDialog(audioContent: GetAudioContentDetailResponse) { private fun showOrderDialog(
audioContent: GetAudioContentDetailResponse,
isOnlyRental: Boolean = false
) {
val dialog = AudioContentOrderFragment( val dialog = AudioContentOrderFragment(
price = audioContent.price, price = audioContent.price,
onClickKeep = { showOrderConfirmDialog(audioContent, OrderType.KEEP) }, isOnlyRental = isOnlyRental,
onClickRental = { showOrderConfirmDialog(audioContent, OrderType.RENTAL) } onClickKeep = { showOrderConfirmDialog(audioContent, isOnlyRental, OrderType.KEEP) },
onClickRental = { showOrderConfirmDialog(audioContent, isOnlyRental, OrderType.RENTAL) }
) )
dialog.show( dialog.show(
@ -691,6 +709,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
private fun showOrderConfirmDialog( private fun showOrderConfirmDialog(
audioContent: GetAudioContentDetailResponse, audioContent: GetAudioContentDetailResponse,
isOnlyRental: Boolean = false,
orderType: OrderType orderType: OrderType
) { ) {
AudioContentOrderConfirmDialog( AudioContentOrderConfirmDialog(
@ -702,6 +721,7 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
profileImageUrl = audioContent.creator.profileImageUrl, profileImageUrl = audioContent.creator.profileImageUrl,
nickname = audioContent.creator.nickname, nickname = audioContent.creator.nickname,
duration = audioContent.duration, duration = audioContent.duration,
isOnlyRental = isOnlyRental,
orderType = orderType, orderType = orderType,
price = audioContent.price, price = audioContent.price,
confirmButtonClick = { confirmButtonClick = {
@ -757,7 +777,11 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
if (isPlaying != null && isPlaying) { if (isPlaying != null && isPlaying) {
R.drawable.btn_audio_content_pause R.drawable.btn_audio_content_pause
} else { } else {
R.drawable.btn_audio_content_play if (isAlertPreview) {
R.drawable.btn_audio_content_preview_play
} else {
R.drawable.btn_audio_content_play
}
} }
) )
} }

View File

@ -190,7 +190,13 @@ class AudioContentDetailViewModel(
{ {
if (it.success && it.data != null) { if (it.success && it.data != null) {
getAudioContentDetail(audioContentId = contentId) getAudioContentDetail(audioContentId = contentId)
_toastLiveData.postValue("구매가 완료되었습니다.") _toastLiveData.postValue(
if (orderType == OrderType.RENTAL) {
"대여가 완료되었습니다."
} else {
"구매가 완료되었습니다."
}
)
} else { } else {
if (it.message != null) { if (it.message != null) {
_toastLiveData.postValue(it.message) _toastLiveData.postValue(it.message)

View File

@ -16,6 +16,7 @@ data class GetAudioContentDetailResponse(
@SerializedName("duration") val duration: String, @SerializedName("duration") val duration: String,
@SerializedName("isAdult") val isAdult: Boolean, @SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("isMosaic") val isMosaic: Boolean, @SerializedName("isMosaic") val isMosaic: Boolean,
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
@SerializedName("existOrdered") val existOrdered: Boolean, @SerializedName("existOrdered") val existOrdered: Boolean,
@SerializedName("orderType") val orderType: OrderType?, @SerializedName("orderType") val orderType: OrderType?,
@SerializedName("remainingTime") val remainingTime: String?, @SerializedName("remainingTime") val remainingTime: String?,

View File

@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.extensions.dpToPx
class AudioContentMainCurationAdapter( class AudioContentMainCurationAdapter(
private val onClickItem: (Long) -> Unit, private val onClickItem: (Long) -> Unit,
private val onClickCreator: (Long) -> Unit, private val onClickCreator: (Long) -> Unit,
private val onClickCurationMore: (Long, String) -> Unit
) : RecyclerView.Adapter<AudioContentMainCurationAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AudioContentMainCurationAdapter.ViewHolder>() {
private val items = mutableListOf<GetAudioContentCurationResponse>() private val items = mutableListOf<GetAudioContentCurationResponse>()
@ -25,6 +26,7 @@ class AudioContentMainCurationAdapter(
fun bind(item: GetAudioContentCurationResponse) { fun bind(item: GetAudioContentCurationResponse) {
binding.tvTitle.text = item.title binding.tvTitle.text = item.title
binding.tvDesc.text = item.description binding.tvDesc.text = item.description
binding.ivAll.setOnClickListener { onClickCurationMore(item.curationId, item.title) }
setAudioContentList(item.audioContents) setAudioContentList(item.audioContents)
} }

View File

@ -1,5 +1,6 @@
package kr.co.vividnext.sodalive.audio_content.main package kr.co.vividnext.sodalive.audio_content.main
import android.annotation.SuppressLint
import android.app.Service import android.app.Service
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
@ -10,12 +11,17 @@ import android.view.inputmethod.InputMethodManager
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.zhpan.bannerview.BaseBannerAdapter import com.zhpan.bannerview.BaseBannerAdapter
import com.zhpan.indicator.enums.IndicatorSlideMode import com.zhpan.indicator.enums.IndicatorSlideMode
import com.zhpan.indicator.enums.IndicatorStyle import com.zhpan.indicator.enums.IndicatorStyle
import kr.co.pointclick.sdk.offerwall.core.PointClickAd
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllActivity
import kr.co.vividnext.sodalive.audio_content.all.AudioContentRankingAllActivity
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationActivity
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListActivity
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadActivity
@ -44,6 +50,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
private lateinit var orderListAdapter: AudioContentMainContentAdapter private lateinit var orderListAdapter: AudioContentMainContentAdapter
private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter private lateinit var newContentThemeAdapter: AudioContentMainNewContentThemeAdapter
private lateinit var newContentAdapter: AudioContentMainContentAdapter private lateinit var newContentAdapter: AudioContentMainContentAdapter
private lateinit var contentRankingAdapter: AudioContentMainRankingAdapter
private lateinit var curationAdapter: AudioContentMainCurationAdapter private lateinit var curationAdapter: AudioContentMainCurationAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -80,12 +87,17 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
setupOrderList() setupOrderList()
setupNewContentTheme() setupNewContentTheme()
setupNewContent() setupNewContent()
setupContentRanking()
setupCuration() setupCuration()
binding.swipeRefreshLayout.setOnRefreshListener { binding.swipeRefreshLayout.setOnRefreshListener {
binding.swipeRefreshLayout.isRefreshing = false binding.swipeRefreshLayout.isRefreshing = false
viewModel.getMain() viewModel.getMain()
} }
binding.ivCanFree.setOnClickListener {
PointClickAd.showOfferwall(requireActivity(), "무료충전")
}
} }
private fun setupNewContentCreator() { private fun setupNewContentCreator() {
@ -116,7 +128,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
outRect.right = 10.7f.dpToPx().toInt() outRect.right = 10.7f.dpToPx().toInt()
} }
orderListAdapter.itemCount - 1 -> { newContentCreatorAdapter.itemCount - 1 -> {
outRect.left = 10.7f.dpToPx().toInt() outRect.left = 10.7f.dpToPx().toInt()
outRect.right = 0 outRect.right = 0
} }
@ -280,7 +292,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
outRect.right = 4f.dpToPx().toInt() outRect.right = 4f.dpToPx().toInt()
} }
orderListAdapter.itemCount - 1 -> { newContentThemeAdapter.itemCount - 1 -> {
outRect.left = 4f.dpToPx().toInt() outRect.left = 4f.dpToPx().toInt()
outRect.right = 0 outRect.right = 0
} }
@ -297,6 +309,10 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
} }
private fun setupNewContent() { private fun setupNewContent() {
binding.ivNewContentAll.setOnClickListener {
startActivity(Intent(requireContext(), AudioContentNewAllActivity::class.java))
}
newContentAdapter = AudioContentMainContentAdapter( newContentAdapter = AudioContentMainContentAdapter(
onClickItem = { onClickItem = {
startActivity( startActivity(
@ -335,7 +351,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
outRect.right = 6.7f.dpToPx().toInt() outRect.right = 6.7f.dpToPx().toInt()
} }
orderListAdapter.itemCount - 1 -> { newContentAdapter.itemCount - 1 -> {
outRect.left = 6.7f.dpToPx().toInt() outRect.left = 6.7f.dpToPx().toInt()
outRect.right = 0 outRect.right = 0
} }
@ -351,6 +367,46 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
binding.rvNewContent.adapter = newContentAdapter binding.rvNewContent.adapter = newContentAdapter
} }
private fun setupContentRanking() {
binding.ivContentRankingAll.setOnClickListener {
startActivity(Intent(requireContext(), AudioContentRankingAllActivity::class.java))
}
contentRankingAdapter = AudioContentMainRankingAdapter(
width = (screenWidth * 0.66).toInt()
) {
startActivity(
Intent(requireContext(), AudioContentDetailActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_ID, it)
}
)
}
binding.rvContentRanking.layoutManager = GridLayoutManager(
context,
3,
GridLayoutManager.HORIZONTAL,
false
)
binding.rvContentRanking.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
outRect.top = 13.3f.dpToPx().toInt()
outRect.bottom = 13.3f.dpToPx().toInt()
outRect.left = 13.3f.dpToPx().toInt()
outRect.right = 13.3f.dpToPx().toInt()
}
})
binding.rvContentRanking.adapter = contentRankingAdapter
}
private fun setupCuration() { private fun setupCuration() {
curationAdapter = AudioContentMainCurationAdapter( curationAdapter = AudioContentMainCurationAdapter(
onClickItem = { onClickItem = {
@ -366,6 +422,15 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
putExtra(Constants.EXTRA_USER_ID, it) putExtra(Constants.EXTRA_USER_ID, it)
} }
) )
},
onClickCurationMore = { curationId, title ->
startActivity(
Intent(requireContext(), AudioContentCurationActivity::class.java).apply {
putExtra(Constants.EXTRA_AUDIO_CONTENT_CURATION_ID, curationId)
putExtra(Constants.EXTRA_AUDIO_CONTENT_CURATION_TITLE, title)
}
)
} }
) )
@ -405,6 +470,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
binding.rvCuration.adapter = curationAdapter binding.rvCuration.adapter = curationAdapter
} }
@SuppressLint("SetTextI18n")
private fun bindData() { private fun bindData() {
viewModel.isLoading.observe(viewLifecycleOwner) { viewModel.isLoading.observe(viewLifecycleOwner) {
if (it) { if (it) {
@ -470,5 +536,11 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
View.VISIBLE View.VISIBLE
} }
} }
viewModel.contentRankingLiveData.observe(viewLifecycleOwner) {
binding.llContentRanking.visibility = View.VISIBLE
binding.tvDate.text = "${it.startDate}~${it.endDate}"
contentRankingAdapter.addItems(it.items)
}
} }
} }

View File

@ -0,0 +1,65 @@
package kr.co.vividnext.sodalive.audio_content.main
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemAudioContentMainRankingBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class AudioContentMainRankingAdapter(
private val width: Int,
private val onClickItem: (Long) -> Unit
) : RecyclerView.Adapter<AudioContentMainRankingAdapter.AudioContentMainRankingItemViewHolder>() {
inner class AudioContentMainRankingItemViewHolder(
private val binding: ItemAudioContentMainRankingBinding
) : RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(item: GetAudioContentRankingItem, index: Int) {
val lp = binding.root.layoutParams
lp.width = width
binding.root.layoutParams = lp
binding.root.setOnClickListener { onClickItem(item.contentId) }
binding.tvTitle.text = item.title
binding.tvRank.text = "${index + 1}"
binding.tvNickname.text = item.creatorNickname
binding.ivCover.load(item.coverImageUrl) {
crossfade(true)
placeholder(R.drawable.ic_place_holder)
transformations(RoundedCornersTransformation(2.7f.dpToPx()))
}
}
}
private val items = mutableListOf<GetAudioContentRankingItem>()
@SuppressLint("NotifyDataSetChanged")
fun addItems(items: List<GetAudioContentRankingItem>) {
this.items.clear()
this.items.addAll(items)
notifyDataSetChanged()
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
) = AudioContentMainRankingItemViewHolder(
ItemAudioContentMainRankingBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: AudioContentMainRankingItemViewHolder, position: Int) {
holder.bind(items[position], index = position)
}
}

View File

@ -45,6 +45,10 @@ class AudioContentMainViewModel(
val curationListLiveData: LiveData<List<GetAudioContentCurationResponse>> val curationListLiveData: LiveData<List<GetAudioContentCurationResponse>>
get() = _curationListLiveData get() = _curationListLiveData
private var _contentRankingLiveData = MutableLiveData<GetAudioContentRanking>()
val contentRankingLiveData: LiveData<GetAudioContentRanking>
get() = _contentRankingLiveData
fun getMain() { fun getMain() {
_isLoading.value = true _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
@ -61,6 +65,7 @@ class AudioContentMainViewModel(
_orderListLiveData.value = data.orderList _orderListLiveData.value = data.orderList
_bannerLiveData.value = data.bannerList _bannerLiveData.value = data.bannerList
_curationListLiveData.value = data.curationList _curationListLiveData.value = data.curationList
_contentRankingLiveData.value = data.contentRanking
val themeList = listOf("전체").union(data.themeList).toList() val themeList = listOf("전체").union(data.themeList).toList()
_themeListLiveData.value = themeList _themeListLiveData.value = themeList

View File

@ -10,7 +10,8 @@ data class GetAudioContentMainResponse(
@SerializedName("orderList") val orderList: List<GetAudioContentMainItem>, @SerializedName("orderList") val orderList: List<GetAudioContentMainItem>,
@SerializedName("themeList") val themeList: List<String>, @SerializedName("themeList") val themeList: List<String>,
@SerializedName("newContentList") val newContentList: List<GetAudioContentMainItem>, @SerializedName("newContentList") val newContentList: List<GetAudioContentMainItem>,
@SerializedName("curationList") val curationList: List<GetAudioContentCurationResponse> @SerializedName("curationList") val curationList: List<GetAudioContentCurationResponse>,
@SerializedName("contentRanking") val contentRanking: GetAudioContentRanking
) )
data class GetNewContentUploadCreator( data class GetNewContentUploadCreator(
@ -23,13 +24,30 @@ data class GetAudioContentMainItem(
@SerializedName("contentId") val contentId: Long, @SerializedName("contentId") val contentId: Long,
@SerializedName("coverImageUrl") val coverImageUrl: String, @SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String, @SerializedName("creatorProfileImageUrl") val creatorProfileImageUrl: String,
@SerializedName("creatorNickname") val creatorNickname: String @SerializedName("creatorNickname") val creatorNickname: String
) )
data class GetAudioContentRanking(
@SerializedName("startDate") val startDate: String,
@SerializedName("endDate") val endDate: String,
@SerializedName("items") val items: List<GetAudioContentRankingItem>
)
data class GetAudioContentRankingItem(
@SerializedName("contentId") val contentId: Long,
@SerializedName("title") val title: String,
@SerializedName("coverImageUrl") val coverImageUrl: String,
@SerializedName("themeStr") val themeStr: String,
@SerializedName("price") val price: Int,
@SerializedName("duration") val duration: String,
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("creatorNickname") val creatorNickname: String
)
data class GetAudioContentCurationResponse( data class GetAudioContentCurationResponse(
@SerializedName("curationId") val curationId: Long,
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("description") val description: String, @SerializedName("description") val description: String,
@SerializedName("contents") val audioContents: List<GetAudioContentMainItem> @SerializedName("contents") val audioContents: List<GetAudioContentMainItem>

View File

@ -23,6 +23,7 @@ class AudioContentOrderConfirmDialog(
profileImageUrl: String, profileImageUrl: String,
nickname: String, nickname: String,
duration: String, duration: String,
isOnlyRental: Boolean,
orderType: OrderType, orderType: OrderType,
price: Int, price: Int,
confirmButtonClick: () -> Unit, confirmButtonClick: () -> Unit,
@ -57,7 +58,7 @@ class AudioContentOrderConfirmDialog(
} }
dialogView.tvDuration.text = duration dialogView.tvDuration.text = duration
dialogView.tvPrice.text = if (orderType == OrderType.RENTAL) { dialogView.tvPrice.text = if (orderType == OrderType.RENTAL && !isOnlyRental) {
"${ceil(price * 0.6).toInt()}" "${ceil(price * 0.6).toInt()}"
} else { } else {
"$price" "$price"

View File

@ -10,6 +10,7 @@ import kotlin.math.ceil
class AudioContentOrderFragment( class AudioContentOrderFragment(
private val price: Int, private val price: Int,
private val isOnlyRental: Boolean,
private val onClickRental: () -> Unit, private val onClickRental: () -> Unit,
private val onClickKeep: () -> Unit private val onClickKeep: () -> Unit
) : BottomSheetDialogFragment() { ) : BottomSheetDialogFragment() {
@ -28,12 +29,18 @@ class AudioContentOrderFragment(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
binding.tvKeep.text = "$price" if (isOnlyRental) {
binding.tvRental.text = "${ceil(price * 0.6).toInt()}" binding.tvRental.text = "$price"
binding.rlKeep.visibility = View.GONE
} else {
binding.tvKeep.text = "$price"
binding.tvRental.text = "${ceil(price * 0.6).toInt()}"
binding.llKeep.setOnClickListener { binding.rlKeep.visibility = View.VISIBLE
onClickKeep() binding.llKeep.setOnClickListener {
dismiss() onClickKeep()
dismiss()
}
} }
binding.llRental.setOnClickListener { binding.llRental.setOnClickListener {

View File

@ -81,6 +81,23 @@ class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderList
} }
}) })
binding.rvOrderList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
.findLastCompletelyVisibleItemPosition()
val itemTotalCount = recyclerView.adapter!!.itemCount - 1
// 스크롤이 끝에 도달했는지 확인
if (!recyclerView.canScrollVertically(1) &&
lastVisibleItemPosition == itemTotalCount
) {
viewModel.getAudioContentOrderList {}
}
}
})
binding.rvOrderList.adapter = adapter binding.rvOrderList.adapter = adapter
} }
@ -106,5 +123,9 @@ class AudioContentOrderListActivity : BaseActivity<ActivityAudioContentOrderList
adapter.items.addAll(it) adapter.items.addAll(it)
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
} }
viewModel.totalCount.observe(this) {
binding.tvTotalCount.text = "$it"
}
} }
} }

View File

@ -25,53 +25,60 @@ class AudioContentOrderListViewModel(
val orderList: LiveData<List<GetAudioContentOrderListItem>> val orderList: LiveData<List<GetAudioContentOrderListItem>>
get() = _orderList get() = _orderList
private var _totalCount = MutableLiveData<Int>()
val totalCount: LiveData<Int>
get() = _totalCount
private var isLast = false private var isLast = false
var page = 1 var page = 1
private val size = 10 private val size = 10
fun getAudioContentOrderList(onFailure: (() -> Unit)? = null) { fun getAudioContentOrderList(onFailure: (() -> Unit)? = null) {
_isLoading.value = true if (_isLoading.value == false) {
compositeDisposable.add( _isLoading.value = true
repository.getAudioContentOrderList( compositeDisposable.add(
page = page, repository.getAudioContentOrderList(
size = size, page = page,
token = "Bearer ${SharedPreferenceManager.token}" size = size,
) token = "Bearer ${SharedPreferenceManager.token}"
.subscribeOn(Schedulers.io()) )
.observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io())
.subscribe( .observeOn(AndroidSchedulers.mainThread())
{ .subscribe(
if (it.success && it.data != null) { {
if (it.data.items.isNotEmpty()) { if (it.success && it.data != null) {
page += 1 _totalCount.value = it.data.totalCount
_orderList.postValue(it.data.items) if (it.data.items.isNotEmpty()) {
page += 1
_orderList.postValue(it.data.items)
} else {
isLast = true
}
} else { } else {
isLast = true if (it.message != null) {
} _toastLiveData.postValue(it.message)
} else { } else {
if (it.message != null) { _toastLiveData.postValue(
_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) { if (onFailure != null) {
onFailure() onFailure()
} }
} }
_isLoading.value = false )
}, )
{ }
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
if (onFailure != null) {
onFailure()
}
}
)
)
} }
} }

View File

@ -169,6 +169,8 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
binding.llPricePaid.setOnClickListener { viewModel.setPriceFree(false) } binding.llPricePaid.setOnClickListener { viewModel.setPriceFree(false) }
binding.llPriceFree.setOnClickListener { viewModel.setPriceFree(true) } binding.llPriceFree.setOnClickListener { viewModel.setPriceFree(true) }
binding.llRentalAndKeep.setOnClickListener { viewModel.setIsOnlyRental(false) }
binding.llOnlyRental.setOnClickListener { viewModel.setIsOnlyRental(true) }
binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) } binding.llCommentNo.setOnClickListener { viewModel.setAvailableComment(false) }
binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) } binding.llCommentYes.setOnClickListener { viewModel.setAvailableComment(true) }
@ -258,6 +260,32 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
} }
) )
compositeDisposable.add(
binding.etPreviewStartTime.textChanges().skip(1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it.isNotBlank()) {
viewModel.previewStartTime = it.toString()
} else {
viewModel.previewStartTime = null
}
}
)
compositeDisposable.add(
binding.etPreviewEndTime.textChanges().skip(1)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
if (it.isNotBlank()) {
viewModel.previewEndTime = it.toString()
} else {
viewModel.previewEndTime = null
}
}
)
viewModel.toastLiveData.observe(this) { viewModel.toastLiveData.observe(this) {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() } it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
} }
@ -272,51 +300,17 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
viewModel.isPriceFreeLiveData.observe(this) { viewModel.isPriceFreeLiveData.observe(this) {
if (it) { if (it) {
viewModel.price = 0 checkPriceFree()
binding.etSetPrice.setText("0")
binding.llSetPrice.visibility = View.GONE
binding.ivPriceFree.visibility = View.VISIBLE
binding.tvPriceFree.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
binding.llPriceFree.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivPricePaid.visibility = View.GONE
binding.tvPricePaid.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llPricePaid.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
} else { } else {
binding.llSetPrice.visibility = View.VISIBLE checkPricePaid()
}
}
binding.ivPricePaid.visibility = View.VISIBLE viewModel.isOnlyRentalLiveData.observe(this) {
binding.tvPricePaid.setTextColor( if (it) {
ContextCompat.getColor( checkOnlyRental()
applicationContext, } else {
R.color.color_eeeeee checkRentalAndKeep()
)
)
binding.llPricePaid.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivPriceFree.visibility = View.GONE
binding.tvPriceFree.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llPriceFree.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
} }
} }
@ -414,6 +408,109 @@ class AudioContentUploadActivity : BaseActivity<ActivityAudioContentUploadBindin
} }
} }
private fun checkPriceFree() {
viewModel.price = 0
binding.etSetPrice.setText("0")
binding.llSetPrice.visibility = View.GONE
binding.llConfigKeep.visibility = View.GONE
binding.tvTitleConfigKeep.visibility = View.GONE
binding.ivPriceFree.visibility = View.VISIBLE
binding.tvPriceFree.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
binding.llPriceFree.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivPricePaid.visibility = View.GONE
binding.tvPricePaid.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llPricePaid.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
binding.llConfigPreviewTime.visibility = View.GONE
}
private fun checkPricePaid() {
binding.llSetPrice.visibility = View.VISIBLE
binding.llConfigKeep.visibility = View.VISIBLE
binding.tvTitleConfigKeep.visibility = View.VISIBLE
binding.ivPricePaid.visibility = View.VISIBLE
binding.tvPricePaid.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
binding.llPricePaid.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivPriceFree.visibility = View.GONE
binding.tvPriceFree.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llPriceFree.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
binding.llConfigPreviewTime.visibility = View.VISIBLE
}
private fun checkRentalAndKeep() {
binding.tvPriceTitle.text = "소장 가격"
binding.ivRentalAndKeep.visibility = View.VISIBLE
binding.tvRentalAndKeep.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
binding.llRentalAndKeep.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivOnlyRental.visibility = View.GONE
binding.tvOnlyRental.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llOnlyRental.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
}
private fun checkOnlyRental() {
binding.tvPriceTitle.text = "대여 가격"
binding.ivOnlyRental.visibility = View.VISIBLE
binding.tvOnlyRental.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_eeeeee
)
)
binding.llOnlyRental.setBackgroundResource(R.drawable.bg_round_corner_6_7_9970ff)
binding.ivRentalAndKeep.visibility = View.GONE
binding.tvRentalAndKeep.setTextColor(
ContextCompat.getColor(
applicationContext,
R.color.color_9970ff
)
)
binding.llRentalAndKeep.setBackgroundResource(
R.drawable.bg_round_corner_6_7_1f1734_9970ff
)
}
private fun getFileName(uri: Uri): String? { private fun getFileName(uri: Uri): String? {
val scheme = uri.scheme val scheme = uri.scheme
var fileName: String? = null var fileName: String? = null

View File

@ -18,6 +18,8 @@ import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okio.BufferedSink import okio.BufferedSink
import java.io.File import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
class AudioContentUploadViewModel( class AudioContentUploadViewModel(
private val repository: AudioContentRepository private val repository: AudioContentRepository
@ -35,6 +37,10 @@ class AudioContentUploadViewModel(
val isAdultLiveData: LiveData<Boolean> val isAdultLiveData: LiveData<Boolean>
get() = _isAdultLiveData get() = _isAdultLiveData
private val _isOnlyRentalLiveData = MutableLiveData(false)
val isOnlyRentalLiveData: LiveData<Boolean>
get() = _isOnlyRentalLiveData
private val _isAvailableCommentLiveData = MutableLiveData(true) private val _isAvailableCommentLiveData = MutableLiveData(true)
val isAvailableCommentLiveData: LiveData<Boolean> val isAvailableCommentLiveData: LiveData<Boolean>
get() = _isAvailableCommentLiveData get() = _isAvailableCommentLiveData
@ -52,6 +58,8 @@ class AudioContentUploadViewModel(
var theme: GetAudioContentThemeResponse? = null var theme: GetAudioContentThemeResponse? = null
var coverImageUri: Uri? = null var coverImageUri: Uri? = null
var contentUri: Uri? = null var contentUri: Uri? = null
var previewStartTime: String? = null
var previewEndTime: String? = null
fun setAdult(isAdult: Boolean) { fun setAdult(isAdult: Boolean) {
_isAdultLiveData.postValue(isAdult) _isAdultLiveData.postValue(isAdult)
@ -63,6 +71,14 @@ class AudioContentUploadViewModel(
fun setPriceFree(isPriceFree: Boolean) { fun setPriceFree(isPriceFree: Boolean) {
_isPriceFreeLiveData.postValue(isPriceFree) _isPriceFreeLiveData.postValue(isPriceFree)
if (isPriceFree) {
_isOnlyRentalLiveData.postValue(false)
}
}
fun setIsOnlyRental(isOnlyRental: Boolean) {
_isOnlyRentalLiveData.postValue(isOnlyRental)
} }
fun uploadAudioContent(onSuccess: () -> Unit) { fun uploadAudioContent(onSuccess: () -> Unit) {
@ -76,7 +92,10 @@ class AudioContentUploadViewModel(
price = price, price = price,
themeId = theme!!.id, themeId = theme!!.id,
isAdult = _isAdultLiveData.value!!, isAdult = _isAdultLiveData.value!!,
isCommentAvailable = _isAvailableCommentLiveData.value!! isOnlyRental = _isOnlyRentalLiveData.value!!,
isCommentAvailable = _isAvailableCommentLiveData.value!!,
previewStartTime = previewStartTime,
previewEndTime = previewEndTime
) )
val requestJson = Gson().toJson(request) val requestJson = Gson().toJson(request)
@ -206,6 +225,52 @@ class AudioContentUploadViewModel(
return false return false
} }
if (previewStartTime != null && previewEndTime != null) {
val startTimeArray = previewStartTime!!.split(":")
if (startTimeArray.size != 3) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
return false
}
for (time in startTimeArray) {
if (time.length != 2) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
return false
}
}
val endTimeArray = previewEndTime!!.split(":")
if (endTimeArray.size != 3) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
return false
}
for (time in endTimeArray) {
if (time.length != 2) {
_toastLiveData.postValue("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다")
return false
}
}
val timeDifference = timeDifference(previewStartTime!!, previewEndTime!!)
if (timeDifference < 30000) {
_toastLiveData.postValue(
"미리 듣기의 최소 시간은 30초 입니다."
)
return false
}
} else {
if (previewStartTime != null || previewEndTime != null) {
_toastLiveData.postValue(
"미리 듣기 시작 시간과 종료 시간 둘 다 입력을 하거나 둘 다 입력 하지 않아야 합니다."
)
return false
}
}
if (contentUri == null) { if (contentUri == null) {
_toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.") _toastLiveData.postValue("오디오 콘텐츠를 선택해 주세요.")
return false return false
@ -218,4 +283,28 @@ class AudioContentUploadViewModel(
return true return true
} }
private fun timeDifference(startTime: String, endTime: String): Long {
try {
// Define a date format for parsing the times
val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.KOREAN)
// Parse the input times into Date objects
val date1 = dateFormat.parse(startTime)
val date2 = dateFormat.parse(endTime)
// Check if either date is null
if (date1 == null || date2 == null) {
return 0
}
// Calculate the absolute time difference in milliseconds
// Check if the time difference is greater than 30 seconds (30000 milliseconds)
return date2.time - date1.time
} catch (e: Exception) {
// Handle invalid time formats or parsing errors
return 0
}
}
} }

View File

@ -9,5 +9,8 @@ data class CreateAudioContentRequest(
@SerializedName("price") val price: Int, @SerializedName("price") val price: Int,
@SerializedName("themeId") val themeId: Long, @SerializedName("themeId") val themeId: Long,
@SerializedName("isAdult") val isAdult: Boolean, @SerializedName("isAdult") val isAdult: Boolean,
@SerializedName("isOnlyRental") val isOnlyRental: Boolean,
@SerializedName("isCommentAvailable") val isCommentAvailable: Boolean, @SerializedName("isCommentAvailable") val isCommentAvailable: Boolean,
@SerializedName("previewStartTime") val previewStartTime: String? = null,
@SerializedName("previewEndTime") val previewEndTime: String? = null
) )

View File

@ -8,6 +8,7 @@ object Constants {
const val PREF_IS_ADULT = "pref_is_adult" const val PREF_IS_ADULT = "pref_is_adult"
const val PREF_NICKNAME = "pref_nickname" const val PREF_NICKNAME = "pref_nickname"
const val PREF_USER_ROLE = "pref_user_role" const val PREF_USER_ROLE = "pref_user_role"
const val PREF_NO_CHAT_ROOM = "pref_no_chat"
const val PREF_PUSH_TOKEN = "pref_push_token" const val PREF_PUSH_TOKEN = "pref_push_token"
const val PREF_PROFILE_IMAGE = "pref_profile_image" const val PREF_PROFILE_IMAGE = "pref_profile_image"
const val PREF_IS_CONTENT_PLAY_LOOP = "pref_is_content_play_loop" const val PREF_IS_CONTENT_PLAY_LOOP = "pref_is_content_play_loop"
@ -46,6 +47,8 @@ object Constants {
const val EXTRA_AUDIO_CONTENT_COMMENT = "audio_content_comment" const val EXTRA_AUDIO_CONTENT_COMMENT = "audio_content_comment"
const val EXTRA_AUDIO_CONTENT_LOADING = "audio_content_loading" const val EXTRA_AUDIO_CONTENT_LOADING = "audio_content_loading"
const val EXTRA_AUDIO_CONTENT_CREATOR_ID = "audio_content_creator_id" const val EXTRA_AUDIO_CONTENT_CREATOR_ID = "audio_content_creator_id"
const val EXTRA_AUDIO_CONTENT_CURATION_ID = "extra_audio_content_curation_id"
const val EXTRA_AUDIO_CONTENT_CURATION_TITLE = "extra_audio_content_curation_title"
const val EXTRA_AUDIO_CONTENT_NEXT_ACTION = "audio_content_next_action" const val EXTRA_AUDIO_CONTENT_NEXT_ACTION = "audio_content_next_action"
const val EXTRA_AUDIO_CONTENT_ALERT_PREVIEW = "audio_content_alert_preview" const val EXTRA_AUDIO_CONTENT_ALERT_PREVIEW = "audio_content_alert_preview"
const val EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL = "audio_content_cover_image_url" const val EXTRA_AUDIO_CONTENT_COVER_IMAGE_URL = "audio_content_cover_image_url"

View File

@ -3,6 +3,8 @@ package kr.co.vividnext.sodalive.common
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import kr.co.vividnext.sodalive.settings.notification.MemberRole import kr.co.vividnext.sodalive.settings.notification.MemberRole
object SharedPreferenceManager { object SharedPreferenceManager {
@ -122,4 +124,18 @@ object SharedPreferenceManager {
set(value) { set(value) {
sharedPreferences[Constants.PREF_IS_VIEWED_ON_BOARDING_TUTORIAL] = value sharedPreferences[Constants.PREF_IS_VIEWED_ON_BOARDING_TUTORIAL] = value
} }
var noChatRoomList: List<Long>
get() {
val list = sharedPreferences[Constants.PREF_NO_CHAT_ROOM, ""]
val gson = Gson()
val listType = object : TypeToken<List<Long>>() {}.type
val myList = gson.fromJson<List<Long>>(list, listType)
return myList ?: emptyList()
}
set(value) {
val gson = Gson()
val listJson = gson.toJson(value)
sharedPreferences[Constants.PREF_NO_CHAT_ROOM] = listJson
}
} }

View File

@ -7,9 +7,12 @@ import kr.co.vividnext.sodalive.audio_content.AudioContentApi
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
import kr.co.vividnext.sodalive.audio_content.PlaybackTrackingRepository import kr.co.vividnext.sodalive.audio_content.PlaybackTrackingRepository
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllViewModel
import kr.co.vividnext.sodalive.audio_content.all.AudioContentRankingAllViewModel
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentListViewModel import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentListViewModel
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentReplyViewModel import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentReplyViewModel
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationViewModel
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel
import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainViewModel import kr.co.vividnext.sodalive.audio_content.main.AudioContentMainViewModel
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
@ -190,7 +193,10 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { ProfileUpdateViewModel(get()) } viewModel { ProfileUpdateViewModel(get()) }
viewModel { NicknameUpdateViewModel(get()) } viewModel { NicknameUpdateViewModel(get()) }
viewModel { MemberTagViewModel(get()) } viewModel { MemberTagViewModel(get()) }
viewModel { UserProfileDonationAllViewModel(get()) } viewModel { UserProfileDonationAllViewModel(get(), get()) }
viewModel { AudioContentCurationViewModel(get()) }
viewModel { AudioContentNewAllViewModel(get()) }
viewModel { AudioContentRankingAllViewModel(get()) }
} }
private val repositoryModule = module { private val repositoryModule = module {

View File

@ -27,6 +27,7 @@ class ExplorerAdapter(
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetExplorerSectionResponse) { fun bind(item: GetExplorerSectionResponse) {
setTitle(item) setTitle(item)
setDesc(item)
setCreatorList(item) setCreatorList(item)
} }
@ -56,8 +57,20 @@ class ExplorerAdapter(
} }
} }
private fun setDesc(item: GetExplorerSectionResponse) {
if (item.desc != null) {
binding.llDesc.visibility = View.VISIBLE
binding.tvDesc.text = item.desc
} else {
binding.llDesc.visibility = View.GONE
}
}
private fun setCreatorList(item: GetExplorerSectionResponse) { private fun setCreatorList(item: GetExplorerSectionResponse) {
val adapter = ExplorerSectionAdapter(onClickItem = onClickItem) val adapter = ExplorerSectionAdapter(
onClickItem = onClickItem,
isVisibleRanking = item.desc != null
)
binding.rvExplorerSection.layoutManager = LinearLayoutManager( binding.rvExplorerSection.layoutManager = LinearLayoutManager(
context, context,

View File

@ -85,17 +85,17 @@ class ExplorerFragment : BaseFragment<FragmentExplorerBinding>(
when (parent.getChildAdapterPosition(view)) { when (parent.getChildAdapterPosition(view)) {
0 -> { 0 -> {
outRect.top = 0 outRect.top = 0
outRect.bottom = 30f.dpToPx().toInt() outRect.bottom = 15f.dpToPx().toInt()
} }
adapter.itemCount - 1 -> { adapter.itemCount - 1 -> {
outRect.top = 30f.dpToPx().toInt() outRect.top = 15f.dpToPx().toInt()
outRect.bottom = 0 outRect.bottom = 0
} }
else -> { else -> {
outRect.top = 30f.dpToPx().toInt() outRect.top = 15f.dpToPx().toInt()
outRect.bottom = 30f.dpToPx().toInt() outRect.bottom = 15f.dpToPx().toInt()
} }
} }
} }

View File

@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.explorer
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load import coil.load
@ -10,7 +11,8 @@ import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemExplorerSectionBinding import kr.co.vividnext.sodalive.databinding.ItemExplorerSectionBinding
class ExplorerSectionAdapter( class ExplorerSectionAdapter(
private val onClickItem: (Long) -> Unit private val onClickItem: (Long) -> Unit,
private val isVisibleRanking: Boolean
) : RecyclerView.Adapter<ExplorerSectionAdapter.ViewHolder>() { ) : RecyclerView.Adapter<ExplorerSectionAdapter.ViewHolder>() {
private val items = mutableListOf<GetExplorerSectionCreatorResponse>() private val items = mutableListOf<GetExplorerSectionCreatorResponse>()
@ -18,7 +20,8 @@ class ExplorerSectionAdapter(
inner class ViewHolder( inner class ViewHolder(
private val binding: ItemExplorerSectionBinding private val binding: ItemExplorerSectionBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetExplorerSectionCreatorResponse) { fun bind(item: GetExplorerSectionCreatorResponse, index: Int) {
binding.root.setOnClickListener { onClickItem(item.id) }
binding.tvNickname.text = item.nickname binding.tvNickname.text = item.nickname
binding.tvTags.text = item.tags binding.tvTags.text = item.tags
@ -28,7 +31,39 @@ class ExplorerSectionAdapter(
crossfade(true) crossfade(true)
} }
binding.root.setOnClickListener { onClickItem(item.id) } if (isVisibleRanking) {
when (index) {
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
}
}
}
} }
} }
@ -41,7 +76,7 @@ class ExplorerSectionAdapter(
) )
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position]) holder.bind(items[position], index = position)
} }
override fun getItemCount() = items.size override fun getItemCount() = items.size

View File

@ -10,6 +10,7 @@ data class GetExplorerSectionResponse(
@SerializedName("title") val title: String, @SerializedName("title") val title: String,
@SerializedName("coloredTitle") val coloredTitle: String?, @SerializedName("coloredTitle") val coloredTitle: String?,
@SerializedName("color") val color: String?, @SerializedName("color") val color: String?,
@SerializedName("desc") val desc: String?,
@SerializedName("creators") val creators: List<GetExplorerSectionCreatorResponse> @SerializedName("creators") val creators: List<GetExplorerSectionCreatorResponse>
) )

View File

@ -10,6 +10,8 @@ data class GetDonationAllResponse(
val accumulatedCansLastWeek: Int, val accumulatedCansLastWeek: Int,
@SerializedName("accumulatedCansThisMonth") @SerializedName("accumulatedCansThisMonth")
val accumulatedCansThisMonth: Int, val accumulatedCansThisMonth: Int,
@SerializedName("isVisibleDonationRank")
val isVisibleDonationRank: Boolean,
@SerializedName("totalCount") @SerializedName("totalCount")
val totalCount: Int, val totalCount: Int,
@SerializedName("userDonationRanking") @SerializedName("userDonationRanking")

View File

@ -53,9 +53,9 @@ class UserProfileDonationAllAdapter(private val userId: Long) :
binding.ivCrown.visibility = View.VISIBLE binding.ivCrown.visibility = View.VISIBLE
binding.rlDonationRankingRoot.setBackgroundResource( binding.rlDonationRankingRoot.setBackgroundResource(
if (items.size == 1) { if (items.size == 1) {
R.drawable.bg_round_corner_4_7_2b2635 R.drawable.bg_round_corner_4_7_13181b
} else { } else {
R.drawable.bg_top_round_corner_4_7_2b2635 R.drawable.bg_top_round_corner_4_7_13181b
} }
) )
@ -81,11 +81,11 @@ class UserProfileDonationAllAdapter(private val userId: Long) :
if (items.size == 2) { if (items.size == 2) {
binding.rlDonationRankingRoot.setBackgroundResource( binding.rlDonationRankingRoot.setBackgroundResource(
R.drawable.bg_bottom_round_corner_4_7_2b2635 R.drawable.bg_bottom_round_corner_4_7_13181b
) )
} else { } else {
binding.rlDonationRankingRoot.setBackgroundColor( binding.rlDonationRankingRoot.setBackgroundColor(
ContextCompat.getColor(context, R.color.color_2b2635) ContextCompat.getColor(context, R.color.color_13181b)
) )
} }
@ -109,7 +109,7 @@ class UserProfileDonationAllAdapter(private val userId: Long) :
binding.ivCrown.setImageResource(R.drawable.ic_crown_3) binding.ivCrown.setImageResource(R.drawable.ic_crown_3)
binding.ivCrown.visibility = View.VISIBLE binding.ivCrown.visibility = View.VISIBLE
binding.rlDonationRankingRoot.setBackgroundResource( binding.rlDonationRankingRoot.setBackgroundResource(
R.drawable.bg_bottom_round_corner_4_7_2b2635 R.drawable.bg_bottom_round_corner_4_7_13181b
) )
lp.setMargins( lp.setMargins(

View File

@ -7,6 +7,7 @@ import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
@ -117,8 +118,13 @@ class UserProfileDonationAllViewActivity : BaseActivity<ActivityUserProfileLiveA
if (SharedPreferenceManager.userId == userId) { if (SharedPreferenceManager.userId == userId) {
binding.llTotal.visibility = View.VISIBLE binding.llTotal.visibility = View.VISIBLE
binding.llVisibleDonationRanking.visibility = View.VISIBLE
binding.ivVisibleDonationRank.setOnClickListener {
viewModel.onClickToggleVisibleDonationRank()
}
} else { } else {
binding.llTotal.visibility = View.GONE binding.llTotal.visibility = View.GONE
binding.llVisibleDonationRanking.visibility = View.GONE
} }
} }
@ -145,5 +151,15 @@ class UserProfileDonationAllViewActivity : BaseActivity<ActivityUserProfileLiveA
adapter.items.addAll(it.userDonationRanking) adapter.items.addAll(it.userDonationRanking)
adapter.notifyDataSetChanged() adapter.notifyDataSetChanged()
} }
viewModel.isVisibleDonationRank.observe(this) {
binding.ivVisibleDonationRank.setImageResource(
if (it) {
R.drawable.btn_toggle_on_big
} else {
R.drawable.btn_toggle_off_big
}
)
}
} }
} }

View File

@ -8,9 +8,12 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.explorer.ExplorerRepository import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateRequest
import kr.co.vividnext.sodalive.user.UserRepository
class UserProfileDonationAllViewModel( class UserProfileDonationAllViewModel(
private val repository: ExplorerRepository private val repository: ExplorerRepository,
private val memberRepository: UserRepository
) : BaseViewModel() { ) : BaseViewModel() {
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<String?>()
@ -25,6 +28,10 @@ class UserProfileDonationAllViewModel(
val donationLiveData: LiveData<GetDonationAllResponse> val donationLiveData: LiveData<GetDonationAllResponse>
get() = _donationLiveData get() = _donationLiveData
private var _isVisibleDonationRank = MutableLiveData<Boolean>()
val isVisibleDonationRank: LiveData<Boolean>
get() = _isVisibleDonationRank
private var isLast = false private var isLast = false
private var page = 1 private var page = 1
private val size = 10 private val size = 10
@ -51,6 +58,7 @@ class UserProfileDonationAllViewModel(
} else { } else {
isLast = true isLast = true
} }
_isVisibleDonationRank.postValue(it.data.isVisibleDonationRank)
} else { } else {
if (it.message != null) { if (it.message != null) {
_toastLiveData.postValue(it.message) _toastLiveData.postValue(it.message)
@ -78,4 +86,43 @@ class UserProfileDonationAllViewModel(
isLast = false isLast = false
getCreatorProfileDonationRanking(userId) getCreatorProfileDonationRanking(userId)
} }
fun onClickToggleVisibleDonationRank() {
val nowStateVisibleDonationRank = _isVisibleDonationRank.value!!
_isLoading.value = true
compositeDisposable.add(
memberRepository.updateProfile(
request = ProfileUpdateRequest(
email = SharedPreferenceManager.email,
isVisibleDonationRank = !nowStateVisibleDonationRank
),
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success) {
_isVisibleDonationRank.postValue(!nowStateVisibleDonationRank)
} 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("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
} }

View File

@ -1,13 +1,18 @@
package kr.co.vividnext.sodalive.live.reservation package kr.co.vividnext.sodalive.live.reservation
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import coil.load import com.bumptech.glide.Glide
import coil.transform.RoundedCornersTransformation import com.bumptech.glide.load.resource.bitmap.CenterCrop
import kr.co.vividnext.sodalive.R import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ItemLiveReservationBinding import kr.co.vividnext.sodalive.databinding.ItemLiveReservationBinding
import kr.co.vividnext.sodalive.databinding.ItemMyLiveReservationBinding import kr.co.vividnext.sodalive.databinding.ItemMyLiveReservationBinding
@ -24,6 +29,7 @@ class LiveReservationAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 1) { return if (viewType == 1) {
MyLiveViewHolder( MyLiveViewHolder(
parent.context,
ItemMyLiveReservationBinding.inflate( ItemMyLiveReservationBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
@ -32,6 +38,7 @@ class LiveReservationAdapter(
) )
} else { } else {
ViewHolder( ViewHolder(
parent.context,
ItemLiveReservationBinding.inflate( ItemLiveReservationBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
@ -70,15 +77,32 @@ class LiveReservationAdapter(
} }
inner class ViewHolder( inner class ViewHolder(
private val context: Context,
private val binding: ItemLiveReservationBinding private val binding: ItemLiveReservationBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomListResponse) { fun bind(item: GetRoomListResponse) {
binding.ivCover.load(item.coverImageUrl) { val lp = binding.ivCover.layoutParams
crossfade(true) lp.width = 80f.dpToPx().toInt()
placeholder(R.drawable.ic_place_holder) lp.height = 116.7f.dpToPx().toInt()
transformations(RoundedCornersTransformation(4.7f.dpToPx()))
} Glide
.with(context)
.asBitmap()
.transform(CenterCrop(), RoundedCorners(16f.dpToPx().toInt()))
.load(item.coverImageUrl)
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
binding.ivCover.setImageBitmap(resource)
binding.ivCover.layoutParams = lp
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
binding.tvDate.text = item.beginDateTime binding.tvDate.text = item.beginDateTime
binding.tvNickname.text = item.creatorNickname binding.tvNickname.text = item.creatorNickname
binding.tvTitle.text = item.title binding.tvTitle.text = item.title
@ -106,6 +130,7 @@ class LiveReservationAdapter(
} }
inner class MyLiveViewHolder( inner class MyLiveViewHolder(
private val context: Context,
private val binding: ItemMyLiveReservationBinding private val binding: ItemMyLiveReservationBinding
) : RecyclerView.ViewHolder(binding.root) { ) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GetRoomListResponse, position: Int) { fun bind(item: GetRoomListResponse, position: Int) {
@ -114,11 +139,28 @@ class LiveReservationAdapter(
} else { } else {
View.GONE View.GONE
} }
binding.ivCover.load(item.coverImageUrl) {
crossfade(true) val lp = binding.ivCover.layoutParams
placeholder(R.drawable.ic_place_holder) lp.width = 80f.dpToPx().toInt()
transformations(RoundedCornersTransformation(4f.dpToPx())) lp.height = 116.7f.dpToPx().toInt()
}
Glide
.with(context)
.asBitmap()
.load(item.coverImageUrl)
.transform(CenterCrop(), RoundedCorners(16f.dpToPx().toInt()))
.into(object : CustomTarget<Bitmap>() {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
binding.ivCover.setImageBitmap(resource)
binding.ivCover.layoutParams = lp
}
override fun onLoadCleared(placeholder: Drawable?) {
}
})
binding.tvDate.text = item.beginDateTime binding.tvDate.text = item.beginDateTime
binding.tvNickname.text = item.creatorNickname binding.tvNickname.text = item.creatorNickname
binding.tvTitle.text = item.title binding.tvTitle.text = item.title

View File

@ -1,15 +1,12 @@
package kr.co.vividnext.sodalive.live.reservation.all package kr.co.vividnext.sodalive.live.reservation.all
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -30,7 +27,6 @@ import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.reservation.LiveReservationAdapter import kr.co.vividnext.sodalive.live.reservation.LiveReservationAdapter
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateActivity
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
import kr.co.vividnext.sodalive.live.room.dialog.LiveCancelDialog import kr.co.vividnext.sodalive.live.room.dialog.LiveCancelDialog
@ -51,19 +47,9 @@ class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBindin
private lateinit var loadingDialog: LoadingDialog private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: LiveReservationAdapter private lateinit var adapter: LiveReservationAdapter
private lateinit var selectedDateString: String private lateinit var selectedDateString: String
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
activityResultLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
refresh()
}
}
setupCalendar() setupCalendar()
} }
@ -198,10 +184,6 @@ class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBindin
if (adapter.items.isEmpty()) { if (adapter.items.isEmpty()) {
binding.swipeRefreshLayout.visibility = View.GONE binding.swipeRefreshLayout.visibility = View.GONE
binding.llNoItems.visibility = View.VISIBLE binding.llNoItems.visibility = View.VISIBLE
binding.llNoItems.setOnClickListener {
val intent = Intent(applicationContext, LiveRoomCreateActivity::class.java)
activityResultLauncher.launch(intent)
}
} }
} else { } else {
binding.swipeRefreshLayout.visibility = View.VISIBLE binding.swipeRefreshLayout.visibility = View.VISIBLE

View File

@ -11,6 +11,7 @@ import android.graphics.Rect
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.CountDownTimer
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.text.Spannable import android.text.Spannable
@ -107,6 +108,57 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
private var isSpeaker = false private var isSpeaker = false
private var isSpeakerFold = false private var isSpeakerFold = false
private var isNoChatting = false
private var remainingNoChattingTime = noChattingTime
private val countDownTimer = object : CountDownTimer(remainingNoChattingTime * 1000, 1000) {
override fun onTick(millisUntilFinished: Long) {
remainingNoChattingTime -= 1
}
override fun onFinish() {
isNoChatting = false
remainingNoChattingTime = noChattingTime
removeNoChatRoom()
Toast.makeText(
applicationContext,
"채팅금지가 해제되었습니다.",
Toast.LENGTH_SHORT
).show()
}
}
private fun startNoChatting() {
hideKeyboard {
binding.etChat.clearFocus()
isNoChatting = true
Toast.makeText(
applicationContext,
"${viewModel.getManagerNickname()}님이 3분간 채팅을 금지하였습니다.",
Toast.LENGTH_SHORT
).show()
countDownTimer.start()
}
}
private fun addNoChatRoom() {
val noChatRoomList = SharedPreferenceManager.noChatRoomList.toMutableList()
noChatRoomList.add(roomId)
SharedPreferenceManager.noChatRoomList = noChatRoomList
}
private fun removeNoChatRoom() {
val noChatRoomList = SharedPreferenceManager.noChatRoomList.toMutableList()
noChatRoomList.remove(roomId)
SharedPreferenceManager.noChatRoomList = noChatRoomList
}
private fun containNoChatRoom(): Boolean {
val noChatRoomList = SharedPreferenceManager.noChatRoomList
return noChatRoomList.contains(roomId)
}
private val onBackPressedCallback = object : OnBackPressedCallback(true) { private val onBackPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
onClickQuit() onClickQuit()
@ -150,6 +202,17 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
viewModel.getMemberCan() viewModel.getMemberCan()
viewModel.getRoomInfo(roomId) viewModel.getRoomInfo(roomId)
binding.etChat.setOnFocusChangeListener { view, hasFocus ->
if (isNoChatting && hasFocus) {
Toast.makeText(
applicationContext,
"${remainingNoChattingTime}초 동안 채팅하실 수 없습니다",
Toast.LENGTH_SHORT
).show()
view.clearFocus()
}
}
} }
override fun onStart() { override fun onStart() {
@ -232,6 +295,15 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
changeListenerMessage(memberId) changeListenerMessage(memberId)
}, },
onClickNoChatting = { userId, nickname, profileUrl ->
LiveRoomNoChattingDialog(
activity = this,
layoutInflater = layoutInflater,
nickname = nickname,
profileUrl = profileUrl,
confirmButtonClick = { setNoChatting(userId, nickname) }
).show(screenWidth)
},
onClickKickOut = { onClickKickOut = {
LiveDialog( LiveDialog(
activity = this, activity = this,
@ -304,6 +376,15 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
cancelButtonClick = {} cancelButtonClick = {}
).show(screenWidth) ).show(screenWidth)
}, },
onClickNoChatting = { userId, nickname, profileUrl ->
LiveRoomNoChattingDialog(
activity = this,
layoutInflater = layoutInflater,
nickname = nickname,
profileUrl = profileUrl,
confirmButtonClick = { setNoChatting(userId, nickname) }
).show(screenWidth)
},
onClickPopupMenu = { userId, nickname, isBlock, view -> onClickPopupMenu = { userId, nickname, isBlock, view ->
showOptionMenu( showOptionMenu(
this, this,
@ -398,6 +479,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
agora.deInitAgoraEngine() agora.deInitAgoraEngine()
} }
} }
countDownTimer.cancel()
super.onDestroy() super.onDestroy()
} }
@ -677,7 +759,13 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
} }
binding.llViewUsers.setOnClickListener { roomProfileDialog.show() } if (response.creatorId == SharedPreferenceManager.userId) {
binding.llViewUsers.visibility = View.VISIBLE
binding.llViewUsers.setOnClickListener { roomProfileDialog.show() }
} else {
binding.llViewUsers.visibility = View.GONE
}
binding.tvParticipate.text = "${response.participantsCount}" binding.tvParticipate.text = "${response.participantsCount}"
setNoticeAndClickableUrl(binding.tvNotice, response.notice) setNoticeAndClickableUrl(binding.tvNotice, response.notice)
@ -967,6 +1055,17 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
} }
private fun setNoChatting(userId: Long, nickname: String) {
agora.sendRawMessageToPeer(
receiverUid = userId.toString(),
requestType = LiveRoomRequestType.NO_CHATTING
) {
handler.post {
showDialog(content = "${nickname}님을 3분간 채팅금지를 하였습니다.")
}
}
}
private fun showDialog( private fun showDialog(
content: String, content: String,
cancelTitle: String = "", cancelTitle: String = "",
@ -1008,7 +1107,13 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
val profileUrl = viewModel.getUserProfileUrl(SharedPreferenceManager.userId.toInt()) val profileUrl = viewModel.getUserProfileUrl(SharedPreferenceManager.userId.toInt())
val rank = viewModel.getUserRank(SharedPreferenceManager.userId) val rank = viewModel.getUserRank(SharedPreferenceManager.userId)
if (binding.etChat.text.isNotBlank() && nickname.isNotBlank() && profileUrl.isNotBlank()) { if (isNoChatting) {
Toast.makeText(
applicationContext,
"${remainingNoChattingTime}초 동안 채팅하실 수 없습니다",
Toast.LENGTH_SHORT
).show()
} else if (binding.etChat.text.isNotBlank() && nickname.isNotBlank() && profileUrl.isNotBlank()) {
val message = binding.etChat.text.toString() val message = binding.etChat.text.toString()
chatAdapter.items.add( chatAdapter.items.add(
LiveRoomNormalChat( LiveRoomNormalChat(
@ -1086,6 +1191,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
private fun joinChannel(roomInfo: GetRoomInfoResponse) { private fun joinChannel(roomInfo: GetRoomInfoResponse) {
loadingDialog.show(width = screenWidth, message = "라이브에 입장하고 있습니다.")
val userId = SharedPreferenceManager.userId val userId = SharedPreferenceManager.userId
agora.joinRtcChannel( agora.joinRtcChannel(
uid = userId.toInt(), uid = userId.toInt(),
@ -1194,6 +1301,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
}, },
rtmChannelJoinSuccess = { rtmChannelJoinSuccess = {
handler.post {
loadingDialog.dismiss()
}
if (userId == roomInfo.creatorId) { if (userId == roomInfo.creatorId) {
setBroadcaster() setBroadcaster()
} else { } else {
@ -1208,6 +1319,10 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} else { } else {
startService(intent) startService(intent)
} }
if (containNoChatRoom()) {
startNoChatting()
}
}, },
rtmChannelJoinFail = { rtmChannelJoinFail = {
agoraConnectFail() agoraConnectFail()
@ -1216,8 +1331,11 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
} }
private fun agoraConnectFail() { private fun agoraConnectFail() {
showToast("라이브에 접속하지 못했습니다.\n다시 시도해 주세요.") handler.post {
finish() loadingDialog.dismiss()
showToast("라이브에 접속하지 못했습니다.\n다시 시도해 주세요.")
finish()
}
} }
private val rtcEventHandler = object : IRtcEngineEventHandler() { private val rtcEventHandler = object : IRtcEngineEventHandler() {
@ -1402,7 +1520,19 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
viewModel.getRoomInfo(roomId = roomId) viewModel.getRoomInfo(roomId = roomId)
return return
} }
if (rawMessage == LiveRoomRequestType.NO_CHATTING.toString() && !isNoChatting) {
handler.post {
addNoChatRoom()
startNoChatting()
}
return
}
} }
} }
} }
companion object {
private const val noChattingTime = 180L
}
} }

View File

@ -0,0 +1,62 @@
package kr.co.vividnext.sodalive.live.room
import android.app.Activity
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.WindowManager
import androidx.appcompat.app.AlertDialog
import coil.load
import coil.transform.CircleCropTransformation
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.DialogLiveNoChattingBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
class LiveRoomNoChattingDialog(
activity: Activity,
layoutInflater: LayoutInflater,
nickname: String,
profileUrl: String,
confirmButtonClick: () -> Unit,
) {
private val alertDialog: AlertDialog
val dialogView = DialogLiveNoChattingBinding.inflate(layoutInflater)
init {
val dialogBuilder = AlertDialog.Builder(activity)
dialogBuilder.setView(dialogView.root)
alertDialog = dialogBuilder.create()
alertDialog.setCancelable(false)
alertDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialogView.tvCancel.setOnClickListener {
alertDialog.dismiss()
}
dialogView.tvConfirm.setOnClickListener {
alertDialog.dismiss()
confirmButtonClick()
}
dialogView.tvNickname.text = nickname
dialogView.ivProfile.load(profileUrl) {
crossfade(true)
placeholder(R.drawable.bg_placeholder)
transformations(CircleCropTransformation())
}
}
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

@ -8,4 +8,5 @@ enum class LiveRoomRequestType {
@SerializedName("KICK_OUT") KICK_OUT, @SerializedName("KICK_OUT") KICK_OUT,
@SerializedName("SET_MANAGER") SET_MANAGER, @SerializedName("SET_MANAGER") SET_MANAGER,
@SerializedName("RELEASE_MANAGER") RELEASE_MANAGER, @SerializedName("RELEASE_MANAGER") RELEASE_MANAGER,
@SerializedName("NO_CHATTING") NO_CHATTING,
} }

View File

@ -58,9 +58,8 @@ class LiveRoomDetailFragment(
behavior.state = BottomSheetBehavior.STATE_EXPANDED behavior.state = BottomSheetBehavior.STATE_EXPANDED
bindData() bindData()
viewModel.getDetail(roomId) { dismiss() }
binding.ivClose.setOnClickListener { dismiss() } binding.ivClose.setOnClickListener { dismiss() }
viewModel.getDetail(roomId) { dismiss() }
} }
private fun bindData() { private fun bindData() {

View File

@ -62,9 +62,9 @@ class LiveRoomDonationRankingAdapter :
binding.ivCrown.visibility = View.VISIBLE binding.ivCrown.visibility = View.VISIBLE
binding.root.setBackgroundResource( binding.root.setBackgroundResource(
if (items.size == 1) { if (items.size == 1) {
R.drawable.bg_round_corner_4_7_2b2635 R.drawable.bg_round_corner_4_7_13181b
} else { } else {
R.drawable.bg_top_round_corner_4_7_2b2635 R.drawable.bg_top_round_corner_4_7_13181b
} }
) )
@ -90,11 +90,11 @@ class LiveRoomDonationRankingAdapter :
if (items.size == 2) { if (items.size == 2) {
binding.root.setBackgroundResource( binding.root.setBackgroundResource(
R.drawable.bg_bottom_round_corner_4_7_2b2635 R.drawable.bg_bottom_round_corner_4_7_13181b
) )
} else { } else {
binding.root.setBackgroundColor( binding.root.setBackgroundColor(
ContextCompat.getColor(context, R.color.color_2b2635) ContextCompat.getColor(context, R.color.color_13181b)
) )
} }
@ -118,7 +118,7 @@ class LiveRoomDonationRankingAdapter :
binding.ivCrown.setImageResource(R.drawable.ic_crown_3) binding.ivCrown.setImageResource(R.drawable.ic_crown_3)
binding.ivCrown.visibility = View.VISIBLE binding.ivCrown.visibility = View.VISIBLE
binding.root.setBackgroundResource( binding.root.setBackgroundResource(
R.drawable.bg_bottom_round_corner_4_7_2b2635 R.drawable.bg_bottom_round_corner_4_7_13181b
) )
lp.setMargins( lp.setMargins(

View File

@ -15,6 +15,7 @@ class LiveRoomProfileAdapter(
private val isStaff: () -> Boolean, private val isStaff: () -> Boolean,
private val onClickInviteSpeaker: (Long) -> Unit, private val onClickInviteSpeaker: (Long) -> Unit,
private val onClickChangeListener: (Long) -> Unit, private val onClickChangeListener: (Long) -> Unit,
private val onClickNoChatting: (Long, String, String) -> Unit,
private val kickOut: (Long) -> Unit, private val kickOut: (Long) -> Unit,
private val onClickProfile: (Long) -> Unit private val onClickProfile: (Long) -> Unit
) : RecyclerView.Adapter<LiveRoomProfileViewHolder>() { ) : RecyclerView.Adapter<LiveRoomProfileViewHolder>() {
@ -164,6 +165,7 @@ class LiveRoomProfileAdapter(
managerId = managerId, managerId = managerId,
onClickInviteSpeaker = onClickInviteSpeaker, onClickInviteSpeaker = onClickInviteSpeaker,
onClickChangeListener = onClickChangeListener, onClickChangeListener = onClickChangeListener,
onClickNoChatting = onClickNoChatting,
kickOut = kickOut, kickOut = kickOut,
onClickProfile = onClickProfile onClickProfile = onClickProfile
) )
@ -233,6 +235,7 @@ class LiveRoomProfileUserViewHolder(
private val managerId: Long, private val managerId: Long,
private val onClickInviteSpeaker: (Long) -> Unit, private val onClickInviteSpeaker: (Long) -> Unit,
private val onClickChangeListener: (Long) -> Unit, private val onClickChangeListener: (Long) -> Unit,
private val onClickNoChatting: (Long, String, String) -> Unit,
private val kickOut: (Long) -> Unit, private val kickOut: (Long) -> Unit,
private val onClickProfile: (Long) -> Unit private val onClickProfile: (Long) -> Unit
) : LiveRoomProfileViewHolder(binding) { ) : LiveRoomProfileViewHolder(binding) {
@ -241,6 +244,7 @@ class LiveRoomProfileUserViewHolder(
item.managerId = managerId item.managerId = managerId
item.onClickInviteSpeaker = onClickInviteSpeaker item.onClickInviteSpeaker = onClickInviteSpeaker
item.onClickChangeListener = onClickChangeListener item.onClickChangeListener = onClickChangeListener
item.onClickNoChatting = onClickNoChatting
item.kickOut = kickOut item.kickOut = kickOut
item.onClickProfile = onClickProfile item.onClickProfile = onClickProfile
item.bind(binding) item.bind(binding)

View File

@ -17,6 +17,7 @@ class LiveRoomProfileDialog(
onClickInviteSpeaker: (Long) -> Unit, onClickInviteSpeaker: (Long) -> Unit,
onClickChangeListener: (Long) -> Unit, onClickChangeListener: (Long) -> Unit,
onClickKickOut: (Long) -> Unit, onClickKickOut: (Long) -> Unit,
onClickNoChatting: (Long, String, String) -> Unit,
onClickProfile: (Long) -> Unit onClickProfile: (Long) -> Unit
) { ) {
private val bottomSheetDialog: BottomSheetDialog = BottomSheetDialog(activity) private val bottomSheetDialog: BottomSheetDialog = BottomSheetDialog(activity)
@ -25,6 +26,7 @@ class LiveRoomProfileDialog(
isStaff = isStaff, isStaff = isStaff,
onClickInviteSpeaker = onClickInviteSpeaker, onClickInviteSpeaker = onClickInviteSpeaker,
onClickChangeListener = onClickChangeListener, onClickChangeListener = onClickChangeListener,
onClickNoChatting = onClickNoChatting,
kickOut = onClickKickOut, kickOut = onClickKickOut,
onClickProfile = onClickProfile onClickProfile = onClickProfile
) )

View File

@ -42,6 +42,7 @@ abstract class LiveRoomProfileItem {
open var managerId = 0L open var managerId = 0L
open var onClickInviteSpeaker: (Long) -> Unit = {} open var onClickInviteSpeaker: (Long) -> Unit = {}
open var onClickChangeListener: (Long) -> Unit = {} open var onClickChangeListener: (Long) -> Unit = {}
open var onClickNoChatting: (Long, String, String) -> Unit = { _, _, _ -> }
open var kickOut: (Long) -> Unit = {} open var kickOut: (Long) -> Unit = {}
open var onClickProfile: (Long) -> Unit = {} open var onClickProfile: (Long) -> Unit = {}
abstract fun bind(binding: ViewBinding) abstract fun bind(binding: ViewBinding)
@ -197,5 +198,18 @@ data class LiveRoomProfileItemUser(
} else { } else {
itemBinding.llControlButtons.visibility = View.GONE itemBinding.llControlButtons.visibility = View.GONE
} }
if (managerId == SharedPreferenceManager.userId) {
itemBinding.tvNoChatting.visibility = View.VISIBLE
itemBinding.tvNoChatting.setOnClickListener {
onClickNoChatting(
id,
nickname,
profileUrl
)
}
} else {
itemBinding.tvNoChatting.visibility = View.GONE
}
} }
} }

View File

@ -28,6 +28,7 @@ class LiveRoomUserProfileDialog(
private val onClickInviteSpeaker: (Long) -> Unit, private val onClickInviteSpeaker: (Long) -> Unit,
private val onClickChangeListener: (Long) -> Unit, private val onClickChangeListener: (Long) -> Unit,
private val onClickKickOut: (Long) -> Unit, private val onClickKickOut: (Long) -> Unit,
private val onClickNoChatting: (Long, String, String) -> Unit,
private val onClickPopupMenu: (Long, String, Boolean, View) -> Unit, private val onClickPopupMenu: (Long, String, Boolean, View) -> Unit,
) { ) {
private val alertDialog: AlertDialog private val alertDialog: AlertDialog
@ -128,6 +129,7 @@ class LiveRoomUserProfileDialog(
if (userProfile.isManager != null) { if (userProfile.isManager != null) {
dialogView.tvSetManager.visibility = View.VISIBLE dialogView.tvSetManager.visibility = View.VISIBLE
dialogView.tvNoChatting.visibility = View.VISIBLE
if (userProfile.isManager) { if (userProfile.isManager) {
dialogView.tvSetManager.text = "스탭 해제" dialogView.tvSetManager.text = "스탭 해제"
@ -142,8 +144,17 @@ class LiveRoomUserProfileDialog(
alertDialog.dismiss() alertDialog.dismiss()
} }
} }
dialogView.tvNoChatting.setOnClickListener {
onClickNoChatting(
userProfile.userId,
userProfile.nickname,
userProfile.profileUrl
)
}
} else { } else {
dialogView.tvSetManager.visibility = View.GONE dialogView.tvSetManager.visibility = View.GONE
dialogView.tvNoChatting.visibility = View.GONE
} }
if ( if (

View File

@ -19,6 +19,8 @@ import com.google.firebase.messaging.FirebaseMessaging
import com.gun0912.tedpermission.PermissionListener import com.gun0912.tedpermission.PermissionListener
import com.gun0912.tedpermission.normal.TedPermission import com.gun0912.tedpermission.normal.TedPermission
import com.orhanobut.logger.Logger import com.orhanobut.logger.Logger
import kr.co.pointclick.sdk.offerwall.core.PointClickAd
import kr.co.pointclick.sdk.offerwall.core.events.PackageReceiver
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService import kr.co.vividnext.sodalive.audio_content.AudioContentPlayService
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailActivity
@ -50,6 +52,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private val audioContentReceiver = AudioContentReceiver() private val audioContentReceiver = AudioContentReceiver()
private var packageReceiver: PackageReceiver? = null
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent) super.onNewIntent(intent)
executeDeeplink() executeDeeplink()
@ -63,6 +67,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
getMemberInfo() getMemberInfo()
getEventPopup() getEventPopup()
initPointClick()
handler.postDelayed({ executeDeeplink() }, 500) handler.postDelayed({ executeDeeplink() }, 500)
} }
@ -79,8 +84,15 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
} }
override fun onPause() { override fun onPause() {
super.onPause()
unregisterReceiver(audioContentReceiver) unregisterReceiver(audioContentReceiver)
super.onPause()
}
override fun onDestroy() {
if (packageReceiver != null) {
applicationContext.unregisterReceiver(packageReceiver)
}
super.onDestroy()
} }
override fun setupView() { override fun setupView() {
@ -362,6 +374,25 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
} }
} }
private fun initPointClick() {
try {
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
packageReceiver = PackageReceiver()
applicationContext.registerReceiver(packageReceiver, intentFilter)
} catch (e: Exception) {
e.printStackTrace()
}
PointClickAd.init(
"fc07cfb1-ef16-455c-bdad-22aa9e8fd78c",
SharedPreferenceManager.userId.toString()
)
}
inner class AudioContentReceiver : BroadcastReceiver() { inner class AudioContentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0) val contentId = intent?.getLongExtra(Constants.EXTRA_AUDIO_CONTENT_ID, 0)

View File

@ -113,17 +113,7 @@ class MainViewModel(
val playbackTrackingList = playbackTrackingRepository.getAllPlaybackTracking() val playbackTrackingList = playbackTrackingRepository.getAllPlaybackTracking()
val trackingDataList = playbackTrackingList val trackingDataList = playbackTrackingList
.filter { it.endPosition != null } .filter { it.endPosition != null }
.filter { .filter { it.endPosition!! - it.startPosition >= 12000 }
if (it.isFree) {
// 무료 콘텐츠의 경우
// 러닝타임의 30% 이상 재생된 데이터
it.endPosition!! - it.startPosition > it.totalDuration * 0.3
} else {
// 유료 콘텐츠의 경우
// 러닝타임의 20% 이상 재생된 데이터
it.endPosition!! - it.startPosition > it.totalDuration * 0.2
}
}
.map { .map {
PlaybackTrackingData(it.contentId, it.playDateTime, it.isPreview) PlaybackTrackingData(it.contentId, it.playDateTime, it.isPreview)
} }

View File

@ -27,7 +27,7 @@ class TextMessageViewModel(private val repository: MessageRepository) : BaseView
var page = 1 var page = 1
var pageSize = 10 var pageSize = 10
private var totalCount = 0 private var isLast = false
private var _isLoading = MutableLiveData(false) private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean> val isLoading: LiveData<Boolean>
@ -35,6 +35,7 @@ class TextMessageViewModel(private val repository: MessageRepository) : BaseView
fun selectMessageBox(messageBox: MessageBox) { fun selectMessageBox(messageBox: MessageBox) {
if (messageBox != _messageBoxLiveData.value!!) { if (messageBox != _messageBoxLiveData.value!!) {
isLast = false
page = 1 page = 1
_messageBoxLiveData.postValue(messageBox) _messageBoxLiveData.postValue(messageBox)
getMessages(messageBox) getMessages(messageBox)
@ -42,7 +43,7 @@ class TextMessageViewModel(private val repository: MessageRepository) : BaseView
} }
fun getMessages(messageBox: MessageBox = _messageBoxLiveData.value!!) { fun getMessages(messageBox: MessageBox = _messageBoxLiveData.value!!) {
if (!_isLoading.value!! && (page - 1 == 0 || totalCount > page * pageSize)) { if (!_isLoading.value!! && !isLast) {
_isLoading.postValue(true) _isLoading.postValue(true)
val messageBoxObservable = when (messageBox) { val messageBoxObservable = when (messageBox) {
@ -78,10 +79,13 @@ class TextMessageViewModel(private val repository: MessageRepository) : BaseView
.subscribe( .subscribe(
{ {
if (it.success && it.data != null) { if (it.success && it.data != null) {
totalCount = it.data.totalCount
_getMessagesLiveData.postValue(it.data.items)
page += 1 page += 1
if (it.data.items.isNotEmpty()) {
_getMessagesLiveData.postValue(it.data.items)
} else {
isLast = true
_getMessagesLiveData.postValue(listOf())
}
} else { } else {
if (it.message != null) { if (it.message != null) {
_toastLiveData.postValue(it.message) _toastLiveData.postValue(it.message)

View File

@ -27,7 +27,7 @@ class VoiceMessageViewModel(private val repository: MessageRepository) : BaseVie
var page = 1 var page = 1
var pageSize = 10 var pageSize = 10
private var totalCount = 0 private var isLast = false
private var _isLoading = MutableLiveData(false) private var _isLoading = MutableLiveData(false)
val isLoading: LiveData<Boolean> val isLoading: LiveData<Boolean>
@ -35,6 +35,7 @@ class VoiceMessageViewModel(private val repository: MessageRepository) : BaseVie
fun selectMessageBox(messageBox: MessageBox) { fun selectMessageBox(messageBox: MessageBox) {
if (messageBox != _messageBoxLiveData.value!!) { if (messageBox != _messageBoxLiveData.value!!) {
isLast = false
page = 1 page = 1
_messageBoxLiveData.postValue(messageBox) _messageBoxLiveData.postValue(messageBox)
getMessages(messageBox) getMessages(messageBox)
@ -42,7 +43,7 @@ class VoiceMessageViewModel(private val repository: MessageRepository) : BaseVie
} }
fun getMessages(messageBox: MessageBox = _messageBoxLiveData.value!!) { fun getMessages(messageBox: MessageBox = _messageBoxLiveData.value!!) {
if (!_isLoading.value!! && (page - 1 == 0 || totalCount > page * pageSize)) { if (!_isLoading.value!! && !isLast) {
_isLoading.postValue(true) _isLoading.postValue(true)
val messageBoxObservable = when (messageBox) { val messageBoxObservable = when (messageBox) {
MessageBox.SENT -> { MessageBox.SENT -> {
@ -77,10 +78,13 @@ class VoiceMessageViewModel(private val repository: MessageRepository) : BaseVie
.subscribe( .subscribe(
{ {
if (it.success && it.data != null) { if (it.success && it.data != null) {
totalCount = it.data.totalCount
_getMessagesLiveData.postValue(it.data.items)
page += 1 page += 1
if (it.data.items.isNotEmpty()) {
_getMessagesLiveData.postValue(it.data.items)
} else {
isLast = true
_getMessagesLiveData.postValue(listOf())
}
} else { } else {
if (it.message != null) { if (it.message != null) {
_toastLiveData.postValue(it.message) _toastLiveData.postValue(it.message)

View File

@ -32,7 +32,7 @@ class CanPaymentActivity : BaseActivity<ActivityCanPaymentBinding>(
ActivityCanPaymentBinding::inflate ActivityCanPaymentBinding::inflate
) { ) {
enum class PaymentMethod(val method: String) { enum class PaymentMethod(val method: String) {
CARD("디지털카드"), BANK("디지털계좌이체") CARD("디지털카드"), BANK("디지털계좌이체"), PHONE("휴대폰")
} }
private val viewModel: CanPaymentViewModel by inject() private val viewModel: CanPaymentViewModel by inject()
@ -103,6 +103,7 @@ class CanPaymentActivity : BaseActivity<ActivityCanPaymentBinding>(
binding.tvMethodCard.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.CARD) } binding.tvMethodCard.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.CARD) }
binding.tvMethodBank.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.BANK) } binding.tvMethodBank.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.BANK) }
binding.tvMethodPhone.setOnClickListener { viewModel.setPaymentMethod(PaymentMethod.PHONE) }
viewModel.paymentMethodLiveData.observe(this) { viewModel.paymentMethodLiveData.observe(this) {
allPaymentMethodSelectFalse() allPaymentMethodSelectFalse()
@ -111,6 +112,7 @@ class CanPaymentActivity : BaseActivity<ActivityCanPaymentBinding>(
when (it) { when (it) {
PaymentMethod.CARD -> paymentMethodSelect(binding.tvMethodCard) PaymentMethod.CARD -> paymentMethodSelect(binding.tvMethodCard)
PaymentMethod.BANK -> paymentMethodSelect(binding.tvMethodBank) PaymentMethod.BANK -> paymentMethodSelect(binding.tvMethodBank)
PaymentMethod.PHONE -> paymentMethodSelect(binding.tvMethodPhone)
} }
} }
} }
@ -119,6 +121,7 @@ class CanPaymentActivity : BaseActivity<ActivityCanPaymentBinding>(
private fun allPaymentMethodSelectFalse() { private fun allPaymentMethodSelectFalse() {
paymentMethodSelectFalse(binding.tvMethodBank) paymentMethodSelectFalse(binding.tvMethodBank)
paymentMethodSelectFalse(binding.tvMethodCard) paymentMethodSelectFalse(binding.tvMethodCard)
paymentMethodSelectFalse(binding.tvMethodPhone)
} }
private fun paymentMethodSelectFalse(view: TextView) { private fun paymentMethodSelectFalse(view: TextView) {

View File

@ -6,6 +6,7 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import kr.co.pointclick.sdk.offerwall.core.PointClickAd
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
@ -41,7 +42,7 @@ class CanStatusActivity : BaseActivity<ActivityCanStatusBinding>(
override fun setupView() { override fun setupView() {
binding.toolbar.tvBack.text = "캔내역" binding.toolbar.tvBack.text = "캔내역"
binding.toolbar.tvBack.setOnClickListener { onClickBackButton() } binding.toolbar.tvBack.setOnClickListener { onClickBackButton() }
binding.llChargeCan.setOnClickListener { binding.flChargeCan.setOnClickListener {
startActivity( startActivity(
Intent( Intent(
applicationContext, applicationContext,
@ -49,6 +50,9 @@ class CanStatusActivity : BaseActivity<ActivityCanStatusBinding>(
) )
) )
} }
binding.tvFreeChargeCan.setOnClickListener {
PointClickAd.showOfferwall(this, "무료충전")
}
loadingDialog = LoadingDialog(this, layoutInflater) loadingDialog = LoadingDialog(this, layoutInflater)

View File

@ -16,5 +16,6 @@ data class ProfileUpdateRequest(
@SerializedName("instagramUrl") val instagramUrl: String? = null, @SerializedName("instagramUrl") val instagramUrl: String? = null,
@SerializedName("websiteUrl") val websiteUrl: String? = null, @SerializedName("websiteUrl") val websiteUrl: String? = null,
@SerializedName("blogUrl") val blogUrl: String? = null, @SerializedName("blogUrl") val blogUrl: String? = null,
@SerializedName("isVisibleDonationRank") val isVisibleDonationRank: Boolean? = null,
@SerializedName("container") val container: String = "aos" @SerializedName("container") val container: String = "aos"
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 B

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_2b2635" /> <solid android:color="@color/color_13181b" />
<corners <corners
android:bottomLeftRadius="4.7dp" android:bottomLeftRadius="4.7dp"
android:bottomRightRadius="4.7dp" /> android:bottomRightRadius="4.7dp" />
<stroke <stroke
android:width="1dp" android:width="1dp"
android:color="@color/color_2b2635" /> android:color="@color/color_13181b" />
</shape> </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_2e6279" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_2e6279" />
</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_b1ef2c" />
<corners android:radius="10dp" />
<stroke
android:width="1dp"
android:color="@color/color_b1ef2c" />
</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_cf5c37" />
<corners android:radius="2.6dp" />
<stroke
android:width="1dp"
android:color="@color/color_cf5c37" />
</shape>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_2b2635" /> <solid android:color="@color/color_13181b" />
<corners android:radius="4.7dp" /> <corners android:radius="4.7dp" />
<stroke <stroke
android:width="1dp" android:width="1dp"
android:color="@color/color_2b2635" /> android:color="@color/color_13181b" />
</shape> </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_3bb9f1" />
<corners android:radius="4.7dp" />
<stroke
android:width="1dp"
android:color="@color/color_3bb9f1" />
</shape>

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_2b2635" /> <solid android:color="@color/color_13181b" />
<corners android:radius="8dp" /> <corners android:radius="8dp" />
<stroke <stroke
android:width="1dp" android:width="1dp"
android:color="@color/color_2b2635" /> android:color="@color/color_13181b" />
</shape> </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="8dp" />
<stroke
android:width="1dp"
android:color="@color/color_3bb9f1" />
</shape>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_2b2635" /> <solid android:color="@color/color_13181b" />
<corners <corners
android:topLeftRadius="4.7dp" android:topLeftRadius="4.7dp"
android:topRightRadius="4.7dp" /> android:topRightRadius="4.7dp" />
<stroke <stroke
android:width="1dp" android:width="1dp"
android:color="@color/color_2b2635" /> android:color="@color/color_13181b" />
</shape> </shape>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/color_9970ff" /> <solid android:color="@color/color_3bb9f1" />
<size android:width="1.5dp" /> <size android:width="1.5dp" />
</shape> </shape>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@color/color_161616"
android:gravity="end"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:paddingVertical="13.3dp">
<TextView
android:id="@+id/tv_sort_newest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="최신순"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
<TextView
android:id="@+id/tv_sort_price_high"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="높은 가격순"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
<TextView
android:id="@+id/tv_sort_price_low"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="낮은 가격순"
android:textColor="@color/color_88e2e2e2"
android:textSize="13.3sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:paddingVertical="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="전체"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
<TextView
android:id="@+id/tv_total_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="0"
android:textColor="@color/color_ff5c49"
android:textSize="13.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="개"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_curation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</LinearLayout>

View File

@ -115,7 +115,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:contentDescription="@null" android:contentDescription="@null"
android:src="@drawable/btn_audio_content_play" /> tools:src="@drawable/btn_audio_content_play" />
<SeekBar <SeekBar
android:id="@+id/sb_progress" android:id="@+id/sb_progress"
@ -430,6 +430,7 @@
android:textSize="12sp" /> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/tv_str_purchase_or_rental"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold" android:fontFamily="@font/gmarket_sans_bold"
@ -536,12 +537,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="6.7dp"
android:layout_marginTop="26.7dp"
android:background="@color/color_232323" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -568,7 +563,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="21.3dp" android:layout_marginTop="21.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635" android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:paddingVertical="13.3dp" android:paddingVertical="13.3dp"
@ -624,7 +619,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="21.3dp" android:layout_marginTop="21.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635" android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:paddingVertical="13.3dp" android:paddingVertical="13.3dp"

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@color/color_222222"
android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="13.3dp"
android:paddingVertical="8dp"
android:text="※ 최근 2주간 등록된 새로운 콘텐츠 입니다."
android:textSize="14.67sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_new_content_theme"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="13.3dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="13.3dp"
android:orientation="horizontal"
android:paddingHorizontal="20dp"
android:paddingVertical="13.3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="전체"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
<TextView
android:id="@+id/tv_total_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="0"
android:textColor="@color/color_ff5c49"
android:textSize="13.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="개"
android:textColor="@color/color_e2e2e2"
android:textSize="13.3sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</LinearLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/black" android:background="@color/black"
@ -9,9 +10,44 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
layout="@layout/detail_toolbar" /> layout="@layout/detail_toolbar" />
<LinearLayout
android:id="@+id/ll_total_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:gravity="center_vertical"
android:orientation="horizontal"
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="12sp" />
<TextView
android:id="@+id/tv_total_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_dd4500"
android:textSize="12sp"
tools:text=" 10" />
<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="12sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_order_list" android:id="@+id/rv_order_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
android:layout_marginTop="13.3dp" />
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/detail_toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@color/color_222222"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="8dp">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_light"
android:text="※ 인기 콘텐츠의 순위는 매주 업데이트됩니다."
android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingHorizontal="6.7dp"
android:paddingVertical="13.3dp" />
</LinearLayout>

View File

@ -366,6 +366,84 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tv_title_config_keep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="26.7dp"
android:fontFamily="@font/gmarket_sans_bold"
android:lineSpacingExtra="5sp"
android:text="소장 설정"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<LinearLayout
android:id="@+id/ll_config_keep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp"
android:baselineAligned="false">
<LinearLayout
android:id="@+id/ll_rental_and_keep"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_1f1734"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_rental_and_keep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_rental_and_keep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="소장/대여"
android:textColor="@color/color_9970ff"
android:textSize="14.7sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_only_rental"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_6_7_1f1734"
android:gravity="center"
android:paddingVertical="14.3dp">
<ImageView
android:id="@+id/iv_only_rental"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6.7dp"
android:contentDescription="@null"
android:src="@drawable/ic_select_check"
android:visibility="gone" />
<TextView
android:id="@+id/tv_only_rental"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="대여만"
android:textColor="@color/color_9970ff"
android:textSize="14.7sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/ll_set_price" android:id="@+id/ll_set_price"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -376,10 +454,11 @@
android:visibility="visible"> android:visibility="visible">
<TextView <TextView
android:id="@+id/tv_price_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:text="소장가격" android:text="소장 가격"
android:textColor="@color/color_eeeeee" android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" /> android:textSize="13.3sp" />
@ -432,7 +511,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:text="※ 이용기간 : 대여(7일) | 소장(서비스종료시까지)" android:text="※ 이용기간 : 대여(15일) | 소장(서비스종료시까지)"
android:textColor="@color/color_777777" android:textColor="@color/color_777777"
android:textSize="13.3sp" /> android:textSize="13.3sp" />
@ -628,6 +707,111 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/ll_config_preview_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="30dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:lineSpacingExtra="5sp"
android:text="미리듣기 시간 설정"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="미리듣기 시간을 직접 설정하지 않으면 콘텐츠 앞부분 30초가 자동으로 설정됩니다. 미리듣기의 시간제한은 없습니다."
android:textColor="@color/color_777777"
android:textSize="13.3sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="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="13.3sp" />
<EditText
android:id="@+id/et_preview_start_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:hint="00:00:00"
android:importantForAutofill="no"
android:inputType="textWebEditText"
android:paddingHorizontal="13.3dp"
android:paddingVertical="17dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="14.7sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="13.3dp"
android:layout_weight="1"
android:orientation="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="13.3sp" />
<EditText
android:id="@+id/et_preview_end_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5.3dp"
android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:hint="00:30:00"
android:importantForAutofill="no"
android:inputType="textWebEditText"
android:paddingHorizontal="13.3dp"
android:paddingVertical="17dp"
android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777"
android:textCursorDrawable="@drawable/edit_text_cursor"
android:textSize="14.7sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -130,6 +130,31 @@
android:textSize="13.3sp" /> android:textSize="13.3sp" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="16.7dp">
<TextView
android:id="@+id/tv_method_phone"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_232323_777777"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:paddingVertical="16.7dp"
android:text="휴대폰 결제"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<TextView <TextView
android:id="@+id/tv_agree" android:id="@+id/tv_agree"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -13,7 +13,7 @@
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_above="@+id/fl_charge_can" android:layout_above="@+id/ll_charge_can"
android:layout_below="@+id/toolbar"> android:layout_below="@+id/toolbar">
<LinearLayout <LinearLayout
@ -165,39 +165,50 @@
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
<FrameLayout <LinearLayout
android:id="@+id/fl_charge_can" android:id="@+id/ll_charge_can"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:background="@drawable/bg_top_round_corner_16_7_222222"> android:background="@drawable/bg_top_round_corner_16_7_222222"
android:paddingHorizontal="13.3dp">
<LinearLayout <TextView
android:id="@+id/ll_charge_can" android:id="@+id/tv_free_charge_can"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_gravity="center"
android:layout_marginVertical="13.7dp" android:layout_marginEnd="8dp"
android:background="@drawable/bg_round_corner_10_80d8ff" android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_b1ef2c"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center" android:gravity="center"
android:paddingVertical="16dp"> android:paddingVertical="16dp"
android:text="무료충전"
android:textColor="@color/black"
android:textSize="18.3sp" />
<ImageView <FrameLayout
android:layout_width="wrap_content" android:id="@+id/fl_charge_can"
android:layout_height="wrap_content" android:layout_width="0dp"
android:contentDescription="@null" android:layout_height="wrap_content"
android:src="@drawable/ic_can" /> android:layout_marginVertical="13.7dp"
android:layout_weight="2"
android:background="@drawable/bg_round_corner_10_80d8ff"
android:paddingVertical="16dp">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6.7dp" android:layout_gravity="center"
android:drawablePadding="6.7dp"
android:fontFamily="@font/gmarket_sans_bold" android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center" android:gravity="center"
android:text="충전하기" android:text="충전하기"
android:textColor="@color/color_1313bc" android:textColor="@color/color_1313bc"
android:textSize="18.3sp" /> android:textSize="18.3sp"
</LinearLayout> app:drawableStartCompat="@drawable/ic_can" />
</FrameLayout> </FrameLayout>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -57,5 +57,4 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_total_count" /> app:layout_constraintTop_toBottomOf="@+id/ll_total_count" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -46,7 +46,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="28.3dp" android:layout_marginTop="28.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635" android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:paddingVertical="16.7dp" android:paddingVertical="16.7dp"

View File

@ -172,7 +172,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="5.3dp" android:layout_marginStart="5.3dp"
android:layout_toStartOf="@+id/iv_creator_follow"
android:layout_toEndOf="@+id/iv_creator_profile" android:layout_toEndOf="@+id/iv_creator_profile"
android:drawablePadding="5.3dp" android:drawablePadding="5.3dp"
android:ellipsize="end" android:ellipsize="end"
@ -187,8 +186,9 @@
android:id="@+id/iv_creator_follow" android:id="@+id/iv_creator_follow"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="13.3dp"
android:layout_toEndOf="@+id/tv_creator_nickname"
android:contentDescription="@null" android:contentDescription="@null"
tools:src="@drawable/btn_following" /> tools:src="@drawable/btn_following" />
</RelativeLayout> </RelativeLayout>
@ -215,63 +215,68 @@
android:src="@drawable/ic_notice_normal" /> android:src="@drawable/ic_notice_normal" />
<LinearLayout <LinearLayout
android:id="@+id/ll_donation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_toStartOf="@+id/ll_view_users"
android:background="@drawable/bg_round_corner_15_transparent_bbbbbb"
android:gravity="center"
android:paddingHorizontal="10dp"
android:paddingVertical="5.3dp"
tools:ignore="RelativeOverlap">
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_can" />
<TextView
android:id="@+id/tv_total_can"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:gravity="center_vertical"
android:textColor="@color/color_bbbbbb"
tools:text="999,999,999,999" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_view_users"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:orientation="horizontal">
android:background="@drawable/bg_round_corner_15_transparent_bbbbbb"
android:orientation="horizontal"
android:paddingHorizontal="11dp"
android:paddingVertical="7dp"
tools:ignore="RelativeOverlap">
<TextView <LinearLayout
android:id="@+id/ll_donation"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium" android:background="@drawable/bg_round_corner_15_transparent_bbbbbb"
android:text="참여자" android:gravity="center"
android:textColor="@color/color_eeeeee" android:paddingHorizontal="10dp"
android:textSize="12sp" /> android:paddingVertical="5.3dp"
tools:ignore="RelativeOverlap">
<TextView <ImageView
android:id="@+id/tv_participate" android:layout_width="16dp"
android:layout_height="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_can" />
<TextView
android:id="@+id/tv_total_can"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6.7dp"
android:gravity="center_vertical"
android:textColor="@color/color_bbbbbb"
tools:text="999,999,999,999" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_view_users"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6.7dp" android:background="@drawable/bg_round_corner_15_transparent_bbbbbb"
android:fontFamily="@font/gmarket_sans_medium" android:orientation="horizontal"
android:textColor="@color/color_9970ff" android:paddingHorizontal="11dp"
android:textSize="12sp" android:visibility="gone"
tools:ignore="RelativeOverlap" android:paddingVertical="7dp"
tools:text="18" /> android:layout_marginStart="8dp"
tools:ignore="RelativeOverlap">
<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="12sp" />
<TextView
android:id="@+id/tv_participate"
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:ignore="RelativeOverlap"
tools:text="18" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -243,7 +243,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="46.7dp" android:layout_marginTop="26.7dp"
android:visibility="gone" /> android:visibility="gone" />
<include <include
@ -252,7 +252,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="46.7dp" android:layout_marginTop="26.7dp"
android:visibility="gone" /> android:visibility="gone" />
<include <include

View File

@ -3,21 +3,65 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/black"
android:orientation="vertical"> android:orientation="vertical">
<include <include
android:id="@+id/toolbar" android:id="@+id/toolbar"
layout="@layout/detail_toolbar" /> layout="@layout/detail_toolbar" />
<LinearLayout
android:id="@+id/ll_visible_donation_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="5.3dp"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<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="16sp" />
<ImageView
android:id="@+id/iv_visible_donation_rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:contentDescription="@null"
tools:src="@drawable/btn_toggle_on_big" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="end"
android:text="※ 비활성화하면 채널 내 후원랭킹이 표시되지 않으며,\n라이브 중에도 후원랭킹에 따른 뱃지가 반영되지 않습니다."
android:textColor="@color/color_555555"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/ll_total" android:id="@+id/ll_total"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="13.3dp" android:layout_margin="13.3dp"
android:background="@drawable/bg_round_corner_8_2b2635" android:background="@drawable/bg_round_corner_8_13181b"
android:orientation="vertical" android:orientation="vertical"
android:paddingHorizontal="16.7dp" android:padding="16.7dp"
android:paddingVertical="13.3dp"
android:visibility="gone"> android:visibility="gone">
<RelativeLayout <RelativeLayout
@ -143,7 +187,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6.7dp" android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff" android:textColor="@color/color_80d8ff"
android:textSize="12sp" android:textSize="12sp"
tools:text="56" /> tools:text="56" />
@ -162,7 +206,7 @@
android:layout_height="1dp" android:layout_height="1dp"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="6.7dp" android:layout_marginTop="6.7dp"
android:background="@color/color_88909090" /> android:background="@color/color_595959" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout" android:id="@+id/swipe_refresh_layout"

View File

@ -0,0 +1,105 @@
<?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_gravity="center"
android:background="@drawable/bg_round_corner_10_222222">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:text="채팅금지"
android:textColor="@color/color_bbbbbb"
android:textSize="18.3sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/ll_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="26.7dp"
android:layout_height="26.7dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:textColor="@color/color_bbbbbb"
android:textSize="16.7sp"
tools:text="델1002" />
</LinearLayout>
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="21dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:text="3분간 채팅금지를 하겠습니까?"
android:textColor="@color/color_bbbbbb"
android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ll_profile" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16.7dp"
android:layout_marginTop="21dp"
android:layout_marginBottom="16.7dp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_desc">
<TextView
android:id="@+id/tv_cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="13.3dp"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_339970ff_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="취소"
android:textColor="@color/color_9970ff"
android:textSize="18.3sp" />
<TextView
android:id="@+id/tv_confirm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/bg_round_corner_10_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="16dp"
android:text="확인"
android:textColor="@color/white"
android:textSize="18.3sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -37,7 +37,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="7.7dp" android:layout_marginTop="7.7dp"
android:background="@drawable/bg_round_corner_8_2b2635" android:background="@drawable/bg_round_corner_8_13181b"
android:paddingHorizontal="18.7dp" android:paddingHorizontal="18.7dp"
android:paddingVertical="10.7dp"> android:paddingVertical="10.7dp">
@ -62,7 +62,7 @@
android:layout_toEndOf="@+id/tv_total_can_title" android:layout_toEndOf="@+id/tv_total_can_title"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:gravity="end" android:gravity="end"
android:textColor="@color/color_9970ff" android:textColor="@color/color_80d8ff"
android:textSize="16sp" android:textSize="16sp"
tools:text="1,999,999" /> tools:text="1,999,999" />
@ -102,7 +102,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="6.7dp" android:layout_marginStart="6.7dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff" android:textColor="@color/color_80d8ff"
android:textSize="12sp" android:textSize="12sp"
tools:text="56" /> tools:text="56" />

View File

@ -215,6 +215,19 @@
android:visibility="gone" /> android:visibility="gone" />
</LinearLayout> </LinearLayout>
<TextView
android:id="@+id/tv_no_chatting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="21.3dp"
android:background="@drawable/bg_round_corner_8_transparent_9970ff"
android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center"
android:paddingVertical="13dp"
android:text="3분간 채팅금지"
android:textColor="@color/color_9970ff"
android:visibility="gone" />
<TextView <TextView
android:id="@+id/tv_tags" android:id="@+id/tv_tags"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -19,15 +19,31 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<TextView <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="26.7dp" android:layout_marginBottom="26.7dp">
android:fontFamily="@font/gmarket_sans_bold"
android:paddingHorizontal="13.3dp" <TextView
android:text="콘텐츠 마켓" android:layout_width="match_parent"
android:textColor="@color/color_9970ff" android:layout_height="wrap_content"
android:textSize="21.3sp" /> android:layout_centerVertical="true"
android:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="콘텐츠 마켓"
android:textColor="@color/color_9970ff"
android:textSize="21.3sp" />
<ImageView
android:id="@+id/iv_can_free"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginHorizontal="13.3dp"
android:contentDescription="@null"
android:src="@drawable/ic_ads_can" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_new_content_creator" android:id="@+id/rv_new_content_creator"
@ -102,14 +118,28 @@
android:orientation="vertical" android:orientation="vertical"
android:visibility="gone"> android:visibility="gone">
<TextView <RelativeLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:fontFamily="@font/gmarket_sans_bold"
android:paddingHorizontal="13.3dp" <TextView
android:text="새로운 콘텐츠" android:layout_width="wrap_content"
android:textColor="@color/color_eeeeee" android:layout_height="wrap_content"
android:textSize="18.3sp" /> android:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="새로운 콘텐츠"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<ImageView
android:id="@+id/iv_new_content_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:contentDescription="@null"
android:paddingHorizontal="13.3dp"
android:src="@drawable/ic_forward" />
</RelativeLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_new_content_theme" android:id="@+id/rv_new_content_theme"
@ -128,6 +158,73 @@
android:paddingHorizontal="13.3dp" /> android:paddingHorizontal="13.3dp" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/ll_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:orientation="vertical"
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:layout_marginStart="13.3dp"
android:fontFamily="@font/gmarket_sans_bold"
android:text="인기 콘텐츠"
android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" />
<ImageView
android:id="@+id/iv_content_ranking_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:contentDescription="@null"
android:paddingHorizontal="13.3dp"
android:src="@drawable/ic_forward" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:background="@color/color_222222"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="8dp">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_eeeeee"
android:textSize="14.7sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_light"
android:text="※ 인기 콘텐츠의 순위는 매주 업데이트됩니다."
android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_content_ranking"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="13.3dp"
android:clipToPadding="false"
android:paddingHorizontal="6.7dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_curation" android:id="@+id/rv_curation"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -28,7 +28,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_light" android:fontFamily="@font/gmarket_sans_light"
android:text="(이용기간 7일)" android:text="(이용기간 15일)"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="12sp" /> android:textSize="12sp" />
</LinearLayout> </LinearLayout>
@ -64,9 +64,11 @@
</RelativeLayout> </RelativeLayout>
<RelativeLayout <RelativeLayout
android:id="@+id/rl_keep"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="26.7dp"> android:layout_marginTop="26.7dp"
android:visibility="gone">
<LinearLayout <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -24,15 +24,15 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="13.3dp" /> android:layout_marginTop="13.3dp"
android:layout_marginBottom="40dp" />
<include <include
android:id="@+id/layout_recommend_channel" android:id="@+id/layout_recommend_channel"
layout="@layout/layout_live_recommend_channel" layout="@layout/layout_live_recommend_channel"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp" android:layout_marginHorizontal="13.3dp" />
android:layout_marginTop="40dp" />
<include <include
android:id="@+id/layout_live_now" android:id="@+id/layout_live_now"

View File

@ -73,7 +73,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_margin="13.3dp" android:layout_margin="13.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635" android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:visibility="gone" android:visibility="gone"

View File

@ -72,7 +72,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_margin="13.3dp" android:layout_margin="13.3dp"
android:background="@drawable/bg_round_corner_4_7_2b2635" android:background="@drawable/bg_round_corner_4_7_13181b"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:visibility="gone" android:visibility="gone"

View File

@ -12,18 +12,29 @@
android:paddingHorizontal="13.3dp" android:paddingHorizontal="13.3dp"
android:textColor="@color/color_eeeeee" android:textColor="@color/color_eeeeee"
android:textSize="18.3sp" android:textSize="18.3sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toStartOf="@+id/iv_all"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="큐레이션" /> tools:text="큐레이션" />
<ImageView
android:id="@+id/iv_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@null"
android:paddingHorizontal="13.3dp"
android:src="@drawable/ic_forward"
app:layout_constraintBottom_toBottomOf="@+id/tv_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tv_title" />
<TextView <TextView
android:id="@+id/tv_desc" android:id="@+id/tv_desc"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:paddingHorizontal="13.3dp" android:paddingHorizontal="13.3dp"
android:layout_marginTop="4dp"
android:textColor="@color/color_777777" android:textColor="@color/color_777777"
android:textSize="13sp" android:textSize="13sp"
app:layout_constraintEnd_toEndOf="@+id/tv_title" app:layout_constraintEnd_toEndOf="@+id/tv_title"
@ -39,8 +50,7 @@
android:layout_marginTop="13.3dp" android:layout_marginTop="13.3dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingHorizontal="13.3dp" android:paddingHorizontal="13.3dp"
app:layout_constraintEnd_toEndOf="@+id/tv_title" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/tv_title" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_desc" /> app:layout_constraintTop_toBottomOf="@+id/tv_desc" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,51 @@
<?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="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_cover"
android:layout_width="60dp"
android:layout_height="60dp"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:fontFamily="@font/gmarket_sans_bold"
android:textColor="@color/color_3bb9f1"
android:textSize="16.7sp"
tools:text="1" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp"
tools:text="라일락 꽃 향기 맡으며" />
<TextView
android:id="@+id/tv_nickname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_777777"
android:textSize="11sp"
tools:text="J Fla" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,57 @@
<?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="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_audio_content_cover_image"
android:layout_width="133.3dp"
android:layout_height="133.3dp"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_audio_content_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:fontFamily="@font/gmarket_sans_medium"
android:maxLines="2"
android:textColor="@color/color_d2d2d2"
android:textSize="13.3sp"
app:layout_constraintEnd_toEndOf="@+id/iv_audio_content_cover_image"
app:layout_constraintStart_toStartOf="@+id/iv_audio_content_cover_image"
app:layout_constraintTop_toBottomOf="@+id/iv_audio_content_cover_image"
tools:text="빛이 나는 사람" />
<ImageView
android:id="@+id/iv_audio_content_creator"
android:layout_width="21.3dp"
android:layout_height="21.3dp"
android:layout_marginTop="8dp"
android:contentDescription="@null"
app:layout_constraintStart_toStartOf="@+id/iv_audio_content_cover_image"
app:layout_constraintTop_toBottomOf="@+id/tv_audio_content_title"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_audio_content_creator_nickname"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="5.3dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:textColor="@color/color_777777"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/iv_audio_content_creator"
app:layout_constraintEnd_toEndOf="@+id/iv_audio_content_cover_image"
app:layout_constraintStart_toEndOf="@+id/iv_audio_content_creator"
app:layout_constraintTop_toTopOf="@+id/iv_audio_content_creator"
tools:ignore="SmallSp"
tools:text="pgwkil" />
</androidx.constraintlayout.widget.ConstraintLayout>

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