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

Init UiState for activity type filter screen #13439

Merged
merged 17 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -2,11 +2,11 @@ package org.wordpress.android.ui.activitylog.list.filter

import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView.Adapter
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ItemUiState
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ListItemUiState
import org.wordpress.android.ui.utils.UiHelpers

class ActivityLogTypeFilterAdapter(private val uiHelpers: UiHelpers) : Adapter<ActivityLogTypeFilterViewHolder>() {
private val items = mutableListOf<ItemUiState>()
private val items = mutableListOf<ListItemUiState>()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ActivityLogTypeFilterViewHolder {
return ActivityLogTypeFilterViewHolder(parent, uiHelpers)
Expand All @@ -18,7 +18,7 @@ class ActivityLogTypeFilterAdapter(private val uiHelpers: UiHelpers) : Adapter<A

override fun getItemCount(): Int = items.size

fun update(newItems: List<ItemUiState>) {
fun update(newItems: List<ListItemUiState>) {
items.clear()
items.addAll(newItems)
notifyDataSetChanged()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.wordpress.android.R
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ItemUiState
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ListItemUiState
import org.wordpress.android.ui.utils.UiHelpers

class ActivityLogTypeFilterViewHolder(
Expand All @@ -13,6 +13,6 @@ class ActivityLogTypeFilterViewHolder(
) : RecyclerView.ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.activity_log_type_filter_item, parent, false)
) {
fun onBind(uiState: ItemUiState) {
fun onBind(uiState: ListItemUiState) {
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,118 @@
package org.wordpress.android.ui.activitylog.list.filter

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.wordpress.android.R
import org.wordpress.android.modules.BG_THREAD
import org.wordpress.android.modules.UI_THREAD
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ListItemUiState.SectionHeader
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.UiState.Content
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.UiState.FullscreenLoading
import org.wordpress.android.ui.utils.UiString
import org.wordpress.android.ui.utils.UiString.UiStringRes
import org.wordpress.android.ui.utils.UiString.UiStringText
import org.wordpress.android.viewmodel.ScopedViewModel
import javax.inject.Inject
import javax.inject.Named

class ActivityLogTypeFilterViewModel @Inject constructor(
@Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
@Named(UI_THREAD) private val mainDispatcher: CoroutineDispatcher
) : ScopedViewModel(mainDispatcher) {
private var isStarted = false

private val _uiState = MutableLiveData<UiState>()
val uiState: LiveData<UiState> = _uiState

fun start() {
if (isStarted) return
isStarted = true

_uiState.value = FullscreenLoading
fetchAvailableActivityTypes()
}

private fun fetchAvailableActivityTypes() {
launch {
// TODO malinjir initiate the fetch
onActivityTypesFetched(listOf(DummyActivityType, DummyActivityType, DummyActivityType))
}
}

private suspend fun onActivityTypesFetched(activityTypes: List<DummyActivityType>) {
_uiState.value = buildContentUiState(activityTypes)
}

private suspend fun buildContentUiState(activityTypes: List<DummyActivityType>): Content {
return withContext(bgDispatcher) {
// TODO malinjir replace the hardcoded header title
val headerListItem = SectionHeader(UiStringText("Test"))
// TODO malinjir replace "it.toString()" with activity type name
val activityTypeListItems: List<ListItemUiState.ActivityType> = activityTypes
.map { ListItemUiState.ActivityType(title = UiStringText(it.toString())) }
Content(
listOf(headerListItem) + activityTypeListItems,
primaryAction = Action(label = UiStringRes(R.string.activity_log_activity_type_filter_apply))
.apply { action = ::onApplyClicked },
secondaryAction = Action(label = UiStringRes(R.string.activity_log_activity_type_filter_clear))
.apply { action = ::onClearClicked }
)
}
}

private fun onApplyClicked() {
// TODO malinjir save and dismiss
}

private fun onClearClicked() {
(_uiState.value as? Content)?.let { it ->
_uiState.value = it.copy(items = getAllActivityTypeItemsUnchecked(it.items))
}
}

private fun getAllActivityTypeItemsUnchecked(listItemUiStates: List<ListItemUiState>): List<ListItemUiState> =
listItemUiStates.map { item ->
if (item is ListItemUiState.ActivityType) {
item.copy(checked = false)
} else {
item
}
}

sealed class UiState {
open val contentVisibility = false
open val loadingVisibility = false

object FullscreenLoading : UiState() {
override val loadingVisibility: Boolean = true
}

data class Content(
val items: List<ListItemUiState>,
val primaryAction: Action,
val secondaryAction: Action
) : UiState() {
override val contentVisibility = true
}
}

sealed class ListItemUiState {
ParaskP7 marked this conversation as resolved.
Show resolved Hide resolved
data class SectionHeader(
val title: UiString
) : ListItemUiState()

data class ActivityType(
val title: UiString,
val checked: Boolean = false
) : ListItemUiState()
}

data class Action(val label: UiString) {
var action: (() -> Unit)? = null
}

object ItemUiState
object DummyActivityType
}
2 changes: 2 additions & 0 deletions WordPress/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,8 @@
<string name="activity_log_rewind_site">Rewind Site</string>
<string name="activity_log_rewind_dialog_message">Are you sure you want to rewind your site back to %1$s at %2$s? This will remove all content and options created or changed since then.</string>
<string name="activity_log_limited_content_on_free_plan">Since you\'re on a free plan, you\'ll see limited events in your activity.</string>
<string name="activity_log_activity_type_filter_apply">Apply</string>
<string name="activity_log_activity_type_filter_clear">Clear</string>

<!-- scan -->
<string name="scan">Scan</string>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,51 @@
package org.wordpress.android.ui.activitylog.list.filter
ParaskP7 marked this conversation as resolved.
Show resolved Hide resolved

import kotlinx.coroutines.InternalCoroutinesApi
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
import org.junit.Test
import org.wordpress.android.BaseUnitTest
import org.wordpress.android.TEST_DISPATCHER
import org.wordpress.android.test
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.ListItemUiState
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.UiState
import org.wordpress.android.ui.activitylog.list.filter.ActivityLogTypeFilterViewModel.UiState.Content

@InternalCoroutinesApi
class ActivityLogTypeFilterViewModelTest : BaseUnitTest() {
private lateinit var viewModel: ActivityLogTypeFilterViewModel

@Before
fun setUp() {
viewModel = ActivityLogTypeFilterViewModel(TEST_DISPATCHER)
viewModel = ActivityLogTypeFilterViewModel(TEST_DISPATCHER, TEST_DISPATCHER)
}

@Test
fun `skeleton test`() {
// Skeleton test.
fun `fullscreen loading shown, when screen initialized`() = test {
val uiStates = initObservers().uiStates

viewModel.start()

assertThat(uiStates[0]).isInstanceOf(UiState.FullscreenLoading::class.java)
}

@Test
fun `section header gets added as first item in the list, when content shown`() {
initObservers()

viewModel.start()

assertThat((viewModel.uiState.value as Content).items[0])
.isInstanceOf(ListItemUiState.SectionHeader::class.java)
}

private fun initObservers(): Observers {
val uiStates = mutableListOf<UiState>()
viewModel.uiState.observeForever {
uiStates.add(it)
}
return Observers((uiStates))
}

private data class Observers(val uiStates: List<UiState>)
}