Compare commits

...

12 Commits

Author SHA1 Message Date
klaus 66a83a118f 콘텐츠 메인
- 배너 indicator 색상 변경
2024-09-24 14:08:30 +09:00
klaus 3494ff0491 콘텐츠 상세
- 시간표시 슬라이더 색상변경
2024-09-24 14:01:50 +09:00
klaus d51fc88813 콘텐츠 업로드
- 미리듣기 최소 시간 15초로 변경
2024-09-24 13:47:14 +09:00
klaus 1930014498 라이브 비밀후원
- 방장인 경우 비밀후원도 후원 총액에 반영되도록 수정
2024-09-24 12:14:47 +09:00
klaus 4189ee4e54 라이브
- 큰 음소거 이미지 변경
2024-09-20 16:12:13 +09:00
klaus a191e295da 라이브
- 최대 스피커 수 방장 포함 6명으로 변경
2024-09-20 16:10:48 +09:00
klaus 0709c68653 크리에이터 채널
- 공유버튼 변경
2024-09-20 15:34:00 +09:00
klaus 084c306159 시리즈 상세 - 크리에이터 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 12:11:33 +09:00
klaus 2ed77a3332 콘텐츠 상세 - 크리에이터 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 11:44:13 +09:00
klaus 5b2c5a6e2f 팔로잉/팔로워 리스트 - 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-20 01:57:27 +09:00
klaus 5063ce815d 크리에이터 채널 - 팔로우와 알림설정
- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
2024-09-13 16:11:39 +09:00
klaus 78323103fd 라이브 정보 수정
- 연령 제한 설정 추가
2024-09-11 23:26:45 +09:00
48 changed files with 585 additions and 231 deletions

View File

