팔로잉/팔로워 리스트 - 팔로우와 알림설정

- 팔로잉 상태에서 알림 켜기/끄기 상태 추가
This commit is contained in:
klaus 2024-09-20 01:57:27 +09:00
parent 5063ce815d
commit 5b2c5a6e2f
14 changed files with 130 additions and 127 deletions

View File

@ -53,5 +53,7 @@ data class AudioContentCreator(
@SerializedName("creatorId") val creatorId: Long,
@SerializedName("nickname") val nickname: 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

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

View File

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

View File

@ -14,5 +14,6 @@ data class GetFollowerListResponseItem(
@SerializedName("userId") val userId: Long,
@SerializedName("profileImage") val profileImage: 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.LoadingDialog
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.moneyFormat
import org.koin.android.ext.android.inject
@ -50,8 +51,26 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
binding.toolbar.tvBack.setOnClickListener { finish() }
adapter = UserFollowerListAdapter(
onClickRegisterNotification = { viewModel.registerNotification(it) },
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) }
onClickFollow = { creatorId, isFollow ->
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(
@ -94,6 +113,7 @@ class UserFollowerListActivity : BaseActivity<ActivityUserFollowerListBinding>(
private fun bindData() {
viewModel.userId = userId
viewModel.followerListItemsLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it)
}

View File

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

View File

@ -34,7 +34,7 @@ class UserFollowerListViewModel(
var userId: Long = 0
var page = 1
private var isLast = false
private val pageSize = 10
private var pageSize = 10
fun getFollowerList() {
if (!isLast && !_isLoading.value!!) {
@ -52,6 +52,7 @@ class UserFollowerListViewModel(
.subscribe(
{
_isLoading.value = false
pageSize = 10
if (it.success && it.data != null) {
val data = it.data
_totalCountLiveData.value = data.totalCount
@ -84,11 +85,13 @@ class UserFollowerListViewModel(
}
}
fun registerNotification(creatorId: Long) {
fun follow(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())
@ -97,43 +100,9 @@ class UserFollowerListViewModel(
{
_isLoading.value = false
if (it.success && it.data != null) {
page = 1
isLast = false
getFollowerList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
fun unRegisterNotification(creatorId: Long) {
_isLoading.value = true
compositeDisposable.add(
userRepository.creatorUnFollow(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
pageSize *= page
page = 1
isLast = false
getFollowerList()
} else {
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.LoadingDialog
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.extensions.dpToPx
import org.koin.android.ext.android.inject
@ -23,6 +24,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
private lateinit var loadingDialog: LoadingDialog
private lateinit var adapter: FollowingCreatorAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -43,8 +45,26 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
}
)
},
onClickRegisterNotification = { viewModel.registerNotification(it) },
onClickUnRegisterNotification = { viewModel.unRegisterNotification(it) }
onClickFollow = { creatorId, isFollow ->
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(
@ -99,6 +119,7 @@ class FollowingCreatorActivity : BaseActivity<ActivityFollowingCreatorBinding>(
}
viewModel.creatorListLiveData.observe(this) {
if (viewModel.page == 2) adapter.clear()
adapter.addAll(it)
}

View File

@ -12,8 +12,7 @@ import kr.co.vividnext.sodalive.databinding.ItemFollowerListBinding
class FollowingCreatorAdapter(
private val onClickItem: (Long) -> Unit,
private val onClickRegisterNotification: (Long) -> Unit,
private val onClickUnRegisterNotification: (Long) -> Unit,
private val onClickFollow: (Long, Boolean) -> Unit
) : RecyclerView.Adapter<FollowingCreatorAdapter.ViewHolder>() {
private val items = mutableListOf<GetCreatorFollowingAllListItem>()
@ -30,29 +29,22 @@ class FollowingCreatorAdapter(
crossfade(true)
}
binding.ivNotification.visibility = View.VISIBLE
binding.ivFollow.visibility = View.VISIBLE
if (item.isFollow) {
binding.ivNotification.setImageResource(R.drawable.btn_following_big)
binding.ivNotification.setOnClickListener {
val index = items.indexOf(item)
val copyItem = item.copy(isFollow = false)
items.add(index, copyItem)
items.removeAt(index + 1)
notifyDataSetChanged()
onClickUnRegisterNotification(item.creatorId)
}
binding.ivFollow.setImageResource(
if (item.isNotify) {
R.drawable.btn_following_big
} else {
R.drawable.btn_following_no_alarm_big
}
)
} else {
binding.ivNotification.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.setImageResource(R.drawable.btn_follow_big)
}
binding.ivFollow.setOnClickListener {
onClickFollow(item.creatorId, item.isFollow)
}
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.UserApi
class FollowingCreatorRepository(
private val api: LiveRecommendApi,
private val userApi: UserApi
) {
class FollowingCreatorRepository(private val api: LiveRecommendApi) {
fun getFollowedCreatorAllList(
page: Int,
size: Int,
token: String
) = 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 kr.co.vividnext.sodalive.base.BaseViewModel
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.user.UserRepository
class FollowingCreatorViewModel(
private val repository: FollowingCreatorRepository
private val repository: FollowingCreatorRepository,
private val userRepository: UserRepository
) : BaseViewModel() {
private val _creatorListLiveData = MutableLiveData<List<GetCreatorFollowingAllListItem>>()
@ -30,7 +32,7 @@ class FollowingCreatorViewModel(
var page = 1
var isLast = false
private val pageSize = 10
private var pageSize = 10
fun getFollowedCreatorAllList() {
if (!isLast && !_isLoading.value!!) {
@ -47,6 +49,7 @@ class FollowingCreatorViewModel(
.subscribe(
{
_isLoading.value = false
pageSize = 10
if (it.success && it.data != null) {
val data = it.data
if (data.items.isEmpty()) {
@ -78,29 +81,40 @@ class FollowingCreatorViewModel(
}
}
fun registerNotification(creatorId: Long) {
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! + 1
fun follow(creatorId: Long, follow: Boolean = true, notify: Boolean = true) {
compositeDisposable.add(
repository.registerNotification(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
userRepository.creatorFollow(
creatorId = creatorId,
follow,
notify,
token = "Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
)
}
fun unRegisterNotification(creatorId: Long) {
_creatorListTotalCountLiveData.value = _creatorListTotalCountLiveData.value!! - 1
compositeDisposable.add(
repository.unRegisterNotification(
creatorId,
"Bearer ${SharedPreferenceManager.token}"
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({}, {})
.subscribe(
{
_isLoading.value = false
if (it.success && it.data != null) {
isLast = false
pageSize *= page
page = 1
getFollowedCreatorAllList()
} else {
if (it.message != null) {
_toastLiveData.postValue(it.message)
} else {
_toastLiveData.postValue(
"알 수 없는 오류가 발생했습니다. 다시 시도해 주세요."
)
}
}
},
{
_isLoading.value = false
it.message?.let { message -> Logger.e(message) }
_toastLiveData.postValue("알 수 없는 오류가 발생했습니다. 다시 시도해 주세요.")
}
)
)
}
}

View File

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

View File

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

View File

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