Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Modal Layout Picker] Retry view #13159

Merged
merged 45 commits into from
Oct 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c201d76
Requests scaled thumbnail images
Oct 7, 2020
01b7f8a
Merge branch 'issue/2452-Preview' into issue/2445-ScaledThumb
Oct 8, 2020
3cfbbd9
Shows message after creating a new page
Oct 8, 2020
d32bf8a
Merge branch 'issue/2452-Preview' into issue/2445-ScaledThumb
Oct 9, 2020
d0b0245
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 9, 2020
85289e2
Removed deprecated tests related to title visibility in landscape mode
Oct 9, 2020
7a1c8b3
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 9, 2020
61e1620
Updates tests broken after merge
Oct 9, 2020
1acae0f
Fixes landscape xml issue
Oct 9, 2020
88bffa7
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 9, 2020
99427fe
Adds analytics for template preview and apply
Oct 9, 2020
c24a506
Moved analytics to the editor
Oct 9, 2020
cf4b09b
Removes unused import
Oct 9, 2020
6c85c8f
Prevents VM on rotation
Oct 12, 2020
94f60e7
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 12, 2020
4af9c97
Merge branch 'issue/2453-NewPageToast' into issue/2454-MLP_Analytics
Oct 12, 2020
06d0f26
Allows creation of blank page in offline / loading mode
Oct 12, 2020
1c3f941
Sets page title according to the selected template
Oct 12, 2020
5b75ddd
Merge branch 'issue/2452-Preview' into issue/2445-ScaledThumb
Oct 13, 2020
bc53c64
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 13, 2020
40528bf
Merge branch 'issue/2453-NewPageToast' into issue/2454-MLP_Analytics
Oct 13, 2020
9886321
Merge branch 'issue/2454-MLP_Analytics' into issue/2456-Cache
Oct 13, 2020
f422eb0
Updates FluxC reference
Oct 14, 2020
a8a61ba
Minor optimisation in layout selection handling
Oct 14, 2020
de5ee7f
Removed unused import
Oct 14, 2020
ded2a9a
Adjusted title visibility threshold and added fade animation
Oct 15, 2020
b7c5a92
Merge branch 'develop' into issue/2445-ScaledThumb
Oct 16, 2020
f2e3a23
Merge branch 'issue/2445-ScaledThumb' into issue/2453-NewPageToast
Oct 16, 2020
80ba44f
Prevents new page message from showing when reopening local drafts
Oct 16, 2020
ece4b82
Merge branch 'issue/2453-NewPageToast' into issue/2454-MLP_Analytics
Oct 16, 2020
0812184
Mutes unneeded analytics in editor preview mode
Oct 16, 2020
94d71e9
Updated FluxC reference
Oct 16, 2020
2537de9
Shows the default empty view when no data can be loaded
Oct 16, 2020
8916f73
Merge branch 'develop' into issue/2454-MLP_Analytics
Oct 16, 2020
8aed243
Merge branch 'issue/2454-MLP_Analytics' into issue/2456-Cache
Oct 16, 2020
4d6a3fc
Merge branch 'issue/2456-Cache' into issue/MLP_RetryView
Oct 16, 2020
552c979
Shows toast on error state
Oct 16, 2020
d2b1110
Moves error view below recycler view to tackle scroll issues
Oct 16, 2020
0b9bc48
Merge branch 'issue/2456-Cache' into issue/MLP_RetryView
Oct 16, 2020
2a5e711
Merge branch 'develop' into issue/MLP_RetryView
Oct 16, 2020
a38cb55
Merge branch 'develop' into issue/MLP_RetryView
Oct 19, 2020
5b9ff44
Handles error state on resume
Oct 19, 2020
3239d4a
MLP Error view design improvements
Oct 20, 2020
ea6cf86
Sets create blank page button visible in loading state
Oct 20, 2020
3535abd
Merge branch 'develop' into issue/MLP_RetryView
Oct 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ package org.wordpress.android.ui.mlp
* The buttons visibility state
*/
data class ButtonsUiState(
val createBlankPageVisible: Boolean,
val createPageVisible: Boolean,
val previewVisible: Boolean
val createBlankPageVisible: Boolean = true,
val createPageVisible: Boolean = false,
val previewVisible: Boolean = false,
val retryVisible: Boolean = false
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ data class GutenbergPageLayouts(
val layouts: List<GutenbergLayout> = listOf(),
val categories: List<GutenbergLayoutCategory> = listOf()
) : Parcelable {
val isNotEmpty: Boolean
get() = layouts.isNotEmpty() || categories.isNotEmpty()
val isEmpty: Boolean
get() = layouts.isEmpty() || categories.isEmpty()
fun getFilteredLayouts(categorySlug: String) =
layouts.filter { l -> l.categories.any { c -> c.slug == categorySlug } }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.android.synthetic.main.modal_layout_picker_bottom_toolbar.*
import kotlinx.android.synthetic.main.modal_layout_picker_categories_skeleton.*
import kotlinx.android.synthetic.main.modal_layout_picker_error.*
import kotlinx.android.synthetic.main.modal_layout_picker_fragment.*
import kotlinx.android.synthetic.main.modal_layout_picker_layouts_skeleton.*
import kotlinx.android.synthetic.main.modal_layout_picker_subtitle_row.*
import kotlinx.android.synthetic.main.modal_layout_picker_title_row.*
import kotlinx.android.synthetic.main.modal_layout_picker_titlebar.*
import org.wordpress.android.R
Expand All @@ -33,8 +35,6 @@ import org.wordpress.android.ui.utils.UiHelpers
import org.wordpress.android.util.AniUtils
import org.wordpress.android.util.AniUtils.Duration
import org.wordpress.android.util.DisplayUtils
import org.wordpress.android.util.ToastUtils
import org.wordpress.android.util.ToastUtils.Duration.SHORT
import org.wordpress.android.util.setVisible
import org.wordpress.android.viewmodel.mlp.ModalLayoutPickerViewModel
import org.wordpress.android.viewmodel.mlp.ModalLayoutPickerViewModel.UiState.ContentUiState
Expand Down Expand Up @@ -97,6 +97,9 @@ class ModalLayoutPickerFragment : BottomSheetDialogFragment() {
previewButton.setOnClickListener {
viewModel.onPreviewPageClicked()
}
retryButton.setOnClickListener {
viewModel.onRetryClicked()
}

setScrollListener()

Expand Down Expand Up @@ -126,6 +129,14 @@ class ModalLayoutPickerFragment : BottomSheetDialogFragment() {
}
}

/**
* Sets the header description visibility
* @param visible if true the description is visible else invisible
*/
private fun setDescriptionVisibility(visible: Boolean) {
description?.visibility = if (visible) View.VISIBLE else View.INVISIBLE
}

override fun onCreateDialog(savedInstanceState: Bundle?) = BottomSheetDialog(requireContext(), getTheme()).apply {
fillTheScreen(this)
window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
Expand Down Expand Up @@ -171,22 +182,20 @@ class ModalLayoutPickerFragment : BottomSheetDialogFragment() {
loadSavedState(savedInstanceState)

viewModel.uiState.observe(this, Observer { uiState ->
setTitleVisibility(uiState.isHeaderVisible)
setDescriptionVisibility(uiState.isDescriptionVisible)
setButtonsVisibility(uiState.buttonsUiState)
setContentVisibility(uiState.loadingSkeletonVisible, uiState.errorViewVisible)
when (uiState) {
is LoadingUiState -> {
setTitleVisibility(uiState.isHeaderVisible)
showLoadingSkeleton(uiState.loadingSkeletonVisible)
}
is ContentUiState -> {
(categoriesRecyclerView.adapter as CategoriesAdapter).setData(uiState.categories)
(layoutsRecyclerView?.adapter as? LayoutCategoryAdapter)?.update(uiState.layoutCategories)
setButtonsVisibility(uiState.buttonsUiState)
setTitleVisibility(uiState.isHeaderVisible)
showLoadingSkeleton(uiState.loadingSkeletonVisible)
}
is ErrorUiState -> {
setTitleVisibility(uiState.isHeaderVisible)
showLoadingSkeleton(uiState.loadingSkeletonVisible)
ToastUtils.showToast(activity, uiState.message, SHORT)
actionableEmptyView.title.setText(uiState.title)
actionableEmptyView.subtitle.setText(uiState.subtitle)
}
}
})
Expand All @@ -202,17 +211,20 @@ class ModalLayoutPickerFragment : BottomSheetDialogFragment() {
})
}

private fun showLoadingSkeleton(skeleton: Boolean) {
private fun setContentVisibility(skeleton: Boolean, error: Boolean) {
categoriesSkeleton.setVisible(skeleton)
categoriesRecyclerView.setVisible(!skeleton)
categoriesRecyclerView.setVisible(!skeleton && !error)
layoutsSkeleton.setVisible(skeleton)
layoutsRecyclerView.setVisible(!skeleton)
layoutsRecyclerView.setVisible(!skeleton && !error)
errorLayout.setVisible(error)
}

private fun setButtonsVisibility(uiState: ButtonsUiState) {
createBlankPageButton.setVisible(uiState.createBlankPageVisible)
createPageButton.setVisible(uiState.createPageVisible)
previewButton.setVisible(uiState.previewVisible)
retryButton.setVisible(uiState.retryVisible)
createOrRetryContainer.setVisible(uiState.createBlankPageVisible || uiState.retryVisible)
}

private fun fillTheScreen(dialog: BottomSheetDialog) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,7 @@ class ModalLayoutPickerViewModel @Inject constructor(
@Subscribe(threadMode = ThreadMode.MAIN)
fun onBlockLayoutsFetched(event: OnBlockLayoutsFetched) {
if (event.isError) {
if (networkUtils.isNetworkAvailable()) {
updateUiState(ErrorUiState(string.mlp_generic_error))
} else {
updateUiState(ErrorUiState(string.no_network_message))
}
setErrorState()
} else {
handleBlockLayoutsResponse(GutenbergPageLayouts(event.layouts, event.categories))
}
Expand All @@ -124,6 +120,14 @@ class ModalLayoutPickerViewModel @Inject constructor(
loadCategories()
}

private fun setErrorState() {
if (networkUtils.isNetworkAvailable()) {
updateUiState(ErrorUiState(string.mlp_error_title, string.mlp_error_subtitle))
} else {
updateUiState(ErrorUiState(string.mlp_network_error_title, string.mlp_network_error_subtitle))
}
}

private fun loadLayouts() {
val state = uiState.value as? ContentUiState ?: ContentUiState()
launch(bgDispatcher) {
Expand Down Expand Up @@ -183,6 +187,15 @@ class ModalLayoutPickerViewModel @Inject constructor(
fetchLayouts()
}

/**
* Retries data fetching
*/
fun onRetryClicked() {
if (networkUtils.isNetworkAvailable()) {
fetchLayouts()
}
}

/**
* Dismisses the MLP
*/
Expand Down Expand Up @@ -308,20 +321,23 @@ class ModalLayoutPickerViewModel @Inject constructor(
}

fun loadSavedState(layouts: GutenbergPageLayouts?, selectedLayout: String?, selectedCategories: List<String>?) {
if (layouts == null) {
if (layouts == null || layouts.isEmpty) {
setErrorState()
return
}
val categories = ArrayList(selectedCategories ?: listOf())
val state = uiState.value as? ContentUiState ?: ContentUiState()
val categories = ArrayList(selectedCategories ?: listOf())
updateUiState(state.copy(selectedLayoutSlug = selectedLayout, selectedCategoriesSlugs = categories))
updateButtonsUiState()
handleBlockLayoutsResponse(layouts)
}

sealed class UiState(
open val isHeaderVisible: Boolean = false,
val isDescriptionVisible: Boolean = true,
val loadingSkeletonVisible: Boolean = false,
open val errorViewVisible: Boolean = false
val errorViewVisible: Boolean = false,
open val buttonsUiState: ButtonsUiState = ButtonsUiState()
) {
object LoadingUiState : UiState(loadingSkeletonVisible = true)

Expand All @@ -332,13 +348,14 @@ class ModalLayoutPickerViewModel @Inject constructor(
val loadedThumbnailSlugs: ArrayList<String> = arrayListOf(),
val categories: List<CategoryListItemUiState> = listOf(),
val layoutCategories: List<LayoutCategoryUiState> = listOf(),
val buttonsUiState: ButtonsUiState = ButtonsUiState(
createBlankPageVisible = true,
previewVisible = false,
createPageVisible = false
)
override val buttonsUiState: ButtonsUiState = ButtonsUiState()
) : UiState()

data class ErrorUiState(@StringRes val message: Int) : UiState(errorViewVisible = true)
data class ErrorUiState(@StringRes val title: Int, @StringRes val subtitle: Int) : UiState(
errorViewVisible = true,
isHeaderVisible = true,
isDescriptionVisible = false,
buttonsUiState = ButtonsUiState(retryVisible = true)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,32 @@
android:paddingBottom="@dimen/mlp_bottom_button_vertical_margin"
android:paddingTop="@dimen/mlp_bottom_button_vertical_margin">

<com.google.android.material.button.MaterialButton
android:id="@+id/createBlankPageButton"
style="@style/Widget.ModalLayoutPicker.Button.Secondary"
<LinearLayout
android:id="@+id/createOrRetryContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/mlp_bottom_button_horizontal_margin"
android:layout_marginStart="@dimen/mlp_bottom_button_horizontal_margin"
android:layout_weight="1"
android:text="@string/mlp_create_blank_page" />
android:orientation="vertical"
android:visibility="gone">

<com.google.android.material.button.MaterialButton
android:id="@+id/retryButton"
style="@style/Widget.ModalLayoutPicker.Button.Primary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_retry"
android:visibility="gone" />

<com.google.android.material.button.MaterialButton
android:id="@+id/createBlankPageButton"
style="@style/Widget.ModalLayoutPicker.Button.Secondary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/mlp_create_blank_page"
android:visibility="gone" />
</LinearLayout>

<com.google.android.material.button.MaterialButton
android:id="@+id/previewButton"
Expand Down
17 changes: 17 additions & 0 deletions WordPress/src/main/res/layout/modal_layout_picker_error.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/errorLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/mlp_layouts_row_height"
android:background="?attr/categoriesBackground">

<org.wordpress.android.ui.ActionableEmptyView
android:id="@+id/actionableEmptyView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:aevImage="@drawable/img_illustration_empty_results_216dp"
app:aevImageHiddenInLandscape="true"
app:aevSubtitle="@string/mlp_error_subtitle"
app:aevTitle="@string/mlp_error_title" />
</FrameLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<include
layout="@layout/modal_layout_picker_error"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
android:layout_width="match_parent">

<TextView
android:id="@+id/description"
style="@style/ModalLayoutPickerSubtitle"
android:text="@string/mlp_choose_layout_subtitle" />

Expand Down
5 changes: 4 additions & 1 deletion WordPress/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2898,7 +2898,10 @@
<string name="mlp_notselected_description">%s</string>
<string name="mlp_notice_page_created">Page created</string>
<string name="mlp_notice_blank_page_created">Blank page created</string>
<string name="mlp_generic_error">An error occurred while fetching the layouts</string>
<string name="mlp_error_title">Layouts not available due to an error</string>
<string name="mlp_error_subtitle">Tap retry or create a blank page using the button below.</string>
<string name="mlp_network_error_title">Layouts not available while offline</string>
<string name="mlp_network_error_subtitle">Tap retry when you\'re back online or create a blank page using the button below.</string>

<string name="capture_button_alt">Capture</string>
<string name="flip_button_alt">Flip camera</string>
Expand Down