@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-08-26T10:43:24.248064Z"> <DropdownSelection timestamp="2024-09-23T12:14:10.678819Z">
<Target type="DEFAULT_BOOT"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/klaus/.android/avd/Pixel_8_Pro_API_34.avd" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=2cec640c34017ece" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@ -35,8 +35,8 @@ android {
applicationId "kr.co.vividnext.sodalive" applicationId "kr.co.vividnext.sodalive"
minSdk 23 minSdk 23
targetSdk 34 targetSdk 34
versionCode 104 versionCode 108
versionName "1.17.0" versionName "1.19.1"
} }
buildTypes { buildTypes {

View File

@ -42,6 +42,7 @@ import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.common.Utils import kr.co.vividnext.sodalive.common.Utils
import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding import kr.co.vividnext.sodalive.databinding.ActivityAudioContentDetailBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat
@ -843,21 +844,50 @@ class AudioContentDetailActivity : BaseActivity<ActivityAudioContentDetailBindin
if (creator.creatorId != SharedPreferenceManager.userId) { if (creator.creatorId != SharedPreferenceManager.userId) {
binding.ivFollow.visibility = View.VISIBLE binding.ivFollow.visibility = View.VISIBLE
if (creator.isFollowing) { if (creator.isFollow) {
binding.ivFollow.setImageResource(R.drawable.btn_following_big) binding.ivFollow.setImageResource(
if (creator.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
binding.ivFollow.setOnClickListener { binding.ivFollow.setOnClickListener {
viewModel.unRegisterNotification( val notifyFragment = CreatorFollowNotifyFragment(
contentId = audioContentId, onClickNotifyAll = {
creatorId = creator.creatorId viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = true,
notify = true
)
},
onClickNotifyNone = {
viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = true,
notify = false
)
},
onClickUnFollow = {
viewModel.follow(
contentId = audioContentId,
creatorId = creator.creatorId,
follow = false,
notify = false
)
}
) )
if (notifyFragment.isAdded) return@setOnClickListener
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} }
} else { } else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big) binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
binding.ivFollow.setOnClickListener { binding.ivFollow.setOnClickListener {
viewModel.registerNotification( viewModel.follow(contentId = audioContentId, creatorId = creator.creatorId)
contentId = audioContentId,
creatorId = creator.creatorId
)
} }
} }
} else { } else {

View File

@ -25,9 +25,11 @@ import kr.co.vividnext.sodalive.mypage.auth.AuthVerifyRequest
import kr.co.vividnext.sodalive.report.ReportRepository import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType import kr.co.vividnext.sodalive.report.ReportType
import kr.co.vividnext.sodalive.user.UserRepository
class AudioContentDetailViewModel( class AudioContentDetailViewModel(
private val repository: AudioContentRepository, private val repository: AudioContentRepository,
private val userRepository: UserRepository,
private val authRepository: AuthRepository, private val authRepository: AuthRepository,
private val reportRepository: ReportRepository, private val reportRepository: ReportRepository,
private val commentRepository: AudioContentCommentRepository private val commentRepository: AudioContentCommentRepository
@ -102,6 +104,41 @@ class AudioContentDetailViewModel(
) )
} }
fun follow(contentId: Long, creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
isLoading.value = true
compositeDisposable.add(
userRepository.creatorFollow(
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
getAudioContentDetail(contentId)
} 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 registerNotification(contentId: Long, creatorId: Long) { fun registerNotification(contentId: Long, creatorId: Long) {
isLoading.value = true isLoading.value = true
compositeDisposable.add( compositeDisposable.add(

View File

@ -53,5 +53,7 @@ data class AudioContentCreator(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String, @SerializedName("profileImageUrl") val profileImageUrl: String,
@SerializedName("isFollowing") val isFollowing: Boolean @SerializedName("isFollowing") val isFollowing: Boolean,
@SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
) )

View File

@ -277,7 +277,7 @@ class AudioContentMainFragment : BaseFragment<FragmentAudioContentMainBinding>(
.setIndicatorVisibility(View.GONE) .setIndicatorVisibility(View.GONE)
.setIndicatorSliderColor( .setIndicatorSliderColor(
ContextCompat.getColor(requireContext(), R.color.color_909090), ContextCompat.getColor(requireContext(), R.color.color_909090),
ContextCompat.getColor(requireContext(), R.color.color_9970ff) ContextCompat.getColor(requireContext(), R.color.color_3bb9f1)
) )
.setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt()) .setIndicatorSliderWidth(4f.dpToPx().toInt(), 10f.dpToPx().toInt())
.setIndicatorHeight(4f.dpToPx().toInt()) .setIndicatorHeight(4f.dpToPx().toInt())

View File

@ -34,6 +34,7 @@ data class GetSeriesDetailResponse(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileImage") val profileImage: String, @SerializedName("profileImage") val profileImage: String,
@SerializedName("isFollow") var isFollow: Boolean @SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
) : Parcelable ) : Parcelable
} }

View File

@ -20,6 +20,7 @@ import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivitySeriesDetailBinding import kr.co.vividnext.sodalive.databinding.ActivitySeriesDetailBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -170,29 +171,68 @@ class SeriesDetailActivity : BaseActivity<ActivitySeriesDetailBinding>(
if (SharedPreferenceManager.userId != creator.creatorId) { if (SharedPreferenceManager.userId != creator.creatorId) {
binding.ivFollow.visibility = View.VISIBLE binding.ivFollow.visibility = View.VISIBLE
binding.ivFollow.setImageResource(
if (creator.isFollow) { if (creator.isFollow) {
R.drawable.btn_following_big binding.ivFollow.setImageResource(
} else { if (creator.isNotify) {
R.drawable.btn_follow_big R.drawable.btn_following_big
} } else {
) R.drawable.btn_following_no_alarm_big
}
)
} else {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
} else { } else {
binding.ivFollow.visibility = View.GONE binding.ivFollow.visibility = View.GONE
} }
binding.ivFollow.setOnClickListener { binding.ivFollow.setOnClickListener {
if (creator.isFollow) { if (creator.isFollow) {
viewModel.unFollow(creator.creatorId) { val notifyFragment = CreatorFollowNotifyFragment(
creator.isFollow = false onClickNotifyAll = {
binding.ivFollow.setImageResource(R.drawable.btn_follow_big) viewModel.follow(
} creatorId = creator.creatorId,
follow = true,
notify = true
) {
creator.isFollow = true
creator.isNotify = true
binding.ivFollow.setImageResource(R.drawable.btn_following_big)
}
},
onClickNotifyNone = {
viewModel.follow(
creatorId = creator.creatorId,
follow = true,
notify = false
) {
creator.isFollow = true
creator.isNotify = false
binding.ivFollow.setImageResource(R.drawable.btn_following_no_alarm_big)
}
},
onClickUnFollow = {
viewModel.follow(
creatorId = creator.creatorId,
follow = false,
notify = false
) {
creator.isFollow = false
creator.isNotify = false
binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
}
}
)
if (notifyFragment.isAdded) return@setOnClickListener
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else { } else {
viewModel.follow(creator.creatorId) { viewModel.follow(creatorId = creator.creatorId) {
creator.isFollow = true creator.isFollow = true
creator.isNotify = true
binding.ivFollow.setImageResource(R.drawable.btn_following_big) binding.ivFollow.setImageResource(R.drawable.btn_following_big)
} }
} }
} }
} }

View File

@ -63,45 +63,19 @@ class SeriesDetailViewModel(
) )
} }
fun follow(creatorId: Long, onSuccess: () -> Unit) { fun follow(
creatorId: Long,
follow: Boolean = true,
notify: Boolean = true,
onSuccess: () -> Unit
) {
_isLoading.value = true _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
userRepository.creatorFollow( userRepository.creatorFollow(
creatorId, creatorId = creatorId,
"Bearer ${SharedPreferenceManager.token}" follow,
) notify,
.subscribeOn(Schedulers.io()) token = "Bearer ${SharedPreferenceManager.token}"
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
if (it.success && it.data != null) {
onSuccess()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
_isLoading.value = false
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unFollow(creatorId: Long, onSuccess: () -> Unit) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -346,9 +346,9 @@ class AudioContentUploadViewModel(
val timeDifference = timeDifference(previewStartTime!!, previewEndTime!!) val timeDifference = timeDifference(previewStartTime!!, previewEndTime!!)
if (timeDifference < 30000) { if (timeDifference < 15000) {
_toastLiveData.postValue( _toastLiveData.postValue(
"미리 듣기의 최소 시간은 30초 입니다." "미리 듣기의 최소 시간은 15초 입니다."
) )
return false return false

View File

@ -237,10 +237,10 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
viewModel { AudioContentUploadViewModel(get()) } viewModel { AudioContentUploadViewModel(get()) }
viewModel { AudioContentModifyViewModel(get()) } viewModel { AudioContentModifyViewModel(get()) }
viewModel { AudioContentThemeViewModel(get()) } viewModel { AudioContentThemeViewModel(get()) }
viewModel { AudioContentDetailViewModel(get(), get(), get(), get()) } viewModel { AudioContentDetailViewModel(get(), get(), get(), get(), get()) }
viewModel { AudioContentCommentListViewModel(get()) } viewModel { AudioContentCommentListViewModel(get()) }
viewModel { AudioContentCommentReplyViewModel(get()) } viewModel { AudioContentCommentReplyViewModel(get()) }
viewModel { FollowingCreatorViewModel(get()) } viewModel { FollowingCreatorViewModel(get(), get()) }
viewModel { ServiceCenterViewModel(get()) } viewModel { ServiceCenterViewModel(get()) }
viewModel { ProfileUpdateViewModel(get()) } viewModel { ProfileUpdateViewModel(get()) }
viewModel { NicknameUpdateViewModel(get()) } viewModel { NicknameUpdateViewModel(get()) }
@ -280,7 +280,7 @@ class AppDI(private val context: Context, isDebugMode: Boolean) {
factory { AudioContentRepository(get(), get(), get()) } factory { AudioContentRepository(get(), get(), get()) }
factory { AudioContentCommentRepository(get()) } factory { AudioContentCommentRepository(get()) }
factory { PlaybackTrackingRepository(get()) } factory { PlaybackTrackingRepository(get()) }
factory { FollowingCreatorRepository(get(), get()) } factory { FollowingCreatorRepository(get()) }
factory { FaqRepository(get()) } factory { FaqRepository(get()) }
factory { MemberTagRepository(get()) } factory { MemberTagRepository(get()) }
factory { UserProfileFantalkAllViewModel(get(), get()) } factory { UserProfileFantalkAllViewModel(get(), get()) }

View File

@ -0,0 +1,42 @@
package kr.co.vividnext.sodalive.explorer.profile
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kr.co.vividnext.sodalive.R
class CreatorFollowNotifyFragment(
private val onClickNotifyAll: () -> Unit,
private val onClickNotifyNone: () -> Unit,
private val onClickUnFollow: () -> Unit,
) : BottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View = inflater.inflate(
R.layout.fragment_creator_follow_notify,
container,
false
)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<LinearLayout>(R.id.ll_notify_all).setOnClickListener {
onClickNotifyAll()
dialog?.dismiss()
}
view.findViewById<LinearLayout>(R.id.ll_notify_none).setOnClickListener {
onClickNotifyNone()
dialog?.dismiss()
}
view.findViewById<LinearLayout>(R.id.ll_unfollow).setOnClickListener {
onClickUnFollow()
dialog?.dismiss()
}
}
}

View File

@ -41,6 +41,8 @@ data class CreatorResponse(
@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("isAvailableChat") val isAvailableChat: Boolean = true, @SerializedName("isAvailableChat") val isAvailableChat: Boolean = true,
@SerializedName("isFollow") val isFollow: Boolean,
@SerializedName("isNotify") val isNotify: Boolean,
@SerializedName("isNotification") val isNotification: Boolean, @SerializedName("isNotification") val isNotification: Boolean,
@SerializedName("notificationRecipientCount") val notificationRecipientCount: Int @SerializedName("notificationRecipientCount") val notificationRecipientCount: Int
) )

View File

@ -83,6 +83,8 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private var userId: Long = 0 private var userId: Long = 0
private var notifyFragment: CreatorFollowNotifyFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0) userId = intent.getLongExtra(Constants.EXTRA_USER_ID, 0)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -703,10 +705,32 @@ class UserProfileActivity : BaseActivity<ActivityUserProfileBinding>(
} }
} }
if (creator.isNotification) { if (creator.isFollow) {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_following_big) layoutUserProfile.ivNotification.setImageResource(
if (creator.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
layoutUserProfile.ivNotification.setOnClickListener { layoutUserProfile.ivNotification.setOnClickListener {
viewModel.unFollow(creator.creatorId) if (notifyFragment == null) {
notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creator.creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creator.creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creator.creatorId, follow = false, notify = false)
}
)
}
if (notifyFragment!!.isAdded) return@setOnClickListener
notifyFragment!!.show(supportFragmentManager, notifyFragment!!.tag)
} }
} else { } else {
layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_follow_big) layoutUserProfile.ivNotification.setImageResource(R.drawable.btn_follow_big)

View File

@ -16,7 +16,6 @@ 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.explorer.profile.cheers.PutModifyCheersRequest import kr.co.vividnext.sodalive.explorer.profile.cheers.PutModifyCheersRequest
import kr.co.vividnext.sodalive.explorer.profile.creator_community.GetCommunityPostListResponse
import kr.co.vividnext.sodalive.report.ReportRepository import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.report.ReportRequest import kr.co.vividnext.sodalive.report.ReportRequest
import kr.co.vividnext.sodalive.report.ReportType import kr.co.vividnext.sodalive.report.ReportType
@ -147,12 +146,14 @@ class UserProfileViewModel(
) )
} }
fun follow(creatorId: Long) { fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_isLoading.value = true _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
userRepository.creatorFollow( userRepository.creatorFollow(
creatorId, creatorId,
"Bearer ${SharedPreferenceManager.token}" follow = follow,
notify = notify,
token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())

View File

@ -14,5 +14,6 @@ data class GetFollowerListResponseItem(
@SerializedName("userId") val userId: Long, @SerializedName("userId") val userId: Long,
@SerializedName("profileImage") val profileImage: String, @SerializedName("profileImage") val profileImage: String,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("isFollow") val isFollow: Boolean? @SerializedName("isFollow") val isFollow: Boolean?,
@SerializedName("isNotify") val isNotify: Boolean?
) )

View File

@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityUserFollowerListBinding import kr.co.vividnext.sodalive.databinding.ActivityUserFollowerListBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat import kr.co.vividnext.sodalive.extensions.moneyFormat
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -50,8 +51,26 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
binding.toolbar.tvBack.setOnClickListener { finish() } binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = UserFollowerListAdapter( adapter = UserFollowerListAdapter(
onClickRegisterNotification = { viewModel.registerNotification(it) }, onClickFollow = { creatorId, isFollow ->
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) } if (isFollow) {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creatorId, follow = false, notify = false)
}
)
if (notifyFragment.isAdded) return@UserFollowerListAdapter
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else {
viewModel.follow(creatorId)
}
}
) )
binding.rvFollowerList.layoutManager = LinearLayoutManager( binding.rvFollowerList.layoutManager = LinearLayoutManager(
@ -94,6 +113,7 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
private fun bindData() { private fun bindData() {
viewModel.userId = userId viewModel.userId = userId
viewModel.followerListItemsLiveData.observe(this) { viewModel.followerListItemsLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it) adapter.addAll(it)
} }

View File

@ -11,8 +11,7 @@ import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class UserFollowerListAdapter( class UserFollowerListAdapter(
private val onClickRegisterNotification: (Long) -> Unit, private val onClickFollow: (Long, Boolean) -> Unit
private val onClickUnRegisterNotification: (Long) -> Unit,
) : RecyclerView.Adapter<UserFollowerListAdapter.ViewHolder>() { ) : RecyclerView.Adapter<UserFollowerListAdapter.ViewHolder>() {
private val items = mutableListOf<GetFollowerListResponseItem>() private val items = mutableListOf<GetFollowerListResponseItem>()
@ -28,23 +27,25 @@ class UserFollowerListAdapter(
crossfade(true) crossfade(true)
} }
if (item.isFollow != null) { if (item.isFollow != null && item.isNotify != null) {
binding.ivNotification.visibility = View.VISIBLE
if (item.isFollow) { if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_following_big) binding.ivFollow.setImageResource(
binding.ivNotification.setOnClickListener { if (item.isNotify) {
onClickUnRegisterNotification(item.userId) R.drawable.btn_following_big
clear() } else {
} R.drawable.btn_following_no_alarm_big
}
)
} else { } else {
binding.ivNotification.setImageResource(R.drawable.btn_follow_big) binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
binding.ivNotification.setOnClickListener { }
onClickRegisterNotification(item.userId)
clear() binding.ivFollow.visibility = View.VISIBLE
} binding.ivFollow.setOnClickListener {
onClickFollow(item.userId, item.isFollow)
} }
} else { } else {
binding.ivNotification.visibility = View.GONE binding.ivFollow.visibility = View.GONE
} }
} }
} }

