From 9f06df569bcdff5dc3182aa02f62b4a0bb5694e9 Mon Sep 17 00:00:00 2001 From: Taras <tarassmakula@gmail.com> Date: Thu, 3 Mar 2022 14:25:48 +0200 Subject: [PATCH] Add success/error handling for invites --- .../circles/extensions/FragmentExtensions.kt | 49 ++++++++++++------- .../InviteMembersDialogFragment.kt | 22 +++++++-- .../group_invite/InviteMembersViewModel.kt | 8 +++ app/src/main/res/drawable/ic_error.xml | 5 ++ .../main/res/layout/error_snack_bar_view.xml | 12 +++-- .../res/layout/success_snack_bar_view.xml | 44 +++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 7 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 app/src/main/res/drawable/ic_error.xml create mode 100644 app/src/main/res/layout/success_snack_bar_view.xml diff --git a/app/src/main/java/com/futo/circles/extensions/FragmentExtensions.kt b/app/src/main/java/com/futo/circles/extensions/FragmentExtensions.kt index a6defc9a7..fed2da545 100644 --- a/app/src/main/java/com/futo/circles/extensions/FragmentExtensions.kt +++ b/app/src/main/java/com/futo/circles/extensions/FragmentExtensions.kt @@ -15,26 +15,37 @@ import com.google.android.material.snackbar.Snackbar @SuppressLint("InflateParams") -fun Fragment.showError(message: String) { - view?.let { - val snack: Snackbar = Snackbar.make(it, message, Snackbar.LENGTH_LONG) - val customSnackView = layoutInflater.inflate(R.layout.error_snack_bar_view, null) - snack.view.setBackgroundColor(Color.TRANSPARENT) - - val snackLayout = snack.view as Snackbar.SnackbarLayout - snackLayout.setPadding(0, 0, 0, 0) - - customSnackView.findViewById<TextView>(R.id.tvErrorMessage).also { textView -> - textView.text = message - } - snackLayout.addView(customSnackView, 0) - - val layoutParams = (snack.view.layoutParams as? FrameLayout.LayoutParams)?.also { params -> - params.gravity = Gravity.TOP - } - snack.view.layoutParams = layoutParams - snack.show() +private fun Fragment.showBar(message: String, isError: Boolean, showOnActivity: Boolean) { + val parentView = if (showOnActivity) activity?.findViewById(android.R.id.content) else view + parentView ?: return + + val snack: Snackbar = Snackbar.make(parentView, message, Snackbar.LENGTH_LONG) + snack.view.setBackgroundColor(Color.TRANSPARENT) + + val snackLayout = snack.view as Snackbar.SnackbarLayout + snackLayout.setPadding(0, 0, 0, 0) + + val customSnackView = layoutInflater.inflate( + if (isError) R.layout.error_snack_bar_view else R.layout.success_snack_bar_view, + null + ).apply { + findViewById<TextView>(R.id.tvMessage)?.text = message + } + snackLayout.addView(customSnackView, 0) + + val layoutParams = (snack.view.layoutParams as? FrameLayout.LayoutParams)?.also { params -> + params.gravity = Gravity.TOP } + snack.view.layoutParams = layoutParams + snack.show() +} + +fun Fragment.showError(message: String, showOnActivity: Boolean = false) { + showBar(message, true, showOnActivity) +} + +fun Fragment.showSuccess(message: String, showOnActivity: Boolean = false) { + showBar(message, false, showOnActivity) } fun Fragment.setEnabledViews(enabled: Boolean) { diff --git a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt index d3d8587d8..37bfee48e 100644 --- a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt +++ b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersDialogFragment.kt @@ -6,9 +6,7 @@ import androidx.navigation.fragment.navArgs import com.futo.circles.R import com.futo.circles.base.BaseFullscreenDialogFragment import com.futo.circles.databinding.InviteMembersDialogFragmentBinding -import com.futo.circles.extensions.getQueryTextChangeStateFlow -import com.futo.circles.extensions.observeData -import com.futo.circles.extensions.setVisibility +import com.futo.circles.extensions.* import com.futo.circles.feature.group_invite.list.search.InviteMembersSearchListAdapter import com.futo.circles.feature.group_invite.list.selected.SelectedUsersListAdapter import org.koin.androidx.viewmodel.ext.android.viewModel @@ -39,6 +37,10 @@ class InviteMembersDialogFragment : binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() } setupLists() setupObservers() + binding.btnInvite.setOnClickWithLoading { + viewModel.invite() + setLoadingState(true) + } } private fun setupLists() { @@ -58,6 +60,20 @@ class InviteMembersDialogFragment : viewModel.selectedUsersLiveData.observeData(this) { items -> selectedUsersListAdapter.submitList(items) binding.selectedUserDivider.setVisibility(items.isNotEmpty()) + binding.btnInvite.setButtonEnabled(items.isNotEmpty()) } + viewModel.inviteResultLiveData.observeResponse(this, + success = { + showSuccess(getString(R.string.invitation_sent), true) + activity?.onBackPressed() + }, + error = { message -> showError(message) }, + onRequestInvoked = { setLoadingState(false) } + ) + } + + private fun setLoadingState(isLoading: Boolean) { + setEnabledViews(!isLoading) + binding.btnInvite.setIsLoading(isLoading) } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt index 2597b2fbf..fe1dd8106 100644 --- a/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt +++ b/app/src/main/java/com/futo/circles/feature/group_invite/InviteMembersViewModel.kt @@ -3,6 +3,8 @@ package com.futo.circles.feature.group_invite import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData +import com.futo.circles.extensions.Response +import com.futo.circles.extensions.launchBg import com.futo.circles.extensions.launchUi import com.futo.circles.feature.group_invite.data_source.InviteMembersDataSource import com.futo.circles.model.CirclesUser @@ -19,6 +21,8 @@ class InviteMembersViewModel( val selectedUsersLiveData = dataSource.selectedUsersFlow.asLiveData() + val inviteResultLiveData = MutableLiveData<Response<Unit>>() + fun initSearchListener(queryFlow: StateFlow<String>) { launchUi { queryFlow @@ -33,4 +37,8 @@ class InviteMembersViewModel( dataSource.toggleUserSelect(user) } + fun invite() { + launchBg { inviteResultLiveData.postValue(dataSource.inviteUsers(this)) } + } + } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_error.xml b/app/src/main/res/drawable/ic_error.xml new file mode 100644 index 000000000..3c9a4b352 --- /dev/null +++ b/app/src/main/res/drawable/ic_error.xml @@ -0,0 +1,5 @@ +<vector android:height="24dp" android:tint="#FFFFFF" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/white" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/> +</vector> diff --git a/app/src/main/res/layout/error_snack_bar_view.xml b/app/src/main/res/layout/error_snack_bar_view.xml index 06992b481..45d2e0986 100644 --- a/app/src/main/res/layout/error_snack_bar_view.xml +++ b/app/src/main/res/layout/error_snack_bar_view.xml @@ -2,6 +2,7 @@ <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/tooltipCard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="16dp" @@ -14,16 +15,16 @@ android:padding="8dp"> <ImageView - android:id="@+id/ivError" + android:id="@+id/ivIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@android:drawable/stat_notify_error" + android:src="@drawable/ic_error" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView - android:id="@+id/tvErrorMessage" + android:id="@+id/tvMessage" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" @@ -32,10 +33,11 @@ android:textColor="@color/white" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toEndOf="@id/ivError" + app:layout_constraintStart_toEndOf="@id/ivIcon" app:layout_constraintTop_toTopOf="parent" tools:text="asdasdasdasdadsaasdsadasdasdasdasasdasdasdasdasasdsdasddasdasdasdasdadssdasdadsasdadasddas" /> </androidx.constraintlayout.widget.ConstraintLayout> -</androidx.cardview.widget.CardView> \ No newline at end of file +</androidx.cardview.widget.CardView> + diff --git a/app/src/main/res/layout/success_snack_bar_view.xml b/app/src/main/res/layout/success_snack_bar_view.xml new file mode 100644 index 000000000..d1d1e6aa9 --- /dev/null +++ b/app/src/main/res/layout/success_snack_bar_view.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/tooltipCard" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_margin="16dp" + app:cardBackgroundColor="@color/blue" + app:cardCornerRadius="8dp"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="8dp"> + + <ImageView + android:id="@+id/ivIcon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/ic_check_circle" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:tint="@color/white" /> + + <TextView + android:id="@+id/tvMessage" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:ellipsize="end" + android:maxLines="2" + android:textColor="@color/white" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@id/ivIcon" + app:layout_constraintTop_toTopOf="parent" + tools:text="asdasdasdasdadsaasdsadasdasdasdasasdasdasdasdasasdsdasddasdasdasdasdadssdasdadsasdadasddas" /> + + </androidx.constraintlayout.widget.ConstraintLayout> + +</androidx.cardview.widget.CardView> + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ab747ba9b..29d3e5f92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,6 +33,7 @@ <string name="suggestion">Suggestions</string> <string name="no_results">No results</string> <string name="invite">Invite</string> + <string name="invitation_sent">Invitation sent</string> <plurals name="member_plurals"> <item quantity="one">%d member</item> -- GitLab