Skip to content
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
@@ -0,0 +1,53 @@
package com.woocommerce.android.ui.bookings.filter

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.woocommerce.android.ui.base.BaseFragment
import com.woocommerce.android.ui.compose.composeView
import com.woocommerce.android.ui.main.AppBarStatus
import com.woocommerce.android.viewmodel.MultiLiveEvent
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class BookingFilterListFragment : BaseFragment() {
override val activityAppBarStatus: AppBarStatus
get() = AppBarStatus.Hidden

private val viewModel: BookingFilterListViewModel by viewModels()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return composeView {
val uiState by viewModel.uiState.observeAsState()
uiState?.let { state ->
BookingFilterListScreen(
state = state,
)
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
handleEvents()
}

private fun handleEvents() {
viewModel.event.observe(viewLifecycleOwner) { event ->
when (event) {
is MultiLiveEvent.Event.Exit -> {
findNavController().popBackStack()
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package com.woocommerce.android.ui.bookings.filter

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import com.woocommerce.android.R
import com.woocommerce.android.ui.bookings.filter.BookingFilterListViewModel.BookingFilterListItem
import com.woocommerce.android.ui.bookings.filter.BookingFilterListViewModel.BookingFilterListUiState
import com.woocommerce.android.ui.compose.component.Toolbar
import com.woocommerce.android.ui.compose.component.WCColoredButton
import com.woocommerce.android.ui.compose.component.WCListItemWithInlineSubtitle
import com.woocommerce.android.ui.compose.preview.LightDarkThemePreviews
import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground

@Composable
fun BookingFilterListScreen(state: BookingFilterListUiState) {
Scaffold(
topBar = {
Column {
Toolbar(
title = stringResource(id = R.string.bookings_filters_default_title),
onNavigationButtonClick = state.onClose,
navigationIcon = ImageVector.vectorResource(id = R.drawable.ic_gridicons_cross_24dp)
)
HorizontalDivider(thickness = 0.5.dp)
}
},
bottomBar = {
Column(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.surfaceContainerLow)
) {
HorizontalDivider(thickness = 0.5.dp)
WCColoredButton(
onClick = state.onShowBookings,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp),
) {
Text(stringResource(id = R.string.bookings_filters_show_bookings))
}
}
},
containerColor = MaterialTheme.colorScheme.surface,
) { innerPadding ->
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
items(state.items) { item -> BookingFilterListRow(item) }
}
}
}

@Composable
private fun BookingFilterListRow(item: BookingFilterListItem) {
Column(modifier = Modifier.fillMaxWidth()) {
WCListItemWithInlineSubtitle(
text = stringResource(item.title),
subtitle = item.value ?: stringResource(id = R.string.bookings_filter_default),
modifier = Modifier
.defaultMinSize(minHeight = 64.dp)
.clickable { item.onClick() }
.padding(vertical = 8.dp)
)
HorizontalDivider(thickness = 0.5.dp)
}
}

@LightDarkThemePreviews
@Composable
private fun BookingFilterListScreenPreview() {
WooThemeWithBackground {
BookingFilterListScreen(
state = BookingFilterListUiState(
items = listOf(
BookingFilterListItem(
title = R.string.bookings_filter_title_team_member,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_title_attendance_status,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_title_payment_status,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_title_type,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_customer_name,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_category,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_title_date,
value = null
),
BookingFilterListItem(
title = R.string.bookings_filter_title_service_event,
value = null
),
)
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.woocommerce.android.ui.bookings.filter

import androidx.annotation.StringRes
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.asLiveData
import com.woocommerce.android.R
import com.woocommerce.android.viewmodel.MultiLiveEvent
import com.woocommerce.android.viewmodel.ScopedViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings.BookingsFilterOption
import javax.inject.Inject

@HiltViewModel
class BookingFilterListViewModel @Inject constructor(
savedStateHandle: SavedStateHandle
) : ScopedViewModel(savedStateHandle) {

private val _uiState = MutableStateFlow(
BookingFilterListUiState(
items = defaultBookingFilters().map { BookingFilterListItem(title = it.titleRes()) },
onClose = ::onClose,
onShowBookings = ::onShowBookings
)
)
val uiState = _uiState.asLiveData()

private fun onClose() {
// TODO Verify unsaved changes and close
triggerEvent(MultiLiveEvent.Event.Exit)
}

private fun onShowBookings() {
// TODO Apply filters and show bookings
triggerEvent(MultiLiveEvent.Event.Exit)
}

@StringRes
private fun BookingsFilterOption.titleRes(): Int = when (this) {
BookingsFilterOption.TeamMember -> R.string.bookings_filter_title_team_member
BookingsFilterOption.AttendanceStatus -> R.string.bookings_filter_title_attendance_status
BookingsFilterOption.PaymentStatus -> R.string.bookings_filter_title_payment_status
BookingsFilterOption.BookingType -> R.string.bookings_filter_title_type
is BookingsFilterOption.Customer -> R.string.bookings_filter_customer_name
BookingsFilterOption.Category -> R.string.bookings_filter_category
is BookingsFilterOption.DateRange -> R.string.bookings_filter_title_date
BookingsFilterOption.ServiceEvent -> R.string.bookings_filter_title_service_event
}

private fun defaultBookingFilters(): List<BookingsFilterOption> = listOf(
BookingsFilterOption.TeamMember,
BookingsFilterOption.AttendanceStatus,
BookingsFilterOption.PaymentStatus,
BookingsFilterOption.BookingType,
BookingsFilterOption.Customer(customerId = null),
BookingsFilterOption.Category,
BookingsFilterOption.DateRange(before = null, after = null),
BookingsFilterOption.ServiceEvent,
)

data class BookingFilterListItem(
@StringRes val title: Int,
val value: String? = null,
val onClick: () -> Unit = {}
)

data class BookingFilterListUiState(
val items: List<BookingFilterListItem>,
val onClose: () -> Unit = {},
val onShowBookings: () -> Unit = {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import javax.inject.Inject

@AndroidEntryPoint
class BookingListFragment : TopLevelFragment() {

override val activityAppBarStatus: AppBarStatus
get() = AppBarStatus.Hidden

Expand Down Expand Up @@ -46,12 +47,13 @@ class BookingListFragment : TopLevelFragment() {
private fun handleEvents() {
viewModel.event.observe(viewLifecycleOwner) { event ->
when (event) {
is BookingListViewModel.NavigateToBookingDetails -> {
findNavController().navigate(
BookingListFragmentDirections
.actionBookingListFragmentToBookingDetailsFragment(event.bookingId)
)
}
is BookingListViewModel.NavigateToFilters -> findNavController().navigate(
BookingListFragmentDirections.actionBookingListFragmentToBookingFilterList()
)

is BookingListViewModel.NavigateToBookingDetails -> findNavController().navigate(
BookingListFragmentDirections.actionBookingListFragmentToBookingDetailsFragment(event.bookingId)
)

is MultiLiveEvent.Event.ShowSnackbar -> uiMessageResolver.showSnack(event.message)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ class BookingListViewModel @Inject constructor(
}

private fun onFilterClicked() {
// TODO Show filter bottom sheet
triggerEvent(NavigateToFilters)
}

private fun prepareFilters(): List<BookingsFilterOption> = with(filtersBuilder) {
Expand All @@ -194,4 +194,5 @@ class BookingListViewModel @Inject constructor(
}

data class NavigateToBookingDetails(val bookingId: Long) : MultiLiveEvent.Event()
object NavigateToFilters : MultiLiveEvent.Event()
}
7 changes: 7 additions & 0 deletions WooCommerce/src/main/res/navigation/nav_graph_bookings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
<action
android:id="@+id/action_bookingListFragment_to_bookingDetailsFragment"
app:destination="@id/bookingDetailsFragment" />
<action
android:id="@+id/action_bookingListFragment_to_bookingFilterList"
app:destination="@id/bookingFilterListFragment" />
</fragment>
<fragment
android:id="@+id/bookingDetailsFragment"
Expand All @@ -28,5 +31,9 @@
app:argType="long" />
</action>
</fragment>
<fragment
android:id="@+id/bookingFilterListFragment"
android:name="com.woocommerce.android.ui.bookings.filter.BookingFilterListFragment"
android:label="BookingFilterListFragment" />

</navigation>
14 changes: 12 additions & 2 deletions WooCommerce/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4163,8 +4163,6 @@
<string name="bookings_sort_by_newest_to_oldest">Newest to oldest</string>
<string name="bookings_sort_by_oldest_to_newest_short">Oldest</string>
<string name="bookings_sort_by_newest_to_oldest_short">Newest</string>
<string name="bookings_filters_default_title">Filters</string>
<string name="bookings_filters_count_title">Filters (%d)</string>
<string name="bookings_empty_state_title_default">No bookings found</string>
<string name="bookings_empty_state_title_today">No bookings today</string>
<string name="bookings_empty_state_title_upcoming">No upcoming bookings</string>
Expand All @@ -4175,6 +4173,18 @@
<string name="bookings_empty_state_description_with_filters">No bookings match your filters. Try adjusting them to see more results.</string>
<string name="bookings_empty_state_change_filters_button">Change filters</string>
<string name="bookings_empty_state_clear_filters_button">Clear filters</string>
<string name="bookings_filters_default_title">Filters</string>
<string name="bookings_filters_count_title">Filters (%d)</string>
<string name="bookings_filters_show_bookings">Show bookings</string>
<string name="bookings_filter_title_team_member">Assigned team member</string>
<string name="bookings_filter_title_attendance_status">Attendance status</string>
<string name="bookings_filter_title_payment_status">Payment status</string>
<string name="bookings_filter_title_type">Booking type</string>
<string name="bookings_filter_customer_name">Customer name</string>
<string name="bookings_filter_category">Category</string>
<string name="bookings_filter_title_date">Date</string>
<string name="bookings_filter_title_service_event">Service / Event</string>
<string name="bookings_filter_default">Any</string>

<!-- Booking details view-->
<string name="booking_details_title">Booking #%s</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@ package org.wordpress.android.fluxc.network.rest.wpcom.wc.bookings
import java.time.Instant

sealed interface BookingsFilterOption {
object TeamMember : BookingsFilterOption

object AttendanceStatus : BookingsFilterOption

object PaymentStatus : BookingsFilterOption

object BookingType : BookingsFilterOption

data class Customer(val customerId: Long?) : BookingsFilterOption

object Category : BookingsFilterOption

data class DateRange(
val before: Instant?,
val after: Instant?
) : BookingsFilterOption

data class Customer(val customerId: Long) : BookingsFilterOption
object ServiceEvent : BookingsFilterOption
}
Loading