From ef9eeaf98876d8ec3479883de19df7f51be695c9 Mon Sep 17 00:00:00 2001 From: Wooyoung Myung Date: Thu, 2 Nov 2023 10:39:50 +0900 Subject: [PATCH 1/7] =?UTF-8?q?kuring-91=20[=EC=88=98=EC=A0=95]=20?= =?UTF-8?q?=EC=BF=A0=EB=A7=81=20=EC=BA=A0=ED=8D=BC=EC=8A=A4=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=20=EB=A9=94=EC=8B=9C=EC=A7=80=EC=97=90=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=20=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EA=B1=B0=EB=A5=BC=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/campus_login.xml | 2 +- app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/campus_login.xml b/app/src/main/res/layout/campus_login.xml index 08241c095..9cf10c09c 100644 --- a/app/src/main/res/layout/campus_login.xml +++ b/app/src/main/res/layout/campus_login.xml @@ -23,7 +23,7 @@ android:layout_marginEnd="20dp" android:fontFamily="@font/sfpro_display_regular" android:gravity="center_horizontal" - android:text="@string/campus_ask_send_message" + android:text="@string/campus_on_construction" android:textColor="@color/kus_primary" android:textSize="15sp" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dbd9c60d1..5f645a3ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -129,6 +129,7 @@ 쿠링 캠퍼스 쿠링청심대 + 더 멋진 쿠링을 위해 잠시만 기다려 주세요! 쿠링 청심대에서 다같이 모여 메세지를 보내세요 상대에게 보여지는 이름을 설정해주세요 적절한 닉네임 형식이 아닙니다. From fcabaa6d3a524907d4df5a86425be754bec11d2d Mon Sep 17 00:00:00 2001 From: Wooyoung Myung Date: Thu, 2 Nov 2023 10:40:04 +0900 Subject: [PATCH 2/7] =?UTF-8?q?kuring-91=20[=EC=A0=9C=EA=B1=B0]=20?= =?UTF-8?q?=EC=BA=A0=ED=8D=BC=EC=8A=A4=20=EB=A9=94=EC=9D=B8=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=20UI=EC=97=90=EC=84=9C=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=EC=9D=84=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/campus_login.xml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/app/src/main/res/layout/campus_login.xml b/app/src/main/res/layout/campus_login.xml index 9cf10c09c..295031af7 100644 --- a/app/src/main/res/layout/campus_login.xml +++ b/app/src/main/res/layout/campus_login.xml @@ -12,7 +12,7 @@ android:layout_marginEnd="60dp" android:layout_marginBottom="60dp" android:src="@drawable/ic_campus_man" - app:layout_constraintBottom_toTopOf="@+id/campus_google_login_bt" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" /> - - \ No newline at end of file From 82a4228c407912aef43c8079dc6586151879a4e3 Mon Sep 17 00:00:00 2001 From: Wooyoung Myung Date: Sun, 5 Nov 2023 23:17:13 +0900 Subject: [PATCH 3/7] =?UTF-8?q?kuring-91=20[=EC=88=98=EC=A0=95]=20?= =?UTF-8?q?=EC=BA=A0=ED=8D=BC=EC=8A=A4=20=EB=A9=94=EC=9D=B8=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=9D=84=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=EC=9D=B4=20=EC=97=86=EB=8A=94=20=EB=B2=84=EC=A0=84?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_campus.xml | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/app/src/main/res/layout/fragment_campus.xml b/app/src/main/res/layout/fragment_campus.xml index d32f384e3..a06810615 100644 --- a/app/src/main/res/layout/fragment_campus.xml +++ b/app/src/main/res/layout/fragment_campus.xml @@ -20,29 +20,11 @@ app:layout_constraintTop_toTopOf="parent" /> - - - - \ No newline at end of file From db7701453e32235d6a6c039091d8b1c3c989ee9b Mon Sep 17 00:00:00 2001 From: Wooyoung Myung Date: Sun, 5 Nov 2023 23:33:53 +0900 Subject: [PATCH 4/7] =?UTF-8?q?kuring-91=20[=EC=A0=9C=EA=B1=B0]=20?= =?UTF-8?q?=EC=B1=84=ED=8C=85=EA=B3=BC=20=EA=B4=80=EB=A0=A8=EB=90=9C=20?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83,=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 5 - .../ku_ring/navigator/KuringNavigator.kt | 1 - .../ku_ring/navigator/KuringNavigatorImpl.kt | 6 +- .../ku_stacks/ku_ring/ui/chat/ChatActivity.kt | 190 ---------- .../ku_ring/ui/chat/ChatMessageAdapter.kt | 150 -------- .../ui/chat/ChatRecyclerDataObserver.kt | 45 --- .../ku_ring/ui/chat/ChatViewModel.kt | 350 ------------------ .../ku_ring/ui/chat/ui_model/ChatUiModel.kt | 28 -- .../ui/chat/ui_model/ChatUiModelMapper.kt | 61 --- .../ui/chat/viewholder/AdminViewHolder.kt | 15 - .../ui/chat/viewholder/ReceiveViewHolder.kt | 75 ---- .../chat/viewholder/SealedChatViewHolder.kt | 6 - .../ui/chat/viewholder/SendViewHolder.kt | 21 -- .../ku_ring/ui/dialogs/ChatActionDialog.kt | 51 --- .../main/campus_onboarding/CampusFragment.kt | 168 --------- .../ui/main/campus_onboarding/CampusState.kt | 7 - .../main/campus_onboarding/CampusViewModel.kt | 108 ------ app/src/main/res/layout/activity_chat.xml | 123 ------ app/src/main/res/layout/campus_auto_login.xml | 49 --- .../main/res/layout/campus_set_nickname.xml | 78 ---- .../main/res/layout/dialog_chat_action.xml | 75 ---- app/src/main/res/layout/item_chat_admin.xml | 75 ---- app/src/main/res/layout/item_chat_receive.xml | 95 ----- app/src/main/res/layout/item_chat_send.xml | 100 ----- 24 files changed, 1 insertion(+), 1881 deletions(-) delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatActivity.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatMessageAdapter.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatRecyclerDataObserver.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatViewModel.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModel.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModelMapper.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/AdminViewHolder.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/ReceiveViewHolder.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SealedChatViewHolder.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SendViewHolder.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/dialogs/ChatActionDialog.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusState.kt delete mode 100644 app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusViewModel.kt delete mode 100644 app/src/main/res/layout/activity_chat.xml delete mode 100644 app/src/main/res/layout/campus_auto_login.xml delete mode 100644 app/src/main/res/layout/campus_set_nickname.xml delete mode 100644 app/src/main/res/layout/dialog_chat_action.xml delete mode 100644 app/src/main/res/layout/item_chat_admin.xml delete mode 100644 app/src/main/res/layout/item_chat_receive.xml delete mode 100644 app/src/main/res/layout/item_chat_send.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 19fff39b7..b6df21b7a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -82,11 +82,6 @@ android:exported="true" android:screenOrientation="portrait" /> - - () - - private lateinit var chatMessageAdapter: ChatMessageAdapter - private lateinit var recyclerObserver: ChatRecyclerDataObserver - private lateinit var pager: RecyclerViewPager - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setupBinding() - setupView() - setupRecyclerView() - observeData() - observeEvent() - } - - private fun setupBinding() { - binding = DataBindingUtil.setContentView(this, R.layout.activity_chat) - binding.lifecycleOwner = this - binding.viewModel = viewModel - } - - private fun setupView() { - binding.chatBackBt.setOnClickListener { - finish() - overridePendingTransition(R.anim.anim_slide_left_enter, R.anim.anim_slide_left_exit) - } - - binding.chatSendBt.setOnClickListener { - val message = binding.chatMessageEt.text.toString() - binding.chatMessageEt.text.clear() - viewModel.sendMessage(message) - } - binding.chatMessageEt.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = - Unit - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit - override fun afterTextChanged(s: Editable?) { - val textTintColor = if (s.isNullOrEmpty()) { - R.color.kus_green_50 - } else { - R.color.kus_green - } - ImageViewCompat.setImageTintList( - binding.chatSendBt, - ColorStateList.valueOf(getColor(textTintColor)) - ) - - s?.length?.let { len -> - val maxLen = 300 - if (len > maxLen) { - showToast(getString(R.string.chat_max_message_length, maxLen.toString())) - binding.chatMessageEt.setText(s.substring(0, maxLen)) - binding.chatMessageEt.setSelection(binding.chatMessageEt.length()) - } - } - } - }) - } - - private fun setupRecyclerView() { - chatMessageAdapter = ChatMessageAdapter( - onErrorClick = { sentMessageUiModel -> makeResendDialog(sentMessageUiModel) }, - onMessageLongClick = { receivedMessageUiModel -> - makeChatActionDialog( - receivedMessageUiModel - ) - } - ) - - binding.chatRecyclerview.apply { - adapter = chatMessageAdapter - pager = RecyclerViewPager( - recyclerView = this, - isReversed = true, - isLoading = { viewModel.isLoading.value == true }, - loadNext = { viewModel.fetchPreviousMessageList(chatMessageAdapter.currentList.first().timeStamp) }, - isEnd = { viewModel.hasPrevious.value == false } - ) - pager.prefetchDistance = 30 - } - - recyclerObserver = ChatRecyclerDataObserver( - recyclerView = binding.chatRecyclerview - ) - chatMessageAdapter.registerAdapterDataObserver(recyclerObserver) - } - - private fun observeData() { - viewModel.chatUiModelList.observe(this) { - chatMessageAdapter.submitList(it.toList()) { - viewModel.isLoading.postValue(false) - } - } - } - - private fun observeEvent() { - viewModel.dialogEvent.observe(this) { - makeDialog(description = getString(it)) - } - - viewModel.toastEvent.observe(this) { - showToast(getString(it)) - } - - viewModel.readyToBottomScrollEvent.observe(this) { - recyclerObserver.readyToBottomScroll(true) - } - } - - private fun makeResendDialog(sentMessageUiModel: SentMessageUiModel) { - makeDialog( - description = getString(R.string.chat_resend_message), - leftText = getString(R.string.chat_delete), - rightText = getString(R.string.chat_resend) - ).setOnCancelClickListener { - viewModel.deletePendingMessage(sentMessageUiModel) - }.setOnConfirmClickListener { - viewModel.deletePendingMessage(sentMessageUiModel) - viewModel.sendMessage(sentMessageUiModel.message) - } - } - - private fun makeChatActionDialog(messageUiModel: ReceivedMessageUiModel) { - ChatActionDialog(this).apply { - show() - }.setOnCopyMessageClickListener { - val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - val clipData = ClipData.newPlainText("message", messageUiModel.message) - clipboardManager.setPrimaryClip(clipData) - showToast(getString(R.string.chat_copied_message)) - }.setOnCopyNicknameClickListener { - val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager - val clipData = ClipData.newPlainText("nickname", messageUiModel.nickname) - clipboardManager.setPrimaryClip(clipData) - showToast(getString(R.string.chat_copied_nickname)) - }.setOnReportClickListener { - makeDialog(description = getString(R.string.report_ask_again)) - .setOnConfirmClickListener { - viewModel.reportMessage(messageUiModel) - } - }.setOnBlockClickListener { - makeDialog(description = getString(R.string.block_ask_again)) - .setOnConfirmClickListener { - viewModel.blockUser(messageUiModel) - } - } - } - - override fun onBackPressed() { - super.onBackPressed() - overridePendingTransition(R.anim.anim_slide_left_enter, R.anim.anim_slide_left_exit) - } - - companion object { - fun start(activity: Activity) { - val intent = Intent(activity, ChatActivity::class.java) - activity.startActivity(intent) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatMessageAdapter.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatMessageAdapter.kt deleted file mode 100644 index 74a6bf566..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatMessageAdapter.kt +++ /dev/null @@ -1,150 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat - -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView.NO_POSITION -import com.ku_stacks.ku_ring.R -import com.ku_stacks.ku_ring.databinding.ItemChatAdminBinding -import com.ku_stacks.ku_ring.databinding.ItemChatReceiveBinding -import com.ku_stacks.ku_ring.databinding.ItemChatSendBinding -import com.ku_stacks.ku_ring.ui.chat.ui_model.AdminMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.ChatUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.ReceivedMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.SentMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.viewholder.AdminViewHolder -import com.ku_stacks.ku_ring.ui.chat.viewholder.ReceiveViewHolder -import com.ku_stacks.ku_ring.ui.chat.viewholder.SealedChatViewHolder -import com.ku_stacks.ku_ring.ui.chat.viewholder.SendViewHolder -import com.ku_stacks.ku_ring.util.DateUtil.areSameDate - -class ChatMessageAdapter( - private val onErrorClick: (SentMessageUiModel) -> Unit, - private val onMessageLongClick: (ReceivedMessageUiModel) -> Unit -) : ListAdapter(MessageDiffCallback) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SealedChatViewHolder { - return when (viewType) { - CHAT_RECEIVED -> { - createReceivedViewHolder(parent) - } - - CHAT_SENT -> { - createSendViewHolder(parent) - } - - CHAT_ADMIN -> { - createAdminViewHolder(parent) - } - - else -> { - throw IllegalStateException("no such viewType : $viewType") - } - } - } - - private fun createAdminViewHolder(parent: ViewGroup): AdminViewHolder { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.item_chat_admin, parent, false) - val binding = ItemChatAdminBinding.bind(view) - return AdminViewHolder(binding) - } - - private fun createSendViewHolder(parent: ViewGroup): SendViewHolder { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.item_chat_send, parent, false) - val binding = ItemChatSendBinding.bind(view) - return SendViewHolder(binding).apply { - binding.chatSendErrorIv.setOnClickListener { - val position = absoluteAdapterPosition.takeIf { it != NO_POSITION } - ?: return@setOnClickListener - onErrorClick(getItem(position) as SentMessageUiModel) - } - } - } - - private fun createReceivedViewHolder(parent: ViewGroup): ReceiveViewHolder { - val view = LayoutInflater.from(parent.context) - .inflate(R.layout.item_chat_receive, parent, false) - val binding = ItemChatReceiveBinding.bind(view) - return ReceiveViewHolder(binding).apply { - binding.chatMessageLayout.setOnLongClickListener { - val position = absoluteAdapterPosition.takeIf { it != NO_POSITION } - ?: return@setOnLongClickListener false - onMessageLongClick(getItem(position) as ReceivedMessageUiModel) - return@setOnLongClickListener true - } - } - } - - override fun onBindViewHolder(holder: SealedChatViewHolder, position: Int) { - val showDate = if (position > 0) { - val cur = currentList[position].timeStamp - val prev = currentList[position - 1].timeStamp - !areSameDate(cur, prev) - } else { - true - } - - val item = getItem(position) - when (holder) { - is ReceiveViewHolder -> { - holder.bind(item as ReceivedMessageUiModel, showDate) - } - - is SendViewHolder -> { - holder.bind(item as SentMessageUiModel, showDate) - } - - is AdminViewHolder -> { - holder.bind(item as AdminMessageUiModel, showDate) - } - } - } - - override fun getItemViewType(position: Int): Int { - return when (getItem(position)) { - is ReceivedMessageUiModel -> CHAT_RECEIVED - is SentMessageUiModel -> CHAT_SENT - is AdminMessageUiModel -> CHAT_ADMIN - } - } - - companion object { - const val CHAT_RECEIVED = 1 - const val CHAT_SENT = 2 - const val CHAT_ADMIN = 3 - } - - private object MessageDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: ChatUiModel, newItem: ChatUiModel): Boolean { - // SentMessageUiModel 은 같은 말풍선에 대해서 messageId 가 (전송 시작) : 0, (전송 후) > 0 로 변하기 때문에 분기처리 - return if (oldItem is SentMessageUiModel && newItem is SentMessageUiModel) { - if (oldItem.messageId > 0 && newItem.messageId > 0) { - oldItem.messageId == newItem.messageId - } else { - oldItem.requestId == newItem.requestId - } - } else { - oldItem.messageId == newItem.messageId - } - - } - - override fun areContentsTheSame(oldItem: ChatUiModel, newItem: ChatUiModel): Boolean { - return if (oldItem is ReceivedMessageUiModel && newItem is ReceivedMessageUiModel) { - oldItem.messageId == newItem.messageId - && oldItem.message == newItem.message - } else if (oldItem is SentMessageUiModel && newItem is SentMessageUiModel) { - oldItem.messageId == newItem.messageId - && oldItem.message == newItem.message - && oldItem.isPending == newItem.isPending - } else if (oldItem is AdminMessageUiModel && newItem is AdminMessageUiModel) { - oldItem.messageId == newItem.messageId - && oldItem.message == newItem.message - } else { - false - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatRecyclerDataObserver.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatRecyclerDataObserver.kt deleted file mode 100644 index 9dca39e3b..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatRecyclerDataObserver.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat - -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView - -// Reference : https://github.com/sendbird/sendbird-chat-sample-android/blob/main/commonmodule/src/main/java/com/sendbird/chat/module/utils/ChatRecyclerDataObserver.kt - -class ChatRecyclerDataObserver( - private val recyclerView: RecyclerView -) : RecyclerView.AdapterDataObserver() { - - private var scrollToBottom: Boolean = false - private var adapter: RecyclerView.Adapter - private var layoutManager: LinearLayoutManager - - init { - if (recyclerView.adapter == null) { - throw IllegalStateException("recyclerViewAdapter must be set") - } - adapter = recyclerView.adapter!! - layoutManager = recyclerView.layoutManager as LinearLayoutManager - } - - override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { - // 이미 가장 하단 메세지를 보고 있던 경우 - if (layoutManager.findLastCompletelyVisibleItemPosition() == adapter.itemCount - 2) { - notifyUpdate() - } else { - // 스크롤을 강제로 내려야 하는 경우(메세지 전송 등) - if (scrollToBottom) { - notifyUpdate() - } - } - super.onItemRangeInserted(positionStart, itemCount) - } - - private fun notifyUpdate() { - recyclerView.scrollToPosition(adapter.itemCount - 1) - scrollToBottom = false - } - - fun readyToBottomScroll(value: Boolean) { - scrollToBottom = value - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatViewModel.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatViewModel.kt deleted file mode 100644 index f117fad81..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ChatViewModel.kt +++ /dev/null @@ -1,350 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.ku_stacks.ku_ring.BuildConfig -import com.ku_stacks.ku_ring.R -import com.ku_stacks.ku_ring.data.api.FeedbackClient -import com.ku_stacks.ku_ring.data.api.request.FeedbackRequest -import com.ku_stacks.ku_ring.repository.UserRepository -import com.ku_stacks.ku_ring.ui.SingleLiveEvent -import com.ku_stacks.ku_ring.ui.chat.ui_model.ChatUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.ReceivedMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.SentMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.toAdminMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.toChatUiModelList -import com.ku_stacks.ku_ring.ui.chat.ui_model.toReceivedMessageUiModel -import com.ku_stacks.ku_ring.ui.chat.ui_model.toSentMessageUiModel -import com.ku_stacks.ku_ring.util.PreferenceUtil -import com.sendbird.android.SendbirdChat -import com.sendbird.android.channel.BaseChannel -import com.sendbird.android.channel.OpenChannel -import com.sendbird.android.handler.ConnectionHandler -import com.sendbird.android.handler.OpenChannelHandler -import com.sendbird.android.message.AdminMessage -import com.sendbird.android.message.BaseMessage -import com.sendbird.android.message.UserMessage -import com.sendbird.android.params.MessageListParams -import com.sendbird.android.params.UserMessageCreateParams -import dagger.hilt.android.lifecycle.HiltViewModel -import io.reactivex.rxjava3.disposables.CompositeDisposable -import io.reactivex.rxjava3.schedulers.Schedulers -import timber.log.Timber -import javax.inject.Inject - -@HiltViewModel -class ChatViewModel @Inject constructor( - private val pref: PreferenceUtil, - private val feedbackClient: FeedbackClient, - private val repository: UserRepository -) : ViewModel() { - - private val disposable = CompositeDisposable() - - private val _dialogEvent = SingleLiveEvent() - val dialogEvent: LiveData - get() = _dialogEvent - - private val _toastEvent = SingleLiveEvent() - val toastEvent: LiveData - get() = _toastEvent - - private val normalMessageList = mutableListOf() - private val pendingMessageList = mutableListOf() - private val _chatUiModelList = MutableLiveData>() - val chatUiModelList: LiveData> - get() = _chatUiModelList - - private lateinit var blackUserList: List - - private val _hasPrevious = MutableLiveData() - val hasPrevious: LiveData - get() = _hasPrevious - - val isLoading = MutableLiveData(false) - - private val _readyToBottomScrollEvent = SingleLiveEvent() - val readyToBottomScrollEvent: LiveData - get() = _readyToBottomScrollEvent - - private var kuringChannel: OpenChannel? = null - - init { - updateBlackUserList() - enterChannel() - addSendbirdHandler() - } - - private fun updateBlackUserList() { - disposable.add( - repository.getBlackUserList() - .subscribeOn(Schedulers.io()) - .subscribe({ - blackUserList = it - }, { - Timber.e("getBlackUserList error $it") - }) - ) - } - - private fun enterChannel() { - val channelUrl = BuildConfig.KURING_CAMPUS_OPEN_CHANNEL_URL - OpenChannel.getChannel(channelUrl) { channel, e1 -> - if (e1 != null) { - Timber.e("Sendbird getChannel error [${e1.code}] : ${e1.message}") - _dialogEvent.postValue(R.string.chat_get_channel_error) - return@getChannel - } - channel?.enter { e2 -> - if (e2 != null) { - Timber.e("Sendbird enterChannel error [${e2.code}] : ${e2.message}") - _dialogEvent.postValue(R.string.chat_enter_channel_error) - return@enter - } - kuringChannel = channel - Timber.e("Sendbird openChannel enter success") - - fetchPreviousMessageList(Long.MAX_VALUE) - } - } - } - - fun sendMessage(text: String) { - if (text.isEmpty()) { - return - } - val params = UserMessageCreateParams(text) - val pendingMessage = kuringChannel?.sendUserMessage(params) { message, e -> - if (e != null) { - Timber.e("Sendbird sendMessage error [${e.code}] : ${e.message}") - updateErrorMessage(message) - return@sendUserMessage - } - updateSucceedMessage(message) - } - _readyToBottomScrollEvent.call() - addPendingMessage(pendingMessage) - } - - fun deletePendingMessage(sentMessageUiModel: SentMessageUiModel) { - pendingMessageList.removeIf { it.requestId == sentMessageUiModel.requestId } - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - - private fun addPendingMessage(message: UserMessage?) { - message?.let { - pendingMessageList.add(it.toSentMessageUiModel(isPending = true)) - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - } - - private fun updateErrorMessage(message: UserMessage?) { - message?.let { msg -> - pendingMessageList.forEachIndexed { index, pendingMessage -> - if (pendingMessage.requestId == msg.requestId) { - pendingMessageList[index] = msg.toSentMessageUiModel(null) - return@forEachIndexed - } - } - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - } - - private fun updateSucceedMessage(message: UserMessage?) { - message?.let { msg -> - pendingMessageList.removeIf { it.requestId == msg.requestId } - normalMessageList.add(msg.toSentMessageUiModel(isPending = false)) - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - } - - fun fetchPreviousMessageList(timeStamp: Long) { - isLoading.value = true - - val params = MessageListParams().apply { - previousResultSize = 100 - } - kuringChannel?.getMessagesByTimestamp(timeStamp, params) { messageList, e -> - if (e != null) { - isLoading.postValue(false) - Timber.e("fetchPreviousMessageList error [${e.code}] : ${e.message}") - return@getMessagesByTimestamp - } - - if (messageList == null) { - isLoading.postValue(false) - Timber.e("fetchPreviousMessageList is null") - return@getMessagesByTimestamp - } - - if (messageList.isEmpty()) { - _hasPrevious.value = false - isLoading.postValue(false) - } else { - _hasPrevious.value = messageList.size >= params.previousResultSize - normalMessageList.addAll(0, messageList.toChatUiModelList(blackUserList)) - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - } - } - - fun fetchLatestMessageList(timeStamp: Long) { - isLoading.value = true - - val params = MessageListParams().apply { - nextResultSize = 100 - } - kuringChannel?.getMessagesByTimestamp(timeStamp, params) { messageList, e -> - if (e != null) { - isLoading.postValue(false) - Timber.e("fetchLatestMessageList error [${e.code}] : ${e.message}") - return@getMessagesByTimestamp - } - - if (messageList.isNullOrEmpty()) { - isLoading.postValue(false) - return@getMessagesByTimestamp - } - - normalMessageList.addAll(messageList.toChatUiModelList(blackUserList)) - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - val hasNext = messageList.size >= params.nextResultSize - if (hasNext) { - fetchLatestMessageList(messageList.last().createdAt) - } - } - } - - private fun addSendbirdHandler() { - SendbirdChat.addConnectionHandler( - CONNECTION_HANDLER_ID, - object : ConnectionHandler { - override fun onConnected(userId: String) { - Timber.e("Sendbird connection connected") - } - - override fun onDisconnected(userId: String) { - Timber.e("Sendbird connection disconnected") - } - - override fun onReconnectFailed() { - Timber.e("Sendbird reconnection failed") - } - - override fun onReconnectStarted() { - Timber.e("Sendbird reconnection started") - } - - override fun onReconnectSucceeded() { - Timber.e("Sendbird reconnection succeed") - - val lastMessageTime = normalMessageList.lastOrNull()?.timeStamp - lastMessageTime?.let { timeStamp -> - fetchLatestMessageList(timeStamp) - } - } - }) - - SendbirdChat.addChannelHandler( - CHANNEL_HANDLER_ID, - object : OpenChannelHandler() { - override fun onMessageReceived(channel: BaseChannel, message: BaseMessage) { - Timber.e("onMessageReceived") - when (message) { - is UserMessage -> normalMessageList.add(message.toReceivedMessageUiModel()) - is AdminMessage -> normalMessageList.add(message.toAdminMessageUiModel()) - } - _chatUiModelList.postValue(normalMessageList + pendingMessageList) - } - } - ) - } - - fun reportMessage(messageUiModel: ReceivedMessageUiModel) { - val reporter = SendbirdChat.currentUser?.userId ?: "" - val feedbackContent = - "🤬 $reporter 가 ${messageUiModel.userId} 를 신고했습니다 - 메세지 내용 : ${messageUiModel.message}" - - // send to Kuring server - disposable.add( - feedbackClient.sendFeedback( - token = pref.fcmToken ?: "", - feedbackRequest = FeedbackRequest(content = feedbackContent), - ) - .subscribeOn(Schedulers.io()) - .subscribe({ - if (it.isSuccess) { - _toastEvent.postValue(R.string.report_success) - } else { - _toastEvent.postValue(R.string.report_fail) - } - }, { - _toastEvent.postValue(R.string.report_error) - }) - ) - - // send to sendbird server - reportToSendbirdServer(messageUiModel) - } - - private fun reportToSendbirdServer(messageUiModel: ReceivedMessageUiModel) { - val params = MessageListParams().apply { - isInclusive = true - previousResultSize = 0 - nextResultSize = 0 - } - kuringChannel?.getMessagesByMessageId(messageUiModel.messageId, params) { messages, e1 -> - if (e1 != null) { - Timber.e("getMessagesByMessageId error [${e1.code}] ${e1.message}") - return@getMessagesByMessageId - } - if (messages?.size == 1) { - kuringChannel?.reportMessage( - message = messages[0], - reportCategory = BaseChannel.ReportCategory.INAPPROPRIATE, - reportDescription = "", - ) { e2 -> - if (e2 != null) { - Timber.e("reportToSendbirdServer error [${e2.code}] : ${e2.message}") - return@reportMessage - } - Timber.e("reportToSendbirdServer success") - } - } - } - } - - fun blockUser(messageUiModel: ReceivedMessageUiModel) { - val userId = messageUiModel.userId - val nickname = messageUiModel.nickname - - disposable.add( - repository.blockUser(userId, nickname) - .subscribeOn(Schedulers.io()) - .subscribe({ - Timber.e("blockUser success") - _toastEvent.postValue(R.string.block_success) - updateBlackUserList() - }, { - Timber.e("blockUser error $it") - _toastEvent.postValue(R.string.block_fail) - }) - ) - } - - override fun onCleared() { - super.onCleared() - SendbirdChat.removeConnectionHandler(CONNECTION_HANDLER_ID) - SendbirdChat.removeChannelHandler(CHANNEL_HANDLER_ID) - - if (!disposable.isDisposed) { - disposable.dispose() - } - } - - companion object { - const val CONNECTION_HANDLER_ID = "KURING_CONNECTION_ID" - const val CHANNEL_HANDLER_ID = "KURING_CHANNEL_ID" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModel.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModel.kt deleted file mode 100644 index 0a698baa3..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModel.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.ui_model - -sealed class ChatUiModel( - open val timeStamp: Long, - open val messageId: Long -) - -data class ReceivedMessageUiModel( - override val timeStamp: Long, - override val messageId: Long, - val userId: String, - val nickname: String, - val message: String -) : ChatUiModel(timeStamp, messageId) - -data class SentMessageUiModel( - override val timeStamp: Long, - override val messageId: Long, - val message: String, - val requestId: String, - val isPending: Boolean? -) : ChatUiModel(timeStamp, messageId) - -data class AdminMessageUiModel( - override val timeStamp: Long, - override val messageId: Long, - val message: String -) : ChatUiModel(timeStamp, messageId) \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModelMapper.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModelMapper.kt deleted file mode 100644 index a5949aae1..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/ui_model/ChatUiModelMapper.kt +++ /dev/null @@ -1,61 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.ui_model - -import com.sendbird.android.SendbirdChat -import com.sendbird.android.message.AdminMessage -import com.sendbird.android.message.BaseMessage -import com.sendbird.android.message.UserMessage -import timber.log.Timber - -fun List.toChatUiModelList(blackUserList: List): List { - val currentUser = SendbirdChat.currentUser - val chatUiModelList = mutableListOf() - - if (currentUser == null) { - Timber.e("currentUser is null!") - } - - for (message in this) { - if (message is AdminMessage) { - chatUiModelList.add(message.toAdminMessageUiModel()) - } else if (message is UserMessage) { - if (message.sender?.userId == currentUser?.userId) { - chatUiModelList.add(message.toSentMessageUiModel(isPending = false)) - } else { - if (!blackUserList.contains(message.sender?.userId)) { - chatUiModelList.add(message.toReceivedMessageUiModel()) - } - } - } else { - Timber.e("message type is strange! ${message.messageId}") - } - } - return chatUiModelList -} - -fun UserMessage.toReceivedMessageUiModel(): ReceivedMessageUiModel { - return ReceivedMessageUiModel( - userId = this.sender?.userId ?: "", - nickname = this.sender?.nickname ?: "", - messageId = this.messageId, - message = this.message, - timeStamp = this.createdAt - ) -} - -fun UserMessage.toSentMessageUiModel(isPending: Boolean?): SentMessageUiModel { - return SentMessageUiModel( - messageId = this.messageId, - message = this.message, - timeStamp = this.createdAt, - requestId = this.requestId, - isPending = isPending - ) -} - -fun AdminMessage.toAdminMessageUiModel(): AdminMessageUiModel { - return AdminMessageUiModel( - messageId = this.messageId, - message = this.message, - timeStamp = this.createdAt - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/AdminViewHolder.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/AdminViewHolder.kt deleted file mode 100644 index c659367c5..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/AdminViewHolder.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.viewholder - -import com.ku_stacks.ku_ring.adapter.visibleIf -import com.ku_stacks.ku_ring.databinding.ItemChatAdminBinding -import com.ku_stacks.ku_ring.ui.chat.ui_model.AdminMessageUiModel - -class AdminViewHolder( - private val binding: ItemChatAdminBinding -) : SealedChatViewHolder(binding.root) { - - fun bind(message: AdminMessageUiModel, showDate: Boolean) { - binding.adminMessageUiModel = message - binding.chatDateTv.visibleIf(showDate) - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/ReceiveViewHolder.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/ReceiveViewHolder.kt deleted file mode 100644 index 90421e73c..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/ReceiveViewHolder.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.viewholder - -import android.graphics.Typeface -import android.text.SpannableStringBuilder -import android.text.Spanned -import android.text.style.BackgroundColorSpan -import android.text.style.StyleSpan -import com.ku_stacks.ku_ring.R -import com.ku_stacks.ku_ring.adapter.visibleIf -import com.ku_stacks.ku_ring.databinding.ItemChatReceiveBinding -import com.ku_stacks.ku_ring.ui.chat.ui_model.ReceivedMessageUiModel -import com.sendbird.android.SendbirdChat - -class ReceiveViewHolder( - private val binding: ItemChatReceiveBinding -) : SealedChatViewHolder(binding.root) { - - fun bind(receivedMessageUiModel: ReceivedMessageUiModel, showDate: Boolean) { - binding.receivedMessageUiModel = receivedMessageUiModel - binding.chatDateTv.visibleIf(showDate) - - binding.chatContentTv.text = spanNickname( - message = receivedMessageUiModel.message, - nickname = SendbirdChat.currentUser?.nickname ?: "" - ) - } - - private fun spanNickname(message: String, nickname: String): SpannableStringBuilder { - val spannableStringBuilder = SpannableStringBuilder(message) - - val nicknameIndexList = getNicknameStartPositionList(message, nickname) - nicknameIndexList.forEach { index -> - spannableStringBuilder.setSpan( - StyleSpan(Typeface.BOLD), - index, - index + nickname.length, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ) - - spannableStringBuilder.setSpan( - BackgroundColorSpan(binding.root.context.getColor(R.color.kus_green_50)), - index, - index + nickname.length, - Spanned.SPAN_EXCLUSIVE_EXCLUSIVE - ) - } - - return spannableStringBuilder - } - - private fun getNicknameStartPositionList(message: String, nickname: String): List { - if (nickname.isEmpty()) { - return emptyList() - } - - val indexList = mutableListOf() - var index = 0 - while (index <= message.length - nickname.length) { - var isNickname = true - nickname.forEachIndexed { i, char -> - if (message[index + i] != char) { - isNickname = false - return@forEachIndexed - } - } - if (isNickname) { - indexList.add(index) - index += nickname.length - } else { - index++ - } - } - return indexList - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SealedChatViewHolder.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SealedChatViewHolder.kt deleted file mode 100644 index 61330a670..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SealedChatViewHolder.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.viewholder - -import android.view.View -import androidx.recyclerview.widget.RecyclerView - -sealed class SealedChatViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SendViewHolder.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SendViewHolder.kt deleted file mode 100644 index bbecf04ad..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/chat/viewholder/SendViewHolder.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.ku_stacks.ku_ring.ui.chat.viewholder - -import com.ku_stacks.ku_ring.adapter.visibleIf -import com.ku_stacks.ku_ring.databinding.ItemChatSendBinding -import com.ku_stacks.ku_ring.ui.chat.ui_model.SentMessageUiModel - -class SendViewHolder( - private val binding: ItemChatSendBinding -) : SealedChatViewHolder(binding.root) { - - fun bind(message: SentMessageUiModel, showDate: Boolean) { - binding.sentMessageUiModel = message - binding.chatDateTv.visibleIf(showDate) - - message.isPending.let { isPending -> - binding.chatTimeTv.visibleIf(isPending == false) - binding.chatSendErrorIv.visibleIf(isPending == null) - binding.chatPendingProgressbar.visibleIf(isPending == true) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/dialogs/ChatActionDialog.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/dialogs/ChatActionDialog.kt deleted file mode 100644 index 3b9f11636..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/dialogs/ChatActionDialog.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.ku_stacks.ku_ring.ui.dialogs - -import android.app.Dialog -import android.content.Context -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import com.ku_stacks.ku_ring.databinding.DialogChatActionBinding - -class ChatActionDialog(context: Context) : Dialog(context) { - - private lateinit var binding: DialogChatActionBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - binding = DialogChatActionBinding.inflate(LayoutInflater.from(context)) - setContentView(binding.root) - } - - fun setOnCopyMessageClickListener(onClickListener: View.OnClickListener) = this.apply { - binding.actionCopyContentTv.setOnClickListener { v -> - onClickListener.onClick(v) - dismiss() - } - } - - fun setOnCopyNicknameClickListener(onClickListener: View.OnClickListener) = this.apply { - binding.actionCopyNicknameTv.setOnClickListener { v -> - onClickListener.onClick(v) - dismiss() - } - } - - fun setOnReportClickListener(onClickListener: View.OnClickListener) = this.apply { - binding.actionReportTv.setOnClickListener { v -> - onClickListener.onClick(v) - dismiss() - } - } - - fun setOnBlockClickListener(onClickListener: View.OnClickListener) = this.apply { - binding.actionBlockTv.setOnClickListener { v -> - onClickListener.onClick(v) - dismiss() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusFragment.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusFragment.kt index 74355152a..e52a9c0bf 100644 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusFragment.kt +++ b/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusFragment.kt @@ -1,26 +1,12 @@ package com.ku_stacks.ku_ring.ui.main.campus_onboarding import android.os.Bundle -import android.text.Editable -import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.activity.result.contract.ActivityResultContracts -import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment -import androidx.fragment.app.viewModels -import com.google.android.gms.auth.api.signin.GoogleSignIn -import com.google.android.gms.auth.api.signin.GoogleSignInOptions -import com.google.android.gms.common.api.ApiException -import com.ku_stacks.ku_ring.R import com.ku_stacks.ku_ring.databinding.FragmentCampusBinding -import com.ku_stacks.ku_ring.navigator.KuringNavigator -import com.ku_stacks.ku_ring.util.PreferenceUtil -import com.ku_stacks.ku_ring.util.makeDialog import dagger.hilt.android.AndroidEntryPoint -import timber.log.Timber -import javax.inject.Inject @AndroidEntryPoint class CampusFragment : Fragment() { @@ -29,34 +15,6 @@ class CampusFragment : Fragment() { private val binding get() = _binding!! - private val viewModel by viewModels() - - @Inject - lateinit var pref: PreferenceUtil - - @Inject - lateinit var navigator: KuringNavigator - - private val loginFinishResult = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - try { - val task = GoogleSignIn.getSignedInAccountFromIntent(it.data) - val account = task.getResult(ApiException::class.java) - Timber.e("account email: ${account.email}") - account.email?.let { userId -> - viewModel.connectToSendbird(userId) {} - changeState(CampusState.SET_NICKNAME_STATE) - } - } catch (e: ApiException) { - Timber.e("signInResult failed [${e.statusCode}]") - requireContext().makeDialog(description = "구글 로그인에 실패하였습니다. [${e.statusCode}]") - } catch (e: Exception) { - Timber.e("signInResult failed : $e") - requireContext().makeDialog(description = "구글 로그인에 실패하였습니다. ${e.message}") - } - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -66,132 +24,6 @@ class CampusFragment : Fragment() { return binding.root } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - setupView() - observeEvent() - } - - private fun setupView() { - val campusUserId = pref.campusUserId - if (campusUserId.isNotEmpty()) { // 저장된 ID 있음 - changeState(CampusState.AUTO_LOGIN_STATE) - - binding.campusAutoLoginLayout.campusNextBt.setOnClickListener { - viewModel.connectToSendbird(campusUserId) { nickname -> - if (nickname != null) { // 닉네임도 있다면 - startChatActivity() - } else { // 닉네임 설정해야한다면 - changeState(CampusState.SET_NICKNAME_STATE) - } - } - } - } else { // 저장된 ID 없음. 처음인 경우 - changeState(CampusState.LOGIN_STATE) - binding.campusLoginLayout.campusGoogleLoginBt.setOnClickListener { - signInGoogle() - } - } - } - - private fun observeEvent() { - viewModel.dialogEvent.observe(viewLifecycleOwner) { - requireContext().makeDialog(description = getString(it)) - } - - viewModel.finishEvent.observe(viewLifecycleOwner) { - startChatActivity() - } - } - - private fun changeState(toNewState: CampusState) { - Timber.e("changeState to $toNewState") - when (toNewState) { - CampusState.LOGIN_STATE -> { - binding.campusLoginLayout.root.visibility = View.VISIBLE - binding.campusSetNicknameLayout.root.visibility = View.GONE - binding.campusAutoLoginLayout.root.visibility = View.GONE - } - - CampusState.SET_NICKNAME_STATE -> { - binding.campusLoginLayout.root.visibility = View.GONE - binding.campusSetNicknameLayout.root.visibility = View.VISIBLE - binding.campusAutoLoginLayout.root.visibility = View.GONE - - binding.campusSetNicknameLayout.nicknameEt.addTextChangedListener(object : - TextWatcher { - override fun beforeTextChanged( - s: CharSequence?, - start: Int, - count: Int, - after: Int - ) = Unit - - override fun onTextChanged( - s: CharSequence?, - start: Int, - before: Int, - count: Int - ) = Unit - - override fun afterTextChanged(s: Editable?) { - val isValidFormat = viewModel.isValidNicknameFormat(s.toString()) - val formatText = if (isValidFormat) { - R.string.nickname_valid_format - } else { - R.string.nickname_not_valid_format - } - val formatTextColor = if (isValidFormat) { - R.color.kus_gray - } else { - R.color.kus_pink - } - - binding.campusSetNicknameLayout.nicknameFormatDescTv.apply { - text = getString(formatText) - setTextColor(ContextCompat.getColor(requireContext(), formatTextColor)) - } - } - }) - - binding.campusSetNicknameLayout.campusNextBt.setOnClickListener { - val nickname = binding.campusSetNicknameLayout.nicknameEt.text.toString() - viewModel.login(nickname) - } - } - - CampusState.AUTO_LOGIN_STATE -> { - binding.campusLoginLayout.root.visibility = View.GONE - binding.campusSetNicknameLayout.root.visibility = View.GONE - binding.campusAutoLoginLayout.root.visibility = View.VISIBLE - } - } - } - - private fun signInGoogle() { - val googleSignInOptions = GoogleSignInOptions - .Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail() - .build() - - val googleSignInClient = - GoogleSignIn.getClient(requireContext().applicationContext, googleSignInOptions) - - val intent = googleSignInClient.signInIntent - loginFinishResult.launch(intent) - } - - private fun startChatActivity() { - changeState(CampusState.AUTO_LOGIN_STATE) - - navigator.navigateToChat(requireActivity()) - requireActivity().overridePendingTransition( - R.anim.anim_slide_right_enter, - R.anim.anim_stay_exit - ) - } - override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusState.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusState.kt deleted file mode 100644 index 6d72dca34..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.ku_stacks.ku_ring.ui.main.campus_onboarding - -enum class CampusState { - LOGIN_STATE, - SET_NICKNAME_STATE, - AUTO_LOGIN_STATE -} diff --git a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusViewModel.kt b/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusViewModel.kt deleted file mode 100644 index a1336ab4b..000000000 --- a/app/src/main/java/com/ku_stacks/ku_ring/ui/main/campus_onboarding/CampusViewModel.kt +++ /dev/null @@ -1,108 +0,0 @@ -package com.ku_stacks.ku_ring.ui.main.campus_onboarding - -import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel -import com.ku_stacks.ku_ring.R -import com.ku_stacks.ku_ring.repository.SendbirdRepository -import com.ku_stacks.ku_ring.ui.SingleLiveEvent -import com.ku_stacks.ku_ring.util.PreferenceUtil -import com.sendbird.android.SendbirdChat -import com.sendbird.android.params.UserUpdateParams -import dagger.hilt.android.lifecycle.HiltViewModel -import io.reactivex.rxjava3.disposables.CompositeDisposable -import timber.log.Timber -import java.util.regex.Pattern -import javax.inject.Inject - -@HiltViewModel -class CampusViewModel @Inject constructor( - private val pref: PreferenceUtil, - private val repository: SendbirdRepository -) : ViewModel() { - - private val disposable = CompositeDisposable() - - private val _dialogEvent = SingleLiveEvent() - val dialogEvent: LiveData - get() = _dialogEvent - - private val _finishEvent = SingleLiveEvent() - val finishEvent: LiveData - get() = _finishEvent - - init { - Timber.e("CampusViewModel init") - } - - fun connectToSendbird(userId: String, nickname: (String?) -> Unit) { - SendbirdChat.connect(userId) { user, e -> - if (e != null) { - Timber.e("Sendbird connect error [${e.code}] : ${e.message}") - _dialogEvent.postValue(R.string.chat_connect_error) - return@connect - } - Timber.e("Sendbird connect success. nickname : ${user?.nickname}") - - pref.campusUserId = userId - nickname(user?.nickname) - } - } - - /* - (?=.{5,15}$) // 5-15 characters long - (?![_.]) // no _ or . at the beginning - (?!.*[_.]{2}) // no __ or _. or ._ or .. inside - [a-zA-Z0-9가-힣._] // allowed characters - (? Unit) { - if (!isValidNicknameFormat(nickname)) { - Timber.e("nickname: $nickname") - _dialogEvent.postValue(R.string.nickname_not_valid_format) - return - } - - val userId = pref.campusUserId - - disposable.add( - repository.hasDuplicateNickname(nickname, userId) - .subscribe({ - if (!it) { - isAuthorized() - } else { - _dialogEvent.postValue(R.string.nickname_duplicated) - } - }, { - Timber.e("authorizeNickname error : $it") - _dialogEvent.postValue(R.string.nickname_check_error) - }) - ) - } - - private fun setNickname(nickname: String, isDone: () -> Unit) { - val params = UserUpdateParams() - .setNickname(nickname) - - SendbirdChat.updateCurrentUserInfo(params) { e -> - if (e != null) { - Timber.e("updateCurrentUserInfo error [${e.code} : ${e.message}]") - return@updateCurrentUserInfo - } - Timber.e("updateCurrentUserInfo success") - isDone() - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_chat.xml b/app/src/main/res/layout/activity_chat.xml deleted file mode 100644 index a9480fa28..000000000 --- a/app/src/main/res/layout/activity_chat.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/campus_auto_login.xml b/app/src/main/res/layout/campus_auto_login.xml deleted file mode 100644 index 4847be5d4..000000000 --- a/app/src/main/res/layout/campus_auto_login.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - -