From 15843c73ebac41e8dac6bf261ef8a59c9fd2607d Mon Sep 17 00:00:00 2001 From: KingLucius Date: Sun, 4 Aug 2024 14:38:52 +0300 Subject: [PATCH] feat(TV UI): Navigation rail redesign --- .../lagradost/cloudstream3/MainActivity.kt | 42 +++++++++++++++---- .../cloudstream3/plugins/PluginManager.kt | 3 ++ .../cloudstream3/ui/home/HomeFragment.kt | 9 ++++ .../ui/home/HomeParentItemAdapterPreview.kt | 5 ++- .../cloudstream3/ui/home/HomeViewModel.kt | 13 +++++- .../cloudstream3/utils/DataStoreHelper.kt | 13 ++++++ app/src/main/res/color/item_select_color.xml | 2 +- .../main/res/drawable/home_icon_filled_24.xml | 9 ++++ .../res/drawable/home_icon_outline_24.xml | 9 ++++ .../main/res/drawable/home_icon_selector.xml | 6 +++ .../drawable/ic_filled_notifications_24dp.xml | 9 ++++ .../ic_outline_notifications_24dp.xml | 9 ++++ .../main/res/drawable/library_icon_filled.xml | 10 +++++ .../res/drawable/library_icon_selector.xml | 6 +++ .../drawable/notifications_icon_selector.xml | 6 +++ app/src/main/res/drawable/outline_big_20.xml | 10 +++++ .../drawable/outline_drawable_round_20.xml | 5 +++ .../res/drawable/settings_icon_filled.xml | 9 ++++ .../res/drawable/settings_icon_outline.xml | 9 ++++ .../res/drawable/settings_icon_selector.xml | 6 +++ app/src/main/res/layout/activity_main.xml | 9 ++-- app/src/main/res/layout/activity_main_tv.xml | 9 ++-- .../main/res/layout/fragment_home_head_tv.xml | 7 +++- app/src/main/res/layout/fragment_home_tv.xml | 5 ++- app/src/main/res/layout/rail_footer.xml | 31 ++++++++++++++ app/src/main/res/layout/rail_header.xml | 21 ++++++++++ app/src/main/res/menu/bottom_nav_menu.xml | 40 +++++++++--------- app/src/main/res/values/colors.xml | 1 + 28 files changed, 272 insertions(+), 41 deletions(-) create mode 100644 app/src/main/res/drawable/home_icon_filled_24.xml create mode 100644 app/src/main/res/drawable/home_icon_outline_24.xml create mode 100644 app/src/main/res/drawable/home_icon_selector.xml create mode 100644 app/src/main/res/drawable/ic_filled_notifications_24dp.xml create mode 100644 app/src/main/res/drawable/ic_outline_notifications_24dp.xml create mode 100644 app/src/main/res/drawable/library_icon_filled.xml create mode 100644 app/src/main/res/drawable/library_icon_selector.xml create mode 100644 app/src/main/res/drawable/notifications_icon_selector.xml create mode 100644 app/src/main/res/drawable/outline_big_20.xml create mode 100644 app/src/main/res/drawable/outline_drawable_round_20.xml create mode 100644 app/src/main/res/drawable/settings_icon_filled.xml create mode 100644 app/src/main/res/drawable/settings_icon_outline.xml create mode 100644 app/src/main/res/drawable/settings_icon_selector.xml create mode 100644 app/src/main/res/layout/rail_footer.xml create mode 100644 app/src/main/res/layout/rail_header.xml diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index b59265ee..77a6d83f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -18,6 +18,8 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.WindowManager +import android.widget.ImageView +import android.widget.LinearLayout import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResultLauncher @@ -25,6 +27,7 @@ import androidx.annotation.IdRes import androidx.annotation.MainThread import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.cardview.widget.CardView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.children import androidx.core.view.isGone @@ -96,6 +99,8 @@ import com.lagradost.cloudstream3.syncproviders.SyncAPI import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.SyncWatchType import com.lagradost.cloudstream3.ui.WatchType +import com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLinear +import com.lagradost.cloudstream3.ui.account.AccountViewModel import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO import com.lagradost.cloudstream3.ui.home.HomeViewModel import com.lagradost.cloudstream3.ui.library.LibraryViewModel @@ -326,6 +331,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa */ val reloadLibraryEvent = Event() + /** + * Used by DataStoreHelper to fully reload Navigation Rail header picture + */ + val reloadAccountEvent = Event() /** * @return true if the str has launched an app task (be it successful or not) @@ -791,6 +800,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa lateinit var viewModel: ResultViewModel2 lateinit var syncViewModel: SyncViewModel private var libraryViewModel: LibraryViewModel? = null + private var accountViewModel: AccountViewModel? = null /** kinda dirty, however it signals that we should use the watch status as sync or not*/ var isLocalList: Boolean = false @@ -1210,6 +1220,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa ) newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus -> + //Log.d("King", "Focus => $newFocus") if (exceptionButtons.contains(newFocus?.id)) return@addOnGlobalFocusChangeListener centerView(newFocus) } @@ -1552,18 +1563,19 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa logError(e) } } - + // we need to run this after we init all apis, otherwise currentSyncApi will fuck itself this@MainActivity.runOnUiThread { // Change library icon with logo of current api in sync - libraryViewModel = ViewModelProvider(this@MainActivity)[LibraryViewModel::class.java] + libraryViewModel = + ViewModelProvider(this@MainActivity)[LibraryViewModel::class.java] libraryViewModel?.currentApiName?.observe(this@MainActivity) { - val syncAPI = libraryViewModel?.currentSyncApi + val syncAPI = libraryViewModel?.currentSyncApi Log.i("SYNC_API", "${syncAPI?.name}, ${syncAPI?.idPrefix}") - val icon = if (syncAPI?.idPrefix == localListApi.idPrefix) { - R.drawable.library_icon + val icon = if (syncAPI?.idPrefix == localListApi.idPrefix) { + R.drawable.library_icon_selector } else { - syncAPI?.icon ?: R.drawable.library_icon + syncAPI?.icon ?: R.drawable.library_icon_selector } binding?.apply { @@ -1658,7 +1670,23 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa } } } - noFocus(this) + //noFocus(this) + + val navProfileRoot = findViewById(R.id.nav_footer_root) + val navProfilePic = findViewById(R.id.nav_footer_profile_pic) + val navProfileCard = findViewById(R.id.nav_footer_profile_card) + + navProfileCard?.setOnClickListener { + showAccountSelectLinear() + } + + val profileImage = DataStoreHelper.getCurrentAccount()?.image + + if (navProfilePic != null) { + navProfilePic.setImage(profileImage) + } else { + navProfileRoot?.isGone = true + } } loadCache() diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt index bc2a1780..c7f41688 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt @@ -294,6 +294,9 @@ object PluginManager { main { val uitext = txt(R.string.plugins_updated, updatedPlugins.size) createNotification(activity, uitext, updatedPlugins) + /*val navBadge = (activity as MainActivity).binding?.navRailView?.getOrCreateBadge(R.id.navigation_settings) + navBadge?.isVisible = true + navBadge?.number = 5*/ } // ioSafe { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index 49de2503..4bfa0304 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -22,6 +22,7 @@ import androidx.recyclerview.widget.RecyclerView import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.chip.Chip +import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.CommonActivity.showToast @@ -57,6 +58,7 @@ import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes +import com.lagradost.cloudstream3.utils.UIHelper.setImage import java.util.* @@ -555,6 +557,13 @@ class HomeFragment : Fragment() { binding?.homeChangeApi?.text = apiName } + observe(homeViewModel.currentAccount) { currentAccount -> + val navProfilePic = (activity as MainActivity).binding?.navRailView?.findViewById(R.id.nav_footer_profile_pic) + navProfilePic?.setImage( + currentAccount?.image + ) + } + observe(homeViewModel.page) { data -> binding?.apply { when (data) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt index 339ef1e1..7efab1ed 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt @@ -16,6 +16,8 @@ import androidx.viewbinding.ViewBinding import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup +import com.google.android.material.navigation.NavigationBarItemView +import com.google.android.material.navigationrail.NavigationRailMenuView import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.HomePageList @@ -476,7 +478,8 @@ class HomeParentItemAdapterPreview( homePreviewHiddenPrevFocus.setOnFocusChangeListener { _, hasFocus -> if (!hasFocus) return@setOnFocusChangeListener if (previewViewpager.currentItem <= 0) { - (activity as? MainActivity)?.binding?.navRailView?.requestFocus() + //Focus the Home item as the default focus will be the header item + (activity as? MainActivity)?.binding?.navRailView?.findViewById(R.id.navigation_home)?.requestFocus() } else { previewViewpager.setCurrentItem(previewViewpager.currentItem - 1, true) binding.homePreviewPlayBtt.requestFocus() diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt index 24ca4df2..2906feb9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt @@ -45,6 +45,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.deleteAllResumeStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds import com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData +import com.lagradost.cloudstream3.utils.DataStoreHelper.getCurrentAccount import com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos @@ -108,6 +109,9 @@ class HomeViewModel : ViewModel() { private val _apiName = MutableLiveData() val apiName: LiveData = _apiName + private val _currentAccount = MutableLiveData() + val currentAccount: MutableLiveData = _currentAccount + private val _randomItems = MutableLiveData?>(null) val randomItems: LiveData?> = _randomItems @@ -404,7 +408,6 @@ class HomeViewModel : ViewModel() { } } - private val _popup = MutableLiveData Unit)?>?>(null) val popup: LiveData Unit)?>?> = _popup @@ -431,11 +434,18 @@ class HomeViewModel : ViewModel() { loadAndCancel(DataStoreHelper.currentHomePage, true) } + private fun reloadAccount(unused: Boolean = false) { + _currentAccount.postValue( + getCurrentAccount() + ) + } + init { MainActivity.bookmarksUpdatedEvent += ::bookmarksUpdated MainActivity.afterPluginsLoadedEvent += ::afterPluginsLoaded MainActivity.mainPluginsLoadedEvent += ::afterMainPluginsLoaded MainActivity.reloadHomeEvent += ::reloadHome + MainActivity.reloadAccountEvent += ::reloadAccount } override fun onCleared() { @@ -443,6 +453,7 @@ class HomeViewModel : ViewModel() { MainActivity.afterPluginsLoadedEvent -= ::afterPluginsLoaded MainActivity.mainPluginsLoadedEvent -= ::afterMainPluginsLoaded MainActivity.reloadHomeEvent -= ::reloadHome + MainActivity.reloadAccountEvent -= ::reloadAccount super.onCleared() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index 2fa5f6a3..77b78ee8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -166,6 +166,7 @@ object DataStoreHelper { showToast(context?.getString(R.string.logged_account, account.name) ?: account.name) MainActivity.bookmarksUpdatedEvent(true) MainActivity.reloadLibraryEvent(true) + MainActivity.reloadAccountEvent(true) val oldAccount = accounts.find { it.keyIndex == account.keyIndex } if (oldAccount != null && currentHomePage != homepage) { // This is not a new account, and the homepage has changed, reload it @@ -191,6 +192,18 @@ object DataStoreHelper { } } + fun getAccount(accountIndex: Int): Account? { + return accounts.firstOrNull { + it.keyIndex == accountIndex + } + } + + fun getCurrentAccount(): Account? { + return accounts.firstOrNull { + it.keyIndex == selectedKeyIndex + } + } + data class PosDur( @JsonProperty("position") val position: Long, @JsonProperty("duration") val duration: Long diff --git a/app/src/main/res/color/item_select_color.xml b/app/src/main/res/color/item_select_color.xml index 3d69c540..5a9453b7 100644 --- a/app/src/main/res/color/item_select_color.xml +++ b/app/src/main/res/color/item_select_color.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/app/src/main/res/drawable/home_icon_filled_24.xml b/app/src/main/res/drawable/home_icon_filled_24.xml new file mode 100644 index 00000000..303b6a10 --- /dev/null +++ b/app/src/main/res/drawable/home_icon_filled_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/home_icon_outline_24.xml b/app/src/main/res/drawable/home_icon_outline_24.xml new file mode 100644 index 00000000..2d5f93a6 --- /dev/null +++ b/app/src/main/res/drawable/home_icon_outline_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/home_icon_selector.xml b/app/src/main/res/drawable/home_icon_selector.xml new file mode 100644 index 00000000..2280cdd0 --- /dev/null +++ b/app/src/main/res/drawable/home_icon_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_filled_notifications_24dp.xml b/app/src/main/res/drawable/ic_filled_notifications_24dp.xml new file mode 100644 index 00000000..ed46f973 --- /dev/null +++ b/app/src/main/res/drawable/ic_filled_notifications_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_outline_notifications_24dp.xml b/app/src/main/res/drawable/ic_outline_notifications_24dp.xml new file mode 100644 index 00000000..928ad086 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_notifications_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/library_icon_filled.xml b/app/src/main/res/drawable/library_icon_filled.xml new file mode 100644 index 00000000..eba49782 --- /dev/null +++ b/app/src/main/res/drawable/library_icon_filled.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/library_icon_selector.xml b/app/src/main/res/drawable/library_icon_selector.xml new file mode 100644 index 00000000..9c6495be --- /dev/null +++ b/app/src/main/res/drawable/library_icon_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/notifications_icon_selector.xml b/app/src/main/res/drawable/notifications_icon_selector.xml new file mode 100644 index 00000000..9226029a --- /dev/null +++ b/app/src/main/res/drawable/notifications_icon_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/outline_big_20.xml b/app/src/main/res/drawable/outline_big_20.xml new file mode 100644 index 00000000..7faf8a88 --- /dev/null +++ b/app/src/main/res/drawable/outline_big_20.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/outline_drawable_round_20.xml b/app/src/main/res/drawable/outline_drawable_round_20.xml new file mode 100644 index 00000000..a2e8253b --- /dev/null +++ b/app/src/main/res/drawable/outline_drawable_round_20.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/settings_icon_filled.xml b/app/src/main/res/drawable/settings_icon_filled.xml new file mode 100644 index 00000000..1d31bb7d --- /dev/null +++ b/app/src/main/res/drawable/settings_icon_filled.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/settings_icon_outline.xml b/app/src/main/res/drawable/settings_icon_outline.xml new file mode 100644 index 00000000..bdc9e98d --- /dev/null +++ b/app/src/main/res/drawable/settings_icon_outline.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/settings_icon_selector.xml b/app/src/main/res/drawable/settings_icon_selector.xml new file mode 100644 index 00000000..c54a9760 --- /dev/null +++ b/app/src/main/res/drawable/settings_icon_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b6290865..a06e6a15 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -14,20 +14,21 @@ + +