feat(dm): 수신자 선택 화면을 연결한다
This commit is contained in:
@@ -68,6 +68,9 @@
|
|||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
tools:replace="android:allowBackup"
|
tools:replace="android:allowBackup"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name="kr.co.vividnext.sodalive.v2.main.chat.recipient.DmRecipientPickerActivity"
|
||||||
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".main.DeepLinkActivity"
|
android:name=".main.DeepLinkActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.doAfterTextChanged
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.base.BaseActivity
|
||||||
|
import kr.co.vividnext.sodalive.common.LoadingDialog
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.databinding.ActivityDmRecipientPickerBinding
|
||||||
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
|
import kr.co.vividnext.sodalive.settings.notification.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.user.UserRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.components.modal.V2ModalDialog
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.chat.dm.DmChatRoomActivity
|
||||||
|
import kr.co.vividnext.sodalive.v2.main.chat.dm.data.DmChatRepository
|
||||||
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
|
class DmRecipientPickerActivity : BaseActivity<ActivityDmRecipientPickerBinding>(
|
||||||
|
ActivityDmRecipientPickerBinding::inflate
|
||||||
|
) {
|
||||||
|
private val explorerRepository: ExplorerRepository by inject()
|
||||||
|
private val userRepository: UserRepository by inject()
|
||||||
|
private val dmRepository: DmChatRepository by inject()
|
||||||
|
private val viewModel: DmRecipientPickerViewModel by viewModels {
|
||||||
|
dmRecipientPickerFactory(explorerRepository, userRepository)
|
||||||
|
}
|
||||||
|
private val adapter = DmRecipientAdapter(::confirmRecipient)
|
||||||
|
private val loadingDialog by lazy { LoadingDialog(this, layoutInflater) }
|
||||||
|
private var isOpeningRoom = false
|
||||||
|
|
||||||
|
override fun setupView() {
|
||||||
|
if (SharedPreferenceManager.role != MemberRole.CREATOR.name) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
binding.btnBack.setOnClickListener { finish() }
|
||||||
|
binding.rvRecipients.layoutManager = LinearLayoutManager(this)
|
||||||
|
binding.rvRecipients.adapter = adapter
|
||||||
|
binding.etSearchNickname.doAfterTextChanged {
|
||||||
|
viewModel.onSearchQueryChanged(it?.toString().orEmpty())
|
||||||
|
}
|
||||||
|
viewModel.recipientStateLiveData.observe(this) { state ->
|
||||||
|
adapter.submitItems(state.recipients)
|
||||||
|
binding.tvFollowers.isVisible = state.mode == DmRecipientPickerMode.FOLLOWERS
|
||||||
|
binding.tvSearchResultCount.isVisible = state.mode == DmRecipientPickerMode.SEARCH
|
||||||
|
binding.tvSearchResultCount.text = getString(
|
||||||
|
R.string.dm_recipient_search_result_count,
|
||||||
|
state.searchResultCount
|
||||||
|
)
|
||||||
|
binding.tvSearchEmpty.isVisible = state.isSearchEmpty
|
||||||
|
binding.rvRecipients.isVisible = !state.isSearchEmpty
|
||||||
|
if (state.isError) showToast(getString(R.string.common_error_request))
|
||||||
|
}
|
||||||
|
viewModel.enter()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun confirmRecipient(recipient: DmRecipientUiModel) {
|
||||||
|
if (isOpeningRoom) return
|
||||||
|
V2ModalDialog(
|
||||||
|
activity = this,
|
||||||
|
layoutInflater = layoutInflater,
|
||||||
|
title = getString(R.string.dm_recipient_confirm_title),
|
||||||
|
desc = getString(R.string.dm_recipient_confirm_message, recipient.nickname),
|
||||||
|
cancelButtonTitle = getString(R.string.cancel),
|
||||||
|
confirmButtonTitle = getString(R.string.dm_recipient_send),
|
||||||
|
confirmButtonClick = { openRoom(recipient.id) }
|
||||||
|
).show(screenWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun openRoom(recipientId: Long) {
|
||||||
|
if (isOpeningRoom) return
|
||||||
|
isOpeningRoom = true
|
||||||
|
loadingDialog.show(screenWidth)
|
||||||
|
compositeDisposable.add(
|
||||||
|
dmRepository.createOrGetRoomByRecipientId(SharedPreferenceManager.token, recipientId)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doFinally {
|
||||||
|
isOpeningRoom = false
|
||||||
|
loadingDialog.dismiss()
|
||||||
|
}
|
||||||
|
.subscribe({ response ->
|
||||||
|
val data = response.data
|
||||||
|
if (response.success && data != null) {
|
||||||
|
startActivity(DmChatRoomActivity.newIntentByRoomId(this, data.roomId))
|
||||||
|
finish()
|
||||||
|
} else {
|
||||||
|
showToast(getString(R.string.common_error_request))
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
showToast(getString(R.string.common_error_request))
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.main.chat.recipient
|
||||||
|
|
||||||
|
import androidx.lifecycle.viewmodel.initializer
|
||||||
|
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
|
||||||
|
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
|
||||||
|
import kr.co.vividnext.sodalive.user.UserRepository
|
||||||
|
|
||||||
|
internal fun dmRecipientPickerFactory(
|
||||||
|
explorerRepository: ExplorerRepository,
|
||||||
|
userRepository: UserRepository
|
||||||
|
) = viewModelFactory {
|
||||||
|
initializer {
|
||||||
|
DmRecipientPickerViewModel(
|
||||||
|
loadFollowers = {
|
||||||
|
explorerRepository.getFollowerList(
|
||||||
|
userId = SharedPreferenceManager.userId,
|
||||||
|
page = 1,
|
||||||
|
size = 20,
|
||||||
|
token = "Bearer ${SharedPreferenceManager.token}"
|
||||||
|
).map { response ->
|
||||||
|
val data = response.data
|
||||||
|
check(response.success && data != null)
|
||||||
|
data.items.map { DmRecipientUiModel(it.userId, it.nickname, it.profileImage) }
|
||||||
|
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||||
|
},
|
||||||
|
searchUsers = { nickname ->
|
||||||
|
userRepository.searchUser(nickname, "Bearer ${SharedPreferenceManager.token}")
|
||||||
|
.map { response ->
|
||||||
|
val data = response.data
|
||||||
|
check(response.success && data != null)
|
||||||
|
data.map { DmRecipientUiModel(it.id, it.nickname, it.profileImageUrl) }
|
||||||
|
}.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||||
|
},
|
||||||
|
debounceScheduler = AndroidSchedulers.mainThread()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/black"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="54dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btn_back"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:padding="@dimen/spacing_12"
|
||||||
|
android:src="@drawable/ic_back" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/search_container"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_marginEnd="@dimen/spacing_14"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@drawable/bg_round_corner_10_232323"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_12">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_search"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/ic_title_search_black" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et_search_nickname"
|
||||||
|
style="@style/Typography.Body3"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="@dimen/spacing_8"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/dm_recipient_search_hint"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/color_979797"
|
||||||
|
android:textCursorDrawable="@drawable/edit_text_cursor"
|
||||||
|
tools:ignore="LabelFor" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_followers"
|
||||||
|
style="@style/Typography.Body2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_14"
|
||||||
|
android:text="@string/dm_recipient_followers"
|
||||||
|
android:textColor="@color/color_e2e2e2" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_search_result_count"
|
||||||
|
style="@style/Typography.Caption2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingHorizontal="@dimen/spacing_14"
|
||||||
|
android:text="@string/dm_recipient_search_result_count"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="검색결과 0" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/recipient_content_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_recipients"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_search_empty"
|
||||||
|
style="@style/Typography.Body5"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="@dimen/spacing_20"
|
||||||
|
android:text="@string/dm_recipient_search_empty"
|
||||||
|
android:textColor="@color/color_777777"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user