diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt index e2bde9b54aeb..86b9542a8b84 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/analytics/AnalyticsEvent.kt @@ -514,6 +514,8 @@ enum class AnalyticsEvent(override val siteless: Boolean = false) : IAnalyticsEv MAIN_TAB_POS_SELECTED, MAIN_TAB_HUB_MENU_SELECTED, MAIN_TAB_HUB_MENU_RESELECTED, + MAIN_TAB_BOOKINGS_SELECTED, + MAIN_TAB_BOOKINGS_RESELECTED, // -- Settings SETTING_CHANGE, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingListFragment.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingListFragment.kt new file mode 100644 index 000000000000..3eebdbd5e1f3 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/BookingListFragment.kt @@ -0,0 +1,37 @@ +package com.woocommerce.android.ui.bookings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.material3.Text +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import com.woocommerce.android.R +import com.woocommerce.android.ui.base.TopLevelFragment +import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground +import com.woocommerce.android.ui.main.AppBarStatus +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class BookingListFragment : TopLevelFragment() { + override val activityAppBarStatus: AppBarStatus + get() = AppBarStatus.Hidden + + override fun getFragmentTitle() = getString(R.string.bookings_tab_title) + override fun shouldExpandToolbar(): Boolean = false + override fun scrollToTop() { + return + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + WooThemeWithBackground { + Text("Empty Booking List screen: WIP") + } + } + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/BookingsTabController.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/BookingsTabController.kt new file mode 100644 index 000000000000..e8e938ea9029 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/BookingsTabController.kt @@ -0,0 +1,46 @@ +package com.woocommerce.android.ui.bookings.tab + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import com.woocommerce.android.R +import com.woocommerce.android.databinding.ActivityMainBinding +import com.woocommerce.android.ui.main.MainActivity +import kotlinx.coroutines.launch +import javax.inject.Inject + +class BookingsTabController @Inject constructor( + private val showBookingsTab: ShowBookingsTab +) : DefaultLifecycleObserver { + private lateinit var activity: MainActivity + private lateinit var binding: ActivityMainBinding + + fun init( + activity: MainActivity, + binding: ActivityMainBinding + ) { + this.activity = activity + this.binding = binding + activity.lifecycle.addObserver(this) + } + + override fun onResume(owner: LifecycleOwner) { + checkBookingsTabVisibility() + } + + override fun onDestroy(owner: LifecycleOwner) { + owner.lifecycle.removeObserver(this) + } + + private fun checkBookingsTabVisibility() { + activity.lifecycleScope.launch { + showBookingsTab() + .onSuccess { + binding.bottomNav.menu.findItem(R.id.bookings)?.isVisible = it + } + .onFailure { + // TODO log error or track errors? + } + } + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/ShowBookingsTab.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/ShowBookingsTab.kt new file mode 100644 index 000000000000..93628e43ad3f --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/bookings/tab/ShowBookingsTab.kt @@ -0,0 +1,13 @@ +package com.woocommerce.android.ui.bookings.tab + +import com.woocommerce.android.util.FeatureFlag +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class ShowBookingsTab @Inject constructor() { + suspend operator fun invoke(): Result = withContext(Dispatchers.IO) { + // Add here: Fetch if site has any published bookable product AND if site is CIAB + return@withContext Result.success(FeatureFlag.BOOKINGS_MVP.isEnabled()) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/BottomNavigationPosition.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/BottomNavigationPosition.kt index 03fec335a95f..36ea5c83835a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/BottomNavigationPosition.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/BottomNavigationPosition.kt @@ -6,13 +6,15 @@ const val MY_STORE_POSITION = 0 const val ORDERS_POSITION = 1 const val PRODUCTS_POSITION = 2 const val POS_POSITION = 3 -const val MORE_POSITION = 4 +const val BOOKINGS_POSITION = 4 +const val MORE_POSITION = 5 enum class BottomNavigationPosition(val position: Int, val id: Int) { MY_STORE(MY_STORE_POSITION, R.id.dashboard), ORDERS(ORDERS_POSITION, R.id.orders), PRODUCTS(PRODUCTS_POSITION, R.id.products), POS(POS_POSITION, R.id.point_of_sale), + BOOKINGS(BOOKINGS_POSITION, R.id.bookings), MORE(MORE_POSITION, R.id.moreMenu) } @@ -20,6 +22,7 @@ fun findNavigationPositionById(id: Int): BottomNavigationPosition = when (id) { BottomNavigationPosition.MY_STORE.id -> BottomNavigationPosition.MY_STORE BottomNavigationPosition.ORDERS.id -> BottomNavigationPosition.ORDERS BottomNavigationPosition.PRODUCTS.id -> BottomNavigationPosition.PRODUCTS + BottomNavigationPosition.BOOKINGS.id -> BottomNavigationPosition.BOOKINGS BottomNavigationPosition.POS.id -> BottomNavigationPosition.POS BottomNavigationPosition.MORE.id -> BottomNavigationPosition.MORE else -> BottomNavigationPosition.MY_STORE diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt index 26cb400780c9..83b45152bf4c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainActivity.kt @@ -61,10 +61,12 @@ import com.woocommerce.android.ui.appwidgets.WidgetUpdater import com.woocommerce.android.ui.base.BaseFragment import com.woocommerce.android.ui.base.TopLevelFragment import com.woocommerce.android.ui.base.UIMessageResolver +import com.woocommerce.android.ui.bookings.tab.BookingsTabController import com.woocommerce.android.ui.common.InfoScreenFragment import com.woocommerce.android.ui.compose.theme.WooThemeWithBackground import com.woocommerce.android.ui.feedback.SurveyType import com.woocommerce.android.ui.login.LoginActivity +import com.woocommerce.android.ui.main.BottomNavigationPosition.BOOKINGS import com.woocommerce.android.ui.main.BottomNavigationPosition.MORE import com.woocommerce.android.ui.main.BottomNavigationPosition.MY_STORE import com.woocommerce.android.ui.main.BottomNavigationPosition.ORDERS @@ -187,6 +189,8 @@ class MainActivity : @Inject lateinit var posTabController: WooPosTabController + @Inject lateinit var bookingsTabController: BookingsTabController + private val viewModel: MainActivityViewModel by viewModels() private var unfilledOrderCount: Int = 0 @@ -332,6 +336,7 @@ class MainActivity : binding.bottomNav.init(navController, this) posTabController.initialize(this, binding, navController) + bookingsTabController.init(this, binding) presenter.takeView(this) @@ -756,6 +761,7 @@ class MainActivity : ORDERS -> AnalyticsEvent.MAIN_TAB_ORDERS_SELECTED PRODUCTS -> AnalyticsEvent.MAIN_TAB_PRODUCTS_SELECTED POS -> AnalyticsEvent.MAIN_TAB_POS_SELECTED + BOOKINGS -> AnalyticsEvent.MAIN_TAB_BOOKINGS_SELECTED MORE -> AnalyticsEvent.MAIN_TAB_HUB_MENU_SELECTED } AnalyticsTracker.track(stat, mapOf(KEY_HORIZONTAL_SIZE_CLASS to deviceTypeToAnalyticsString)) @@ -781,6 +787,7 @@ class MainActivity : PRODUCTS -> AnalyticsEvent.MAIN_TAB_PRODUCTS_RESELECTED MORE -> AnalyticsEvent.MAIN_TAB_HUB_MENU_RESELECTED POS -> null + BOOKINGS -> AnalyticsEvent.MAIN_TAB_BOOKINGS_RESELECTED } stat?.let { AnalyticsTracker.track(it, mapOf(KEY_HORIZONTAL_SIZE_CLASS to deviceTypeToAnalyticsString)) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainBottomNavigationView.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainBottomNavigationView.kt index 04cabf2fb97b..728a8893ef01 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainBottomNavigationView.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/main/MainBottomNavigationView.kt @@ -157,6 +157,15 @@ class MainBottomNavigationView @JvmOverloads constructor( listener.onNavItemReselected(navPos) } + /** + * Currently BottomNavigationView support a maximum of 5 tabs. We need to override that limit to enable + * adding or removing tabs based on the user's site type/configuration. However, there shouldn't be any + * scenario where we end up displaying more than 5 tabs at once. + */ + override fun getMaxItemCount(): Int { + return OVERRIDEN_MAX_ITEM_COUNT + } + private fun assignNavigationListeners(assign: Boolean) { setOnItemSelectedListener(if (assign) this else null) setOnItemReselectedListener(if (assign) this else null) @@ -167,5 +176,6 @@ class MainBottomNavigationView @JvmOverloads constructor( companion object { private const val MAX_CHARACTERS_IN_BADGE = 4 + private const val OVERRIDEN_MAX_ITEM_COUNT = 6 } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt index 414e30a1b4ff..8b57b4d272f8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/util/FeatureFlag.kt @@ -11,7 +11,8 @@ enum class FeatureFlag { BETTER_CUSTOMER_SEARCH_M2, ORDER_CREATION_AUTO_TAX_RATE, WOO_POS_HISTORICAL_ORDERS_M1, - WOO_POS_LOCAL_CATALOG_M1; + WOO_POS_LOCAL_CATALOG_M1, + BOOKINGS_MVP; fun isEnabled(context: Context? = null): Boolean { return when (this) { @@ -23,7 +24,8 @@ enum class FeatureFlag { WC_SHIPPING_BANNER, BETTER_CUSTOMER_SEARCH_M2, ORDER_CREATION_AUTO_TAX_RATE, - WOO_POS_LOCAL_CATALOG_M1 -> PackageUtils.isDebugBuild() + WOO_POS_LOCAL_CATALOG_M1, + BOOKINGS_MVP -> PackageUtils.isDebugBuild() } } } diff --git a/WooCommerce/src/main/res/drawable/as_menu_booking_list.xml b/WooCommerce/src/main/res/drawable/as_menu_booking_list.xml new file mode 100644 index 000000000000..9faf79cf1ab0 --- /dev/null +++ b/WooCommerce/src/main/res/drawable/as_menu_booking_list.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + diff --git a/WooCommerce/src/main/res/drawable/ic_bookings_tab.xml b/WooCommerce/src/main/res/drawable/ic_bookings_tab.xml new file mode 100644 index 000000000000..6b3377b67b8c --- /dev/null +++ b/WooCommerce/src/main/res/drawable/ic_bookings_tab.xml @@ -0,0 +1,9 @@ + + + diff --git a/WooCommerce/src/main/res/menu/menu_bottom_bar.xml b/WooCommerce/src/main/res/menu/menu_bottom_bar.xml index 4a52292b1905..01da6a7bcbc7 100644 --- a/WooCommerce/src/main/res/menu/menu_bottom_bar.xml +++ b/WooCommerce/src/main/res/menu/menu_bottom_bar.xml @@ -15,6 +15,11 @@ android:icon="@drawable/as_menu_products_list" android:title="@string/products" /> + + + WordPress Media Library Media loading failed There is no network available + + + Bookings +