From 023f7efe55337147c8b0fcde80a7abd76160e14c Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 18:46:27 +0530 Subject: [PATCH 1/9] created a SettingsFragment --- .../stream/ui/settings/SettingsFragment.kt | 48 ++++++++++++++++ app/src/main/res/layout/fragment_settings.xml | 55 +++++++++++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 104 insertions(+) create mode 100644 app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt create mode 100644 app/src/main/res/layout/fragment_settings.xml diff --git a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt new file mode 100644 index 0000000..dc21757 --- /dev/null +++ b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt @@ -0,0 +1,48 @@ +package zechs.drive.stream.ui.settings + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.fragment.findNavController +import zechs.drive.stream.databinding.FragmentSettingsBinding +import zechs.drive.stream.ui.BaseFragment + + +class SettingsFragment : BaseFragment() { + + companion object { + const val TAG = "SettingsFragment" + } + + private var _binding: FragmentSettingsBinding? = null + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentSettingsBinding.inflate( + inflater, container, /* attachToParent */false + ) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + _binding = FragmentSettingsBinding.bind(view) + + binding.toolbar.setNavigationOnClickListener { + findNavController().navigateUp() + } + + } + + override fun onDestroyView() { + super.onDestroyView() + binding.rvList.adapter = null + _binding = null + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml new file mode 100644 index 0000000..5f2336c --- /dev/null +++ b/app/src/main/res/layout/fragment_settings.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ae0c49..554b169 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -60,4 +60,5 @@ Please fill all the fields Please grant notification permission to receive update notifications Grant + App Settings \ No newline at end of file From a1b1dfe770c65286a00eba988ffb41aab45af6df Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 18:47:28 +0530 Subject: [PATCH 2/9] added Settings to Home menu --- .../java/zechs/drive/stream/ui/home/HomeFragment.kt | 4 ++++ app/src/main/res/drawable/ic_settings_24.xml | 10 ++++++++++ app/src/main/res/layout/fragment_home.xml | 6 ++++++ app/src/main/res/navigation/nav_graph.xml | 7 +++++++ 4 files changed, 27 insertions(+) create mode 100644 app/src/main/res/drawable/ic_settings_24.xml diff --git a/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt b/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt index 5b0c264..4bcff07 100644 --- a/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt @@ -86,6 +86,10 @@ class HomeFragment : BaseFragment() { query = "'root' in parents and trashed=true" ) + btnAppSettings.setOnClickListener { + findNavController().navigateSafe(R.id.action_homeFragment_to_settingsFragment) + } + } setupToolbar() diff --git a/app/src/main/res/drawable/ic_settings_24.xml b/app/src/main/res/drawable/ic_settings_24.xml new file mode 100644 index 0000000..61d7553 --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 7feac63..ac841b5 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -61,6 +61,12 @@ android:text="@string/trashed" app:icon="@drawable/ic_delete_24" /> + + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 037a861..3a02aa0 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -46,7 +46,14 @@ + + \ No newline at end of file From ea8006e599d7cbf4a7ce5195d3cb66615021a6a5 Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 22:10:40 +0530 Subject: [PATCH 3/9] updated transition animation --- app/src/main/java/zechs/drive/stream/ui/BaseFragment.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/zechs/drive/stream/ui/BaseFragment.kt b/app/src/main/java/zechs/drive/stream/ui/BaseFragment.kt index 1ec0e0e..bcacfc1 100755 --- a/app/src/main/java/zechs/drive/stream/ui/BaseFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/BaseFragment.kt @@ -15,6 +15,14 @@ abstract class BaseFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enterTransition = MaterialSharedAxis( + /* axis */ MaterialSharedAxis.X, + /* forward */ true + ).apply { + interpolator = LinearInterpolator() + duration = 300 + } + returnTransition = MaterialSharedAxis( /* axis */ MaterialSharedAxis.X, /* forward */ false From 02c110cb67498753fd5c4d5e2e8287132f9c4668 Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 22:16:22 +0530 Subject: [PATCH 4/9] implemented app settings ui - select theme - set default player - check for updates --- app/src/main/res/drawable/ic_player_24.xml | 13 ++ app/src/main/res/layout/fragment_settings.xml | 143 +++++++++++++++--- app/src/main/res/values/strings.xml | 4 + 3 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 app/src/main/res/drawable/ic_player_24.xml diff --git a/app/src/main/res/drawable/ic_player_24.xml b/app/src/main/res/drawable/ic_player_24.xml new file mode 100644 index 0000000..57df50b --- /dev/null +++ b/app/src/main/res/drawable/ic_player_24.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 5f2336c..6ebceb1 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -31,25 +31,134 @@ - + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 554b169..54ec6f5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -61,4 +61,8 @@ Please grant notification permission to receive update notifications Grant App Settings + Light, Dark and Follow System + Default player + Select default video player + Check for updates \ No newline at end of file From ce8830cf6f0ef6960779f170b7ccb6213f8f2644 Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 22:50:44 +0530 Subject: [PATCH 5/9] implemented theme chooser in app settings --- .../drive/stream/ui/home/HomeFragment.kt | 28 +------------ .../stream/ui/settings/SettingsFragment.kt | 39 +++++++++++++++++-- app/src/main/res/menu/main_menu.xml | 6 --- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt b/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt index 4bcff07..8273462 100644 --- a/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/home/HomeFragment.kt @@ -17,8 +17,6 @@ import kotlinx.coroutines.launch import zechs.drive.stream.R import zechs.drive.stream.databinding.FragmentHomeBinding import zechs.drive.stream.ui.BaseFragment -import zechs.drive.stream.ui.main.MainViewModel -import zechs.drive.stream.utils.AppTheme import zechs.drive.stream.utils.ext.navigateSafe @@ -32,7 +30,6 @@ class HomeFragment : BaseFragment() { private val binding get() = _binding!! private val viewModel by activityViewModels() - private val mainViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, @@ -110,11 +107,6 @@ class HomeFragment : BaseFragment() { } private fun setupToolbar() { - val themes = listOf( - getString(R.string.theme_dark), - getString(R.string.theme_light), - getString(R.string.theme_system) - ) binding.toolbar.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.action_logOut -> { @@ -131,25 +123,7 @@ class HomeFragment : BaseFragment() { .show() return@setOnMenuItemClickListener true } - R.id.action_theme -> { - MaterialAlertDialogBuilder(requireContext()).apply { - setTitle(getString(R.string.select_theme)) - setSingleChoiceItems( - themes.toTypedArray(), - mainViewModel.currentThemeIndex - ) { dialog, item -> - val theme = when (item) { - AppTheme.DARK.value -> AppTheme.DARK - AppTheme.LIGHT.value -> AppTheme.LIGHT - AppTheme.SYSTEM.value -> AppTheme.SYSTEM - else -> throw IllegalArgumentException("Unknown theme value") - } - mainViewModel.setTheme(theme) - dialog.dismiss() - } - }.also { it.show() } - return@setOnMenuItemClickListener true - } + else -> { return@setOnMenuItemClickListener false } diff --git a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt index dc21757..51ae657 100644 --- a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt @@ -4,9 +4,14 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import zechs.drive.stream.R import zechs.drive.stream.databinding.FragmentSettingsBinding import zechs.drive.stream.ui.BaseFragment +import zechs.drive.stream.ui.main.MainViewModel +import zechs.drive.stream.utils.AppTheme class SettingsFragment : BaseFragment() { @@ -18,6 +23,8 @@ class SettingsFragment : BaseFragment() { private var _binding: FragmentSettingsBinding? = null private val binding get() = _binding!! + private val mainViewModel by activityViewModels() + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -37,11 +44,37 @@ class SettingsFragment : BaseFragment() { findNavController().navigateUp() } + setupThemeMenu() + } + + private fun setupThemeMenu() { + val themes = listOf( + getString(R.string.theme_dark), + getString(R.string.theme_light), + getString(R.string.theme_system) + ) + binding.settingSelectTheme.setOnClickListener { + MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(getString(R.string.select_theme)) + setSingleChoiceItems( + themes.toTypedArray(), + mainViewModel.currentThemeIndex + ) { dialog, item -> + val theme = when (item) { + AppTheme.DARK.value -> AppTheme.DARK + AppTheme.LIGHT.value -> AppTheme.LIGHT + AppTheme.SYSTEM.value -> AppTheme.SYSTEM + else -> throw IllegalArgumentException("Unknown theme value") + } + mainViewModel.setTheme(theme) + dialog.dismiss() + } + }.also { it.show() } + } } - override fun onDestroyView() { - super.onDestroyView() - binding.rvList.adapter = null + override fun onDestroy() { + super.onDestroy() _binding = null } diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml index fcfbcd4..718db52 100644 --- a/app/src/main/res/menu/main_menu.xml +++ b/app/src/main/res/menu/main_menu.xml @@ -2,12 +2,6 @@ - - Date: Sat, 24 Jun 2023 23:05:00 +0530 Subject: [PATCH 6/9] refactored `ThemeManager` to `AppSettings` --- app/src/main/java/zechs/drive/stream/di/AppModule.kt | 4 ++-- .../main/java/zechs/drive/stream/ui/main/MainViewModel.kt | 7 ++++--- .../drive/stream/utils/{ThemeManager.kt => AppSettings.kt} | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) rename app/src/main/java/zechs/drive/stream/utils/{ThemeManager.kt => AppSettings.kt} (93%) diff --git a/app/src/main/java/zechs/drive/stream/di/AppModule.kt b/app/src/main/java/zechs/drive/stream/di/AppModule.kt index 28c3756..c0dd0e8 100755 --- a/app/src/main/java/zechs/drive/stream/di/AppModule.kt +++ b/app/src/main/java/zechs/drive/stream/di/AppModule.kt @@ -8,7 +8,7 @@ import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import zechs.drive.stream.utils.SessionManager -import zechs.drive.stream.utils.ThemeManager +import zechs.drive.stream.utils.AppSettings import javax.inject.Singleton @@ -33,6 +33,6 @@ object AppModule { @Provides fun provideThemeDataStore( @ApplicationContext appContext: Context - ): ThemeManager = ThemeManager(appContext) + ): AppSettings = AppSettings(appContext) } \ No newline at end of file diff --git a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt index 27385b5..ad4bc3d 100755 --- a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt +++ b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import zechs.drive.stream.data.model.LatestRelease import zechs.drive.stream.data.repository.GithubRepository +import zechs.drive.stream.utils.AppSettings import zechs.drive.stream.utils.AppTheme import zechs.drive.stream.utils.SessionManager import zechs.drive.stream.utils.ThemeManager @@ -23,7 +24,7 @@ import javax.inject.Inject class MainViewModel @Inject constructor( private val sessionManager: SessionManager, private val githubRepository: GithubRepository, - private val themeManager: ThemeManager + private val appSettings: AppSettings ) : ViewModel() { private val _isLoading = MutableStateFlow(true) @@ -64,13 +65,13 @@ class MainViewModel @Inject constructor( } private suspend fun getTheme() { - val fetchTheme = themeManager.fetchTheme() + val fetchTheme = appSettings.fetchTheme() currentThemeIndex = fetchTheme.value _theme.emit(fetchTheme) } fun setTheme(theme: AppTheme) = viewModelScope.launch { - themeManager.saveTheme(theme) + appSettings.saveTheme(theme) getTheme() } diff --git a/app/src/main/java/zechs/drive/stream/utils/ThemeManager.kt b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt similarity index 93% rename from app/src/main/java/zechs/drive/stream/utils/ThemeManager.kt rename to app/src/main/java/zechs/drive/stream/utils/AppSettings.kt index ae610ed..453ae2e 100644 --- a/app/src/main/java/zechs/drive/stream/utils/ThemeManager.kt +++ b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt @@ -11,15 +11,15 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class ThemeManager @Inject constructor( +class AppSettings @Inject constructor( @ApplicationContext appContext: Context ) { companion object { private val Context.dataStore by preferencesDataStore( - "APP_THEME" + "APP_SETTINGS" ) - const val TAG = "ThemeManager" + const val TAG = "AppSettings" const val APP_THEME = "APP_THEME" } From 20c2e03850f3f509eedda88aa885202ad1c3b83c Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 23:14:08 +0530 Subject: [PATCH 7/9] implemented default video player setting --- .../drive/stream/ui/files/FilesFragment.kt | 21 ++++++-------- .../drive/stream/ui/main/MainViewModel.kt | 16 ++++++++++- .../stream/ui/settings/SettingsFragment.kt | 26 +++++++++++++++++ .../zechs/drive/stream/utils/AppSettings.kt | 28 +++++++++++++++++++ app/src/main/res/values/strings.xml | 2 ++ 5 files changed, 79 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/zechs/drive/stream/ui/files/FilesFragment.kt b/app/src/main/java/zechs/drive/stream/ui/files/FilesFragment.kt index 012d46e..b886cb0 100644 --- a/app/src/main/java/zechs/drive/stream/ui/files/FilesFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/files/FilesFragment.kt @@ -11,6 +11,7 @@ import android.widget.TextView import androidx.core.view.isGone import androidx.core.view.isInvisible import androidx.core.view.isVisible +import androidx.fragment.app.activityViewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope @@ -23,7 +24,6 @@ import androidx.recyclerview.widget.RecyclerView import androidx.transition.Transition import androidx.transition.TransitionManager import com.google.android.material.color.MaterialColors -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.google.android.material.transition.MaterialFadeThrough import dagger.hilt.android.AndroidEntryPoint @@ -34,8 +34,10 @@ import zechs.drive.stream.databinding.FragmentFilesBinding import zechs.drive.stream.ui.BaseFragment import zechs.drive.stream.ui.files.adapter.FilesAdapter import zechs.drive.stream.ui.files.adapter.FilesDataModel +import zechs.drive.stream.ui.main.MainViewModel import zechs.drive.stream.ui.player.PlayerActivity import zechs.drive.stream.ui.player2.MPVActivity +import zechs.drive.stream.utils.VideoPlayer import zechs.drive.stream.utils.state.Resource @@ -49,6 +51,7 @@ class FilesFragment : BaseFragment() { private var _binding: FragmentFilesBinding? = null private val binding get() = _binding!! + private val mainViewModel by activityViewModels() private val viewModel by lazy { ViewModelProvider(this)[FilesViewModel::class.java] } @@ -244,18 +247,10 @@ class FilesFragment : BaseFragment() { } private fun launchVideoPlayer(file: DriveFile) { - - val items = arrayOf("ExoPlayer", "MPV") - - MaterialAlertDialogBuilder(requireContext()) - .setTitle(getString(R.string.play_using)) - .setItems(items) { dialog, which -> - when (which) { - 0 -> launchExo(file) - 1 -> viewModel.fetchToken(file) - } - dialog.dismiss() - }.show() + when (mainViewModel.currentPlayerIndex) { + VideoPlayer.EXO_PLAYER -> launchExo(file) + VideoPlayer.MPV -> viewModel.fetchToken(file) + } } private fun mpvObserver() { diff --git a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt index ad4bc3d..c9e97ac 100755 --- a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt +++ b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt @@ -16,7 +16,7 @@ import zechs.drive.stream.data.repository.GithubRepository import zechs.drive.stream.utils.AppSettings import zechs.drive.stream.utils.AppTheme import zechs.drive.stream.utils.SessionManager -import zechs.drive.stream.utils.ThemeManager +import zechs.drive.stream.utils.VideoPlayer import zechs.drive.stream.utils.state.Resource import javax.inject.Inject @@ -47,6 +47,7 @@ class MainViewModel @Inject constructor( viewModelScope.launch { getTheme() val status = getLoginStatus() + if (status) getPlayer() _hasLoggedIn.value = status delay(250L) _isLoading.value = false @@ -75,4 +76,17 @@ class MainViewModel @Inject constructor( getTheme() } + var currentPlayerIndex = VideoPlayer.MPV + private set + + private suspend fun getPlayer() { + val fetchPlayer = appSettings.fetchPlayer() + currentPlayerIndex = fetchPlayer + } + + fun setPlayer(player: VideoPlayer) = viewModelScope.launch { + appSettings.savePlayer(player) + getPlayer() + } + } diff --git a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt index 51ae657..e6278e5 100644 --- a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt @@ -12,6 +12,7 @@ import zechs.drive.stream.databinding.FragmentSettingsBinding import zechs.drive.stream.ui.BaseFragment import zechs.drive.stream.ui.main.MainViewModel import zechs.drive.stream.utils.AppTheme +import zechs.drive.stream.utils.VideoPlayer class SettingsFragment : BaseFragment() { @@ -45,6 +46,7 @@ class SettingsFragment : BaseFragment() { } setupThemeMenu() + setupDefaultPlayerMenu() } private fun setupThemeMenu() { @@ -73,6 +75,30 @@ class SettingsFragment : BaseFragment() { } } + private fun setupDefaultPlayerMenu() { + val players = listOf( + getString(R.string.exoplayer), + getString(R.string.mpv) + ) + binding.settingDefaultPlayer.setOnClickListener { + MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(getString(R.string.default_player)) + setSingleChoiceItems( + players.toTypedArray(), + mainViewModel.currentPlayerIndex.value + ) { dialog, item -> + val player = when (item) { + VideoPlayer.EXO_PLAYER.value -> VideoPlayer.EXO_PLAYER + VideoPlayer.MPV.value -> VideoPlayer.MPV + else -> throw IllegalArgumentException("Unknown default player") + } + mainViewModel.setPlayer(player) + dialog.dismiss() + } + }.also { it.show() } + } + } + override fun onDestroy() { super.onDestroy() _binding = null diff --git a/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt index 453ae2e..fcc48ac 100644 --- a/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt +++ b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt @@ -21,6 +21,7 @@ class AppSettings @Inject constructor( ) const val TAG = "AppSettings" const val APP_THEME = "APP_THEME" + const val VIDEO_PLAYER = "VIDEO_PLAYER" } private val sessionStore = appContext.dataStore @@ -45,6 +46,24 @@ class AppSettings @Inject constructor( return appTheme } + suspend fun savePlayer(player: VideoPlayer) { + val dataStoreKey = stringPreferencesKey(VIDEO_PLAYER) + sessionStore.edit { settings -> + settings[dataStoreKey] = player.text + } + Log.d(TAG, "savePlayer: ${player.text}") + } + + suspend fun fetchPlayer(): VideoPlayer { + val dataStoreKey = stringPreferencesKey(VIDEO_PLAYER) + val preferences = sessionStore.data.first() + val videoPlayer = when (preferences[dataStoreKey]) { + VideoPlayer.EXO_PLAYER.text -> VideoPlayer.EXO_PLAYER + else -> VideoPlayer.MPV + } + Log.d(TAG, "fetchPlayer: $videoPlayer") + return videoPlayer + } } enum class AppTheme( @@ -54,4 +73,13 @@ enum class AppTheme( DARK("Dark", 0), LIGHT("Light", 1), SYSTEM("System", 2) +} + +enum class VideoPlayer( + val text: String, + val value: Int +) { + EXO_PLAYER("ExoPlayer", 0), + MPV("MPV", 1), + } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54ec6f5..cdceb6f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,4 +65,6 @@ Default player Select default video player Check for updates + ExoPlayer + MPV \ No newline at end of file From 44e43fad94381f5b5040c166156a68e5028dabc6 Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 23:43:59 +0530 Subject: [PATCH 8/9] fix: contradicting function name --- .../main/java/zechs/drive/stream/data/model/LatestRelease.kt | 2 +- app/src/main/java/zechs/drive/stream/ui/main/MainActivity.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/zechs/drive/stream/data/model/LatestRelease.kt b/app/src/main/java/zechs/drive/stream/data/model/LatestRelease.kt index 00c5694..94937ea 100644 --- a/app/src/main/java/zechs/drive/stream/data/model/LatestRelease.kt +++ b/app/src/main/java/zechs/drive/stream/data/model/LatestRelease.kt @@ -13,6 +13,6 @@ data class LatestRelease( val htmlUrl: String ) { - fun isLatest() = tagName != BuildConfig.VERSION_NAME + fun isLatest() = tagName == BuildConfig.VERSION_NAME } \ No newline at end of file diff --git a/app/src/main/java/zechs/drive/stream/ui/main/MainActivity.kt b/app/src/main/java/zechs/drive/stream/ui/main/MainActivity.kt index 25965f1..7e9b3c3 100644 --- a/app/src/main/java/zechs/drive/stream/ui/main/MainActivity.kt +++ b/app/src/main/java/zechs/drive/stream/ui/main/MainActivity.kt @@ -134,10 +134,10 @@ class MainActivity : AppCompatActivity() { is Resource.Success -> { val release = it.data!! if (release.isLatest()) { + Log.d(TAG, "Already on latest version") + } else { Log.d(TAG, "Newer version of app is available (latest=${release.tagName})") sendUpdateNotification(release) - } else { - Log.d(TAG, "Already on latest version") } } is Resource.Error -> Log.d(TAG, it.message!!) From 7d315450c0ed8a77a5a63318c8064090689efd31 Mon Sep 17 00:00:00 2001 From: zechs Date: Sat, 24 Jun 2023 23:58:05 +0530 Subject: [PATCH 9/9] implemented manual `CheckForUpdate` option --- .../drive/stream/ui/main/MainViewModel.kt | 22 ++++++- .../stream/ui/settings/SettingsFragment.kt | 66 +++++++++++++++++++ .../zechs/drive/stream/utils/AppSettings.kt | 20 ++++++ .../drive/stream/utils/util/Converter.kt | 12 ++++ app/src/main/res/layout/fragment_settings.xml | 2 + 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt index c9e97ac..09c8d75 100755 --- a/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt +++ b/app/src/main/java/zechs/drive/stream/ui/main/MainViewModel.kt @@ -43,11 +43,20 @@ class MainViewModel @Inject constructor( var currentThemeIndex = 2 private set + private val _lastUpdated = MutableStateFlow(null) + val lastUpdated = _lastUpdated.asStateFlow() + + var isChecking = false + private set + init { viewModelScope.launch { getTheme() val status = getLoginStatus() - if (status) getPlayer() + if (status) { + getPlayer() + getLastUpdated() + } _hasLoggedIn.value = status delay(250L) _isLoading.value = false @@ -61,8 +70,17 @@ class MainViewModel @Inject constructor( return true } - private fun getLatestRelease() = viewModelScope.launch { + fun getLatestRelease() = viewModelScope.launch { + _latest.postValue(Resource.Loading()) + isChecking = true _latest.postValue(githubRepository.getLatestRelease()) + isChecking = false + appSettings.saveLastUpdated() + getLastUpdated() + } + + private fun getLastUpdated() = viewModelScope.launch { + _lastUpdated.emit(appSettings.fetchLastUpdated()) } private suspend fun getTheme() { diff --git a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt index e6278e5..8e3d233 100644 --- a/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/zechs/drive/stream/ui/settings/SettingsFragment.kt @@ -4,15 +4,23 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isInvisible import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.navigation.fragment.findNavController +import androidx.transition.TransitionManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.snackbar.Snackbar +import kotlinx.coroutines.launch import zechs.drive.stream.R import zechs.drive.stream.databinding.FragmentSettingsBinding import zechs.drive.stream.ui.BaseFragment import zechs.drive.stream.ui.main.MainViewModel import zechs.drive.stream.utils.AppTheme import zechs.drive.stream.utils.VideoPlayer +import zechs.drive.stream.utils.state.Resource class SettingsFragment : BaseFragment() { @@ -47,6 +55,7 @@ class SettingsFragment : BaseFragment() { setupThemeMenu() setupDefaultPlayerMenu() + setupCheckForUpdates() } private fun setupThemeMenu() { @@ -99,6 +108,63 @@ class SettingsFragment : BaseFragment() { } } + private fun setupCheckForUpdates() { + + var isUserClick = false + binding.settingCheckForUpdate.setOnClickListener { + if (!mainViewModel.isChecking) { + mainViewModel.getLatestRelease() + isUserClick = true + } + } + + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.RESUMED) { + mainViewModel.lastUpdated.collect { + if (it != null) { + val last = "Last checked: $it" + TransitionManager.beginDelayedTransition( + binding.settingCheckForUpdate, + ) + binding.lastCheckedLabel.text = last + } + } + } + } + + fun isChecking(bool: Boolean) { + binding.progressBarChecking.isInvisible = !bool + } + + mainViewModel.latest.observe(viewLifecycleOwner) { state -> + when (state) { + is Resource.Loading -> isChecking(true) + + is Resource.Error -> { + isChecking(false) + showSnackBar("Unable to check for updates") + } + + is Resource.Success -> { + isChecking(false) + val release = state.data!! + if (release.isLatest() && isUserClick) { + showSnackBar("You are already on the latest version") + } + } + } + } + + } + + private fun showSnackBar(message: String) { + Snackbar.make( + binding.root, + message, + Snackbar.LENGTH_SHORT + ).show() + } + override fun onDestroy() { super.onDestroy() _binding = null diff --git a/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt index fcc48ac..88e23af 100644 --- a/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt +++ b/app/src/main/java/zechs/drive/stream/utils/AppSettings.kt @@ -7,6 +7,7 @@ import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.first +import zechs.drive.stream.utils.util.Converter import javax.inject.Inject import javax.inject.Singleton @@ -22,6 +23,7 @@ class AppSettings @Inject constructor( const val TAG = "AppSettings" const val APP_THEME = "APP_THEME" const val VIDEO_PLAYER = "VIDEO_PLAYER" + const val LAST_UPDATED = "LAST_UPDATED" } private val sessionStore = appContext.dataStore @@ -64,6 +66,24 @@ class AppSettings @Inject constructor( Log.d(TAG, "fetchPlayer: $videoPlayer") return videoPlayer } + + suspend fun saveLastUpdated() { + val dataStoreKey = stringPreferencesKey(LAST_UPDATED) + val lastUpdated = System.currentTimeMillis() + sessionStore.edit { settings -> + settings[dataStoreKey] = lastUpdated.toString() + } + Log.d(TAG, "saveLastUpdated: ${Converter.fromTimeInMills(lastUpdated)}") + } + + suspend fun fetchLastUpdated(): String? { + val dataStoreKey = stringPreferencesKey(LAST_UPDATED) + val preferences = sessionStore.data.first() + val lastUpdated = preferences[dataStoreKey] ?: return null + val parsed = Converter.fromTimeInMills(lastUpdated.toLong()) + Log.d(TAG, "fetchLastUpdated: $parsed") + return parsed + } } enum class AppTheme( diff --git a/app/src/main/java/zechs/drive/stream/utils/util/Converter.kt b/app/src/main/java/zechs/drive/stream/utils/util/Converter.kt index 4bf9dcf..e68c142 100755 --- a/app/src/main/java/zechs/drive/stream/utils/util/Converter.kt +++ b/app/src/main/java/zechs/drive/stream/utils/util/Converter.kt @@ -1,5 +1,8 @@ package zechs.drive.stream.utils.util +import java.text.SimpleDateFormat +import java.util.Locale + object Converter { fun toHumanSize(size: Long): String { @@ -16,4 +19,13 @@ object Converter { } } + fun fromTimeInMills( + time: Long, + format: String = "hh:mm a dd MMM, yyyy", + ): String { + val date = java.util.Date(time) + val formatter = SimpleDateFormat(format, Locale.ENGLISH) + return formatter.format(date) + } + } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 6ebceb1..3207031 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -127,6 +127,7 @@ android:padding="16dp">