View File

@ -34,7 +34,7 @@ class UserFollowerListViewModel(
var userId: Long = 0 var userId: Long = 0
var page = 1 var page = 1
private var isLast = false private var isLast = false
private val pageSize = 10 private var pageSize = 10
fun getFollowerList() { fun getFollowerList() {
if (!isLast && !_isLoading.value!!) { if (!isLast && !_isLoading.value!!) {
@ -52,6 +52,7 @@ class UserFollowerListViewModel(
.subscribe( .subscribe(
{ {
_isLoading.value = false _isLoading.value = false
pageSize = 10
if (it.success && it.data != null) { if (it.success && it.data != null) {
val data = it.data val data = it.data
_totalCountLiveData.value = data.totalCount _totalCountLiveData.value = data.totalCount
@ -84,12 +85,14 @@ class UserFollowerListViewModel(
} }
} }
fun registerNotification(creatorId: Long) { fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_isLoading.value = true _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
userRepository.creatorFollow( userRepository.creatorFollow(
creatorId, creatorId = creatorId,
"Bearer ${SharedPreferenceManager.token}" follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
@ -97,43 +100,9 @@ class UserFollowerListViewModel(
{ {
_isLoading.value = false _isLoading.value = false
if (it.success && it.data != null) { if (it.success && it.data != null) {
page = 1
isLast = false isLast = false
getFollowerList() pageSize *= page
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unRegisterNotification(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
page = 1 page = 1
isLast = false
getFollowerList() getFollowerList()
} else { } else {
if (it.message != null) { if (it.message != null) {

View File

@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityFollowingCreatorBinding import kr.co.vividnext.sodalive.databinding.ActivityFollowingCreatorBinding
import kr.co.vividnext.sodalive.explorer.profile.CreatorFollowNotifyFragment
import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity import kr.co.vividnext.sodalive.explorer.profile.UserProfileActivity
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -23,6 +24,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
private lateinit var loadingDialog: LoadingDialog private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: FollowingCreatorAdapter private lateinit var adapter: FollowingCreatorAdapter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -43,8 +45,26 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
} }
) )
}, },
onClickRegisterNotification = { viewModel.registerNotification(it) }, onClickFollow = { creatorId, isFollow ->
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) } if (isFollow) {
val notifyFragment = CreatorFollowNotifyFragment(
onClickNotifyAll = {
viewModel.follow(creatorId, follow = true, notify = true)
},
onClickNotifyNone = {
viewModel.follow(creatorId, follow = true, notify = false)
},
onClickUnFollow = {
viewModel.follow(creatorId, follow = false, notify = false)
}
)
if (notifyFragment.isAdded) return@FollowingCreatorAdapter
notifyFragment.show(supportFragmentManager, notifyFragment.tag)
} else {
viewModel.follow(creatorId)
}
},
) )
binding.rvFollowingCreator.layoutManager = LinearLayoutManager( binding.rvFollowingCreator.layoutManager = LinearLayoutManager(
@ -99,6 +119,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
} }
viewModel.creatorListLiveData.observe(this) { viewModel.creatorListLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it) adapter.addAll(it)
} }

View File

@ -12,8 +12,7 @@ import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class FollowingCreatorAdapter( class FollowingCreatorAdapter(
private val onClickItem: (Long) -> Unit, private val onClickItem: (Long) -> Unit,
private val onClickRegisterNotification: (Long) -> Unit, private val onClickFollow: (Long, Boolean) -> Unit
private val onClickUnRegisterNotification: (Long) -> Unit,
) : RecyclerView.Adapter<FollowingCreatorAdapter.ViewHolder>() { ) : RecyclerView.Adapter<FollowingCreatorAdapter.ViewHolder>() {
private val items = mutableListOf<GetCreatorFollowingAllListItem>() private val items = mutableListOf<GetCreatorFollowingAllListItem>()
@ -30,29 +29,22 @@ class FollowingCreatorAdapter(
crossfade(true) crossfade(true)
} }
binding.ivNotification.visibility = View.VISIBLE binding.ivFollow.visibility = View.VISIBLE
if (item.isFollow) { if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_following_big) binding.ivFollow.setImageResource(
binding.ivNotification.setOnClickListener { if (item.isNotify) {
val index = items.indexOf(item) R.drawable.btn_following_big
val copyItem = item.copy(isFollow = false) } else {
items.add(index, copyItem) R.drawable.btn_following_no_alarm_big
items.removeAt(index + 1) }
notifyDataSetChanged() )
onClickUnRegisterNotification(item.creatorId)
}
} else { } else {
binding.ivNotification.setImageResource(R.drawable.btn_follow_big) binding.ivFollow.setImageResource(R.drawable.btn_follow_big)
binding.ivNotification.setOnClickListener {
val index = items.indexOf(item)
val copyItem = item.copy(isFollow = true)
items.add(index, copyItem)
items.removeAt(index + 1)
notifyDataSetChanged()
onClickRegisterNotification(item.creatorId)
}
} }
binding.ivFollow.setOnClickListener {
onClickFollow(item.creatorId, item.isFollow)
}
binding.root.setOnClickListener { onClickItem(item.creatorId) } binding.root.setOnClickListener { onClickItem(item.creatorId) }
} }
} }

View File

@ -4,29 +4,10 @@ import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest import kr.co.vividnext.sodalive.user.CreatorFollowRequestRequest
import kr.co.vividnext.sodalive.user.UserApi import kr.co.vividnext.sodalive.user.UserApi
class FollowingCreatorRepository( class FollowingCreatorRepository(private val api: LiveRecommendApi) {
private val api: LiveRecommendApi,
private val userApi: UserApi
) {
fun getFollowedCreatorAllList( fun getFollowedCreatorAllList(
page: Int, page: Int,
size: Int, size: Int,
token: String token: String
) = api.getCreatorFollowingAllList(page = page - 1, size = size, authHeader = token) ) = api.getCreatorFollowingAllList(page = page - 1, size = size, authHeader = token)
fun registerNotification(
creatorId: Long,
token: String
) = userApi.creatorFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
fun unRegisterNotification(
creatorId: Long,
token: String
) = userApi.creatorUnFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId),
authHeader = token
)
} }

View File

@ -7,9 +7,11 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kr.co.vividnext.sodalive.base.BaseViewModel import kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.user.UserRepository
class FollowingCreatorViewModel( class FollowingCreatorViewModel(
private val repository: FollowingCreatorRepository private val repository: FollowingCreatorRepository,
private val userRepository: UserRepository
) : BaseViewModel() { ) : BaseViewModel() {
private val _creatorListLiveData = MutableLiveData<List<GetCreatorFollowingAllListItem>>() private val _creatorListLiveData = MutableLiveData<List<GetCreatorFollowingAllListItem>>()
@ -30,7 +32,7 @@ class FollowingCreatorViewModel(
var page = 1 var page = 1
var isLast = false var isLast = false
private val pageSize = 10 private var pageSize = 10
fun getFollowedCreatorAllList() { fun getFollowedCreatorAllList() {
if (!isLast && !_isLoading.value!!) { if (!isLast && !_isLoading.value!!) {
@ -47,6 +49,7 @@ class FollowingCreatorViewModel(
.subscribe( .subscribe(
{ {
_isLoading.value = false _isLoading.value = false
pageSize = 10
if (it.success && it.data != null) { if (it.success && it.data != null) {
val data = it.data val data = it.data
if (data.items.isEmpty()) { if (data.items.isEmpty()) {
@ -78,29 +81,41 @@ class FollowingCreatorViewModel(
} }
} }
fun registerNotification(creatorId: Long) { fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! + 1 _isLoading.value = true
compositeDisposable.add( compositeDisposable.add(
repository.registerNotification( userRepository.creatorFollow(
creatorId, creatorId = creatorId,
"Bearer ${SharedPreferenceManager.token}" follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
) )
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {}) .subscribe(
) {
} _isLoading.value = false
if (it.success && it.data != null) {
fun unRegisterNotification(creatorId: Long) { isLast = false
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! - 1 pageSize *= page
compositeDisposable.add( page = 1
repository.unRegisterNotification( getFollowedCreatorAllList()
creatorId, } else {
"Bearer ${SharedPreferenceManager.token}" if (it.message != null) {
) _toastLiveData.postValue(it.message)
.subscribeOn(Schedulers.io()) } else {
.observeOn(AndroidSchedulers.mainThread()) _toastLiveData.postValue(
.subscribe({}, {}) "알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
) )
} }
} }

View File

@ -14,5 +14,6 @@ data class GetCreatorFollowingAllListItem(
@SerializedName("creatorId") val creatorId: Long, @SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: String, @SerializedName("nickname") val nickname: String,
@SerializedName("profileImageUrl") val profileImageUrl: String, @SerializedName("profileImageUrl") val profileImageUrl: String,
@SerializedName("isFollow") val isFollow: Boolean @SerializedName("isFollow") var isFollow: Boolean,
@SerializedName("isNotify") var isNotify: Boolean
) )

View File

@ -46,6 +46,7 @@ import io.agora.rtm.RtmMessageType
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.agora.Agora import kr.co.vividnext.sodalive.agora.Agora
import kr.co.vividnext.sodalive.base.BaseActivity import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.base.SodaDialog
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.RealPathUtil import kr.co.vividnext.sodalive.common.RealPathUtil
@ -320,7 +321,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
}, },
onClickInviteSpeaker = { memberId -> onClickInviteSpeaker = { memberId ->
if (speakerListAdapter.itemCount <= 4) { if (speakerListAdapter.itemCount <= 5) {
inviteSpeaker(memberId) inviteSpeaker(memberId)
} else { } else {
showToast("스피커 정원이 초과했습니다.") showToast("스피커 정원이 초과했습니다.")
@ -403,7 +404,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
}, },
onClickInviteSpeaker = { onClickInviteSpeaker = {
if (speakerListAdapter.itemCount <= 4) { if (speakerListAdapter.itemCount <= 5) {
inviteSpeaker(it) inviteSpeaker(it)
} else { } else {
showToast("스피커 정원이 초과했습니다.") showToast("스피커 정원이 초과했습니다.")
@ -689,6 +690,20 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
it?.let { showToast(it) } it?.let { showToast(it) }
} }
viewModel.changeIsAdultLiveData.observe(this) {
if (it && !SharedPreferenceManager.isAuth) {
agora.muteAllRemoteAudioStreams(true)
binding.rvChat.visibility = View.INVISIBLE
SodaDialog(this@LiveRoomActivity,
layoutInflater,
"알림",
"지금 참여하던 라이브는 '19세 이상' 연령제한이 설정되어 정보통신망 이용촉진 및 정보 보호 등에 관한 법률 및 청소년 보호법의 규정에 의해 만 19세 미만의 청소년은 이용할 수 없습니다.\n마이페이지에서 본인인증 후 다시 이용하시기 바랍니다.",
"확인",
{ finish() }
).show(screenWidth)
}
}
donationMessageViewModel.isLoading.observe(this) { donationMessageViewModel.isLoading.observe(this) {
if (it) { if (it) {
loadingDialog.show(screenWidth) loadingDialog.show(screenWidth)
@ -758,10 +773,14 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
if (response.creatorId == SharedPreferenceManager.userId) { if (response.creatorId == SharedPreferenceManager.userId) {
binding.ivEdit.setOnClickListener { binding.ivEdit.setOnClickListener {
viewModel.getAllMenuPreset { viewModel.getAllMenuPreset {
roomInfoEditDialog.setRoomInfo(response.title, response.notice) roomInfoEditDialog.setRoomInfo(
response.title,
response.notice,
response.isAdult
)
roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl) roomInfoEditDialog.setCoverImageUrl(response.coverImageUrl)
roomInfoEditDialog.setMenuPreset(it) roomInfoEditDialog.setMenuPreset(it)
roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageUri, isActivateMenu, menuId, menu -> roomInfoEditDialog.setConfirmAction { newTitle, newContent, newCoverImageUri, isActivateMenu, menuId, menu, isAdult ->
viewModel.editLiveRoomInfo( viewModel.editLiveRoomInfo(
response.roomId, response.roomId,
newTitle, newTitle,
@ -770,6 +789,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
isActivateMenu, isActivateMenu,
menuId, menuId,
menu, menu,
isAdult,
onSuccess = { onSuccess = {
Toast.makeText( Toast.makeText(
applicationContext, applicationContext,
@ -1109,8 +1129,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) { ) {
super.getItemOffsets(outRect, view, parent, state) super.getItemOffsets(outRect, view, parent, state)
outRect.left = 4f.dpToPx().toInt() outRect.left = 2f.dpToPx().toInt()
outRect.right = 4f.dpToPx().toInt() outRect.right = 2f.dpToPx().toInt()
} }
}) })
rvSpeakers.adapter = speakerListAdapter rvSpeakers.adapter = speakerListAdapter
@ -1639,10 +1659,8 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
Logger.e("onAudioVolumeIndication - $speakers") Logger.e("onAudioVolumeIndication - $speakers")
val activeSpeakerIds = speakers val activeSpeakerIds = speakers
.asSequence()
.filter { it.volume > 0 } .filter { it.volume > 0 }
.map { it.uid } .map { it.uid }
.toList()
Logger.e("onAudioVolumeIndication - $activeSpeakerIds") Logger.e("onAudioVolumeIndication - $activeSpeakerIds")
handler.post { handler.post {
@ -1862,6 +1880,7 @@ class LiveRoomActivity : BaseActivity<ActivityLiveRoomBinding>(ActivityLiveRoomB
) )
) )
invalidateChat() invalidateChat()
viewModel.addDonationCan(message.can)
if (message.signature != null) { if (message.signature != null) {
addSignature(message.signature) addSignature(message.signature)

View File

@ -72,6 +72,10 @@ class LiveRoomViewModel(
val coverImageUrlLiveData: LiveData<String> val coverImageUrlLiveData: LiveData<String>
get() = _coverImageUrlLiveData get() = _coverImageUrlLiveData
private val _changeIsAdultLiveData = MutableLiveData(false)
val changeIsAdultLiveData: LiveData<Boolean>
get() = _changeIsAdultLiveData
lateinit var roomInfoResponse: GetRoomInfoResponse lateinit var roomInfoResponse: GetRoomInfoResponse
fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized fun isRoomInfoInitialized() = this::roomInfoResponse.isInitialized
@ -212,6 +216,10 @@ class LiveRoomViewModel(
getTotalDonationCan(roomId = roomId) getTotalDonationCan(roomId = roomId)
if (it.data.isAdult && !SharedPreferenceManager.isAuth) {
_changeIsAdultLiveData.value = true
}
if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) { if (userId > 0 && it.data.creatorId == SharedPreferenceManager.userId) {
val nickname = getUserNickname(userId) val nickname = getUserNickname(userId)
onSuccess(nickname) onSuccess(nickname)
@ -425,6 +433,7 @@ class LiveRoomViewModel(
isActivateMenu: Boolean?, isActivateMenu: Boolean?,
menuId: Long, menuId: Long,
menu: String, menu: String,
isAdult: Boolean?,
onSuccess: () -> Unit onSuccess: () -> Unit
) { ) {
val request = EditLiveRoomInfoRequest( val request = EditLiveRoomInfoRequest(
@ -443,13 +452,15 @@ class LiveRoomViewModel(
timezone = null, timezone = null,
menuPanId = if (isActivateMenu == true) menuId else 0, menuPanId = if (isActivateMenu == true) menuId else 0,
menuPan = if (isActivateMenu == true) menu else "", menuPan = if (isActivateMenu == true) menu else "",
isActiveMenuPan = isActivateMenu isActiveMenuPan = isActivateMenu,
isAdult = isAdult
) )
val requestJson = if ( val requestJson = if (
request.title != null || request.title != null ||
request.notice != null || request.notice != null ||
request.isActiveMenuPan != null || request.isActiveMenuPan != null ||
request.isAdult != null ||
request.menuPan.isNotBlank() request.menuPan.isNotBlank()
) { ) {
Gson().toJson(request) Gson().toJson(request)

View File

@ -35,8 +35,8 @@ class LiveRoomProfileListAdapter : RecyclerView.Adapter<LiveRoomProfileListAdapt
} }
val ivMuteLp = binding.ivMute.layoutParams val ivMuteLp = binding.ivMute.layoutParams
ivMuteLp.width = 30f.dpToPx().toInt() ivMuteLp.width = 28f.dpToPx().toInt()
ivMuteLp.height = 30f.dpToPx().toInt() ivMuteLp.height = 28f.dpToPx().toInt()
binding.ivMute.layoutParams = ivMuteLp binding.ivMute.layoutParams = ivMuteLp
} }

View File

@ -12,5 +12,6 @@ data class EditLiveRoomInfoRequest(
@SerializedName("timezone") val timezone: String?, @SerializedName("timezone") val timezone: String?,
@SerializedName("menuPanId") val menuPanId: Long = 0, @SerializedName("menuPanId") val menuPanId: Long = 0,
@SerializedName("menuPan") val menuPan: String = "", @SerializedName("menuPan") val menuPan: String = "",
@SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean? = null @SerializedName("isActiveMenuPan") val isActiveMenuPan: Boolean? = null,
@SerializedName("isAdult") val isAdult: Boolean? = null
) )

View File

@ -19,6 +19,7 @@ import androidx.lifecycle.MutableLiveData
import coil.load import coil.load
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
import kr.co.vividnext.sodalive.R import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.DialogLiveRoomInfoUpdateBinding import kr.co.vividnext.sodalive.databinding.DialogLiveRoomInfoUpdateBinding
import kr.co.vividnext.sodalive.extensions.dpToPx import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
@ -39,10 +40,12 @@ class LiveRoomInfoEditDialog(
private var menuId = 0L private var menuId = 0L
private val menuList = mutableListOf<GetMenuPresetResponse>() private val menuList = mutableListOf<GetMenuPresetResponse>()
private val isAdultLiveData = MutableLiveData(false)
private val isActivateMenuLiveData = MutableLiveData(false) private val isActivateMenuLiveData = MutableLiveData(false)
private val selectedMenuLiveData = MutableLiveData<LiveRoomCreateViewModel.SelectedMenu>() private val selectedMenuLiveData = MutableLiveData<LiveRoomCreateViewModel.SelectedMenu>()
private var menu: String = "" private var menu: String = ""
private var isAdult: Boolean = false
private var isActivateMenu: Boolean? = null private var isActivateMenu: Boolean? = null
private lateinit var selectedMenu: LiveRoomCreateViewModel.SelectedMenu private lateinit var selectedMenu: LiveRoomCreateViewModel.SelectedMenu
@ -96,6 +99,15 @@ class LiveRoomInfoEditDialog(
selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3) selectMenuPreset(LiveRoomCreateViewModel.SelectedMenu.MENU_3)
} }
if (SharedPreferenceManager.isAuth) {
dialogView.llAdult.visibility = View.VISIBLE
dialogView.ivAdultSwitch.setOnClickListener {
isAdultLiveData.value = !isAdultLiveData.value!!
}
} else {
dialogView.llAdult.visibility = View.GONE
}
selectedMenuLiveData.observe(activity) { selectedMenuLiveData.observe(activity) {
deselectAllMenuPreset() deselectAllMenuPreset()
@ -129,14 +141,28 @@ class LiveRoomInfoEditDialog(
dialogView.ivSwitch.setImageResource(R.drawable.btn_toggle_off_big) dialogView.ivSwitch.setImageResource(R.drawable.btn_toggle_off_big)
} }
} }
isAdultLiveData.observe(activity) {
dialogView.ivAdultSwitch.setImageResource(
if (it) {
R.drawable.btn_toggle_on_big
} else {
R.drawable.btn_toggle_off_big
}
)
}
} }
fun setRoomInfo( fun setRoomInfo(
currentTitle: String, currentTitle: String,
currentContent: String, currentContent: String,
isAdult: Boolean
) { ) {
dialogView.etTitle.setText(currentTitle) dialogView.etTitle.setText(currentTitle)
dialogView.etNotice.setText(currentContent) dialogView.etNotice.setText(currentContent)
this.isAdult = isAdult
isAdultLiveData.value = isAdult
} }
fun setCoverImageUri(coverImageUri: Uri) { fun setCoverImageUri(coverImageUri: Uri) {
@ -176,7 +202,7 @@ class LiveRoomInfoEditDialog(
} }
} }
fun setConfirmAction(confirmAction: (String, String, Uri?, Boolean?, Long, String) -> Unit) { fun setConfirmAction(confirmAction: (String, String, Uri?, Boolean?, Long, String, Boolean?) -> Unit) {
dialogView.tvConfirm.setOnClickListener { dialogView.tvConfirm.setOnClickListener {
alertDialog.dismiss() alertDialog.dismiss()
@ -202,7 +228,12 @@ class LiveRoomInfoEditDialog(
isActivateMenu isActivateMenu
}, },
menuId, menuId,
menu menu,
if (isAdult != isAdultLiveData.value!!) {
isAdultLiveData.value!!
} else {
null
}
) )
coverImageUri = null coverImageUri = null
coverImageUrl = null coverImageUrl = null

View File

@ -4,4 +4,8 @@ import androidx.annotation.Keep
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
@Keep @Keep
data class CreatorFollowRequestRequest(@SerializedName("creatorId") val creatorId: Long) data class CreatorFollowRequestRequest(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("isNotify") val isNotify: Boolean = true,
@SerializedName("isActive") val isActive: Boolean = true
)

View File

@ -54,9 +54,15 @@ class UserRepository(private val userApi: UserApi) {
fun creatorFollow( fun creatorFollow(
creatorId: Long, creatorId: Long,
follow: Boolean = true,
notify: Boolean = true,
token: String token: String
) = userApi.creatorFollow( ) = userApi.creatorFollow(
request = CreatorFollowRequestRequest(creatorId = creatorId), request = CreatorFollowRequestRequest(
creatorId = creatorId,
isActive = follow,
isNotify = notify
),
authHeader = token authHeader = token
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -15,7 +15,7 @@
<item android:id="@android:id/progress"> <item android:id="@android:id/progress">
<clip> <clip>
<shape> <shape>
<solid android:color="@color/color_9970ff" /> <solid android:color="@color/color_3bb9f1" />
</shape> </shape>
</clip> </clip>
</item> </item>

View File

@ -735,7 +735,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:text="미리듣기 시간을 직접 설정하지 않으면 콘텐츠 앞부분 30초가 자동으로 설정됩니다. 미리듣기의 시간제한은 없습니다." android:text="미리듣기 시간을 직접 설정하지 않으면 콘텐츠 앞부분 15초가 자동으로 설정됩니다. 미리듣기의 시간제한은 없습니다."
android:textColor="@color/color_777777" android:textColor="@color/color_777777"
android:textSize="13.3sp" /> android:textSize="13.3sp" />
@ -803,7 +803,7 @@
android:background="@drawable/bg_round_corner_6_7_222222" android:background="@drawable/bg_round_corner_6_7_222222"
android:fontFamily="@font/gmarket_sans_bold" android:fontFamily="@font/gmarket_sans_bold"
android:gravity="center" android:gravity="center"
android:hint="00:30:00" android:hint="00:00:15"
android:importantForAutofill="no" android:importantForAutofill="no"
android:inputType="textWebEditText" android:inputType="textWebEditText"
android:paddingHorizontal="13.3dp" android:paddingHorizontal="13.3dp"

View File

@ -271,7 +271,7 @@
android:layout_marginTop="12dp"> android:layout_marginTop="12dp">
<RelativeLayout <RelativeLayout
android:layout_width="180dp" android:layout_width="166dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/bg_round_corner_5_3_transparent_bbbbbb" android:background="@drawable/bg_round_corner_5_3_transparent_bbbbbb"
android:padding="5.3dp"> android:padding="5.3dp">

View File

@ -29,7 +29,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="4dp" android:layout_marginStart="4dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:textColor="@color/color_9970ff" android:textColor="@color/color_3bb9f1"
android:textSize="18.3sp" android:textSize="18.3sp"
app:layout_constraintStart_toEndOf="@+id/tv_title" app:layout_constraintStart_toEndOf="@+id/tv_title"
app:layout_constraintTop_toTopOf="@+id/tv_title" app:layout_constraintTop_toTopOf="@+id/tv_title"

View File

@ -138,6 +138,48 @@
tools:ignore="LabelFor" /> tools:ignore="LabelFor" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/ll_adult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="33.3dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/gmarket_sans_bold"
android:text="연령제한"
android:textColor="@color/color_eeeeee"
android:textSize="16.7sp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/gmarket_sans_medium"
android:lineSpacingExtra="5sp"
android:text="19세 이상"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp" />
<ImageView
android:id="@+id/iv_adult_switch"
android:layout_width="33.3dp"
android:layout_height="20dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:contentDescription="@null"
android:src="@drawable/btn_toggle_off_big" />
</RelativeLayout>
</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

@ -5,7 +5,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@drawable/bg_round_corner_10_13181b"> android:background="@drawable/bg_round_corner_10_13181b"
android:paddingHorizontal="24dp">
<TextView <TextView
android:id="@+id/tv_title" android:id="@+id/tv_title"
@ -27,7 +28,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="6dp" android:layout_marginTop="6dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center"
android:textColor="@color/color_bbbbbb" android:textColor="@color/color_bbbbbb"
android:textSize="15sp" android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -38,7 +38,6 @@
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="16.7dp"
android:layout_marginTop="45dp" android:layout_marginTop="45dp"
android:layout_marginBottom="16.7dp" android:layout_marginBottom="16.7dp"
android:gravity="center" android:gravity="center"

View File

@ -0,0 +1,88 @@
<?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="@drawable/bg_top_round_corner_10_222222"
android:orientation="vertical"
android:padding="16dp">
<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="18.3sp" />
<LinearLayout
android:id="@+id/ll_notify_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_notify_all" />
<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" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_notify_none"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_notify_none" />
<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" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_unfollow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:src="@drawable/ic_avatar_unfollow" />
<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" />
</LinearLayout>
</LinearLayout>

View File

@ -17,14 +17,14 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="13.3dp" android:layout_marginStart="13.3dp"
android:layout_toStartOf="@+id/iv_notification" android:layout_toStartOf="@+id/iv_follow"
android:layout_toEndOf="@+id/iv_profile" android:layout_toEndOf="@+id/iv_profile"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:textSize="16.7sp" android:textSize="16.7sp"
tools:text="상남자" /> tools:text="상남자" />
<ImageView <ImageView
android:id="@+id/iv_notification" android:id="@+id/iv_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_alignParentEnd="true"

View File

@ -1,19 +1,19 @@
<?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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="30dp" android:layout_width="28dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:gravity="center"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout <RelativeLayout
android:layout_width="30dp" android:layout_width="28dp"
android:layout_height="30dp"> android:layout_height="28dp">
<ImageView <ImageView
android:id="@+id/iv_profile" android:id="@+id/iv_profile"
android:layout_width="26.7dp" android:layout_width="25dp"
android:layout_height="26.7dp" android:layout_height="25dp"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:contentDescription="@null" android:contentDescription="@null"
tools:src="@mipmap/ic_launcher" /> tools:src="@mipmap/ic_launcher" />
@ -42,8 +42,7 @@
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:lines="1" android:lines="1"
android:textColor="@color/color_777777" android:textColor="@color/color_777777"
android:textSize="10.7sp" android:textSize="8.7sp"
tools:ignore="SmallSp" tools:ignore="SmallSp"
tools:text="932sld23" /> tools:text="932sld23" />
</LinearLayout> </LinearLayout>