theme selection & gradle update
* it's now possible to change the app theme (light/dark) * update gradle to version 6.7.1 * update gradle pugin to version 4.1.1 * update kotlin to 1.4.10
This commit is contained in:
		| @ -38,6 +38,7 @@ import org.mosad.teapod.preferences.EncryptedPreferences | ||||
| import org.mosad.teapod.preferences.Preferences | ||||
| import org.mosad.teapod.ui.components.LoginDialog | ||||
| import org.mosad.teapod.ui.fragments.* | ||||
| import org.mosad.teapod.util.DataTypes | ||||
| import org.mosad.teapod.util.StorageController | ||||
| import org.mosad.teapod.util.TMDBApiController | ||||
| import kotlin.system.measureTimeMillis | ||||
| @ -46,13 +47,22 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS | ||||
|  | ||||
|     private var activeBaseFragment: Fragment = HomeFragment() // the currently active fragment, home at the start | ||||
|  | ||||
|     companion object { | ||||
|         var wasInitialized = false | ||||
|     } | ||||
|  | ||||
|     override fun onCreate(savedInstanceState: Bundle?) { | ||||
|         super.onCreate(savedInstanceState) | ||||
|  | ||||
|         if (!wasInitialized) { | ||||
|             load() | ||||
|         } | ||||
|  | ||||
|         theme.applyStyle(getThemeResource(), true) | ||||
|  | ||||
|         setContentView(R.layout.activity_main) | ||||
|         nav_view.setOnNavigationItemSelectedListener(this) | ||||
|  | ||||
|         load() | ||||
|  | ||||
|         supportFragmentManager.commit { | ||||
|             replace(R.id.nav_host_fragment, activeBaseFragment, activeBaseFragment.javaClass.simpleName) | ||||
|         } | ||||
| @ -102,6 +112,13 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS | ||||
|         return ret | ||||
|     } | ||||
|  | ||||
|     private fun getThemeResource(): Int { | ||||
|         return when (Preferences.theme) { | ||||
|             DataTypes.Theme.DARK -> R.style.AppTheme_Dark | ||||
|             else -> R.style.AppTheme_Light | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun load() { | ||||
|         // running login and list in parallel does not bring any speed improvements | ||||
|         val time = measureTimeMillis { | ||||
| @ -118,10 +135,26 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS | ||||
|  | ||||
|             StorageController.load(this) | ||||
|             AoDParser.initialLoading() | ||||
|  | ||||
|             wasInitialized = true | ||||
|         } | ||||
|         Log.i(javaClass.name, "login and list in $time ms") | ||||
|     } | ||||
|  | ||||
|     private fun showLoginDialog(firstTry: Boolean) { | ||||
|         LoginDialog(this, firstTry).positiveButton { | ||||
|             EncryptedPreferences.saveCredentials(login, password, context) | ||||
|  | ||||
|             if (!AoDParser.login()) { | ||||
|                 showLoginDialog(false) | ||||
|                 Log.w(javaClass.name, "Login failed, please try again.") | ||||
|             } | ||||
|         }.negativeButton { | ||||
|             Log.i(javaClass.name, "Login canceled, exiting.") | ||||
|             finish() | ||||
|         }.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show the media fragment for the selected media. | ||||
|      * While loading show the loading fragment. | ||||
| @ -159,17 +192,15 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS | ||||
|         startActivity(intent) | ||||
|     } | ||||
|  | ||||
|     private fun showLoginDialog(firstTry: Boolean) { | ||||
|         LoginDialog(this, firstTry).positiveButton { | ||||
|             EncryptedPreferences.saveCredentials(login, password, context) | ||||
|  | ||||
|             if (!AoDParser.login()) { | ||||
|                 showLoginDialog(false) | ||||
|                 Log.w(javaClass.name, "Login failed, please try again.") | ||||
|             } | ||||
|         }.negativeButton { | ||||
|             Log.i(javaClass.name, "Login canceled, exiting.") | ||||
|             finish() | ||||
|         }.show() | ||||
|     /** | ||||
|      * use custom restart instead of recreate(), since it has animations | ||||
|      */ | ||||
|     fun restart() { | ||||
|         val restartIntent = intent | ||||
|         restartIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) | ||||
|         finish() | ||||
|         startActivity(restartIntent) | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
| @ -1,7 +1,9 @@ | ||||
| package org.mosad.teapod.preferences | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.SharedPreferences | ||||
| import org.mosad.teapod.R | ||||
| import org.mosad.teapod.util.DataTypes | ||||
|  | ||||
| object Preferences { | ||||
|  | ||||
| @ -9,14 +11,18 @@ object Preferences { | ||||
|         internal set | ||||
|     var autoplay = true | ||||
|         internal set | ||||
|     var theme = DataTypes.Theme.LIGHT | ||||
|         internal set | ||||
|  | ||||
|     fun savePreferSecondary(context: Context, preferSecondary: Boolean) { | ||||
|         val sharedPref = context.getSharedPreferences( | ||||
|     private fun getSharedPref(context: Context): SharedPreferences { | ||||
|         return context.getSharedPreferences( | ||||
|             context.getString(R.string.preference_file_key), | ||||
|             Context.MODE_PRIVATE | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|         with(sharedPref.edit()) { | ||||
|     fun savePreferSecondary(context: Context, preferSecondary: Boolean) { | ||||
|         with(getSharedPref(context).edit()) { | ||||
|             putBoolean(context.getString(R.string.save_key_prefer_secondary), preferSecondary) | ||||
|             apply() | ||||
|         } | ||||
| @ -25,12 +31,7 @@ object Preferences { | ||||
|     } | ||||
|  | ||||
|     fun saveAutoplay(context: Context, autoplay: Boolean) { | ||||
|         val sharedPref = context.getSharedPreferences( | ||||
|             context.getString(R.string.preference_file_key), | ||||
|             Context.MODE_PRIVATE | ||||
|         ) | ||||
|  | ||||
|         with(sharedPref.edit()) { | ||||
|         with(getSharedPref(context).edit()) { | ||||
|             putBoolean(context.getString(R.string.save_key_autoplay), autoplay) | ||||
|             apply() | ||||
|         } | ||||
| @ -38,14 +39,20 @@ object Preferences { | ||||
|         this.autoplay = autoplay | ||||
|     } | ||||
|  | ||||
|     fun saveTheme(context: Context, theme: DataTypes.Theme) { | ||||
|         with(getSharedPref(context).edit()) { | ||||
|             putString(context.getString(R.string.save_key_theme), theme.toString()) | ||||
|             apply() | ||||
|         } | ||||
|  | ||||
|         this.theme = theme | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * initially load the stored values | ||||
|      */ | ||||
|     fun load(context: Context) { | ||||
|         val sharedPref = context.getSharedPreferences( | ||||
|             context.getString(R.string.preference_file_key), | ||||
|             Context.MODE_PRIVATE | ||||
|         ) | ||||
|         val sharedPref = getSharedPref(context) | ||||
|  | ||||
|         preferSecondary = sharedPref.getBoolean( | ||||
|             context.getString(R.string.save_key_prefer_secondary), false | ||||
| @ -53,6 +60,11 @@ object Preferences { | ||||
|         autoplay = sharedPref.getBoolean( | ||||
|             context.getString(R.string.save_key_autoplay), true | ||||
|         ) | ||||
|         theme = DataTypes.Theme.valueOf( | ||||
|             sharedPref.getString( | ||||
|                 context.getString(R.string.save_key_theme), DataTypes.Theme.LIGHT.toString() | ||||
|             ) ?:  DataTypes.Theme.LIGHT.toString() | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -7,17 +7,21 @@ import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import androidx.fragment.app.Fragment | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.afollestad.materialdialogs.list.listItemsSingleChoice | ||||
| import de.psdev.licensesdialog.LicensesDialog | ||||
| import kotlinx.android.synthetic.main.fragment_account.* | ||||
| import org.mosad.teapod.BuildConfig | ||||
| import org.mosad.teapod.MainActivity | ||||
| import org.mosad.teapod.R | ||||
| import org.mosad.teapod.parser.AoDParser | ||||
| import org.mosad.teapod.preferences.EncryptedPreferences | ||||
| import org.mosad.teapod.preferences.Preferences | ||||
| import org.mosad.teapod.ui.components.LoginDialog | ||||
| import org.mosad.teapod.util.DataTypes.Theme | ||||
|  | ||||
| class AccountFragment : Fragment() { | ||||
|  | ||||
|  | ||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | ||||
|         return inflater.inflate(R.layout.fragment_account, container, false) | ||||
|     } | ||||
| @ -27,6 +31,11 @@ class AccountFragment : Fragment() { | ||||
|  | ||||
|         text_account_login.text = EncryptedPreferences.login | ||||
|         text_info_about_desc.text = getString(R.string.info_about_desc, BuildConfig.VERSION_NAME, getString(R.string.build_time)) | ||||
|         text_theme_selected.text = when (Preferences.theme) { | ||||
|             Theme.DARK -> getString(R.string.theme_dark) | ||||
|             else -> getString(R.string.theme_light) | ||||
|         } | ||||
|  | ||||
|         switch_secondary.isChecked = Preferences.preferSecondary | ||||
|         switch_autoplay.isChecked = Preferences.autoplay | ||||
|  | ||||
| @ -38,6 +47,10 @@ class AccountFragment : Fragment() { | ||||
|             showLoginDialog(true) | ||||
|         } | ||||
|  | ||||
|         linear_theme.setOnClickListener { | ||||
|             showThemeDialog() | ||||
|         } | ||||
|  | ||||
|         linear_about.setOnClickListener { | ||||
|             MaterialDialog(requireContext()) | ||||
|                 .title(R.string.info_about) | ||||
| @ -46,15 +59,14 @@ class AccountFragment : Fragment() { | ||||
|         } | ||||
|  | ||||
|         text_licenses.setOnClickListener { | ||||
|             val selectedTheme = requireContext().applicationInfo.theme | ||||
|  | ||||
|             val dialogCss = when (selectedTheme) { | ||||
|                 R.style.AppTheme_Dark -> R.string.license_dialog_style_dark | ||||
|             val dialogCss = when (Preferences.theme) { | ||||
|                 Theme.DARK -> R.string.license_dialog_style_dark | ||||
|                 else -> R.string.license_dialog_style_light | ||||
|             } | ||||
|  | ||||
|             val themeId = when (selectedTheme) { | ||||
|                 R.style.AppTheme_Dark -> R.style.LicensesDialogTheme_Dark | ||||
|             val themeId = when (Preferences.theme) { | ||||
|                 Theme.DARK -> R.style.LicensesDialogTheme_Dark | ||||
|                 else -> R.style.AppTheme_Light | ||||
|             } | ||||
|  | ||||
| @ -90,4 +102,24 @@ class AccountFragment : Fragment() { | ||||
|             password = "" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun showThemeDialog() { | ||||
|         val themes = listOf( | ||||
|             resources.getString(R.string.theme_light), | ||||
|             resources.getString(R.string.theme_dark) | ||||
|         ) | ||||
|  | ||||
|         MaterialDialog(requireContext()).show { | ||||
|             title(R.string.theme) | ||||
|             listItemsSingleChoice(items = themes, initialSelection = Preferences.theme.ordinal) { _, index, _ -> | ||||
|                 when(index) { | ||||
|                     0 -> Preferences.saveTheme(context, Theme.LIGHT) | ||||
|                     1 -> Preferences.saveTheme(context, Theme.DARK) | ||||
|                     else -> Preferences.saveTheme(context, Theme.LIGHT) | ||||
|                 } | ||||
|  | ||||
|                 (activity as MainActivity).restart() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -6,6 +6,11 @@ class DataTypes { | ||||
|         MOVIE, | ||||
|         TVSHOW | ||||
|     } | ||||
|  | ||||
|     enum class Theme(val str: String) { | ||||
|         LIGHT("Light"), | ||||
|         DARK("Dark") | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  | ||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_style_24.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_style_24.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| <vector android:height="24dp" android:tint="#FFFFFF" | ||||
|     android:viewportHeight="24" android:viewportWidth="24" | ||||
|     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <path android:fillColor="@android:color/white" android:pathData="M2.53,19.65l1.34,0.56v-9.03l-2.43,5.86c-0.41,1.02 0.08,2.19 1.09,2.61zM22.03,15.95L17.07,3.98c-0.31,-0.75 -1.04,-1.21 -1.81,-1.23 -0.26,0 -0.53,0.04 -0.79,0.15L7.1,5.95c-0.75,0.31 -1.21,1.03 -1.23,1.8 -0.01,0.27 0.04,0.54 0.15,0.8l4.96,11.97c0.31,0.76 1.05,1.22 1.83,1.23 0.26,0 0.52,-0.05 0.77,-0.15l7.36,-3.05c1.02,-0.42 1.51,-1.59 1.09,-2.6zM7.88,8.75c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM5.88,19.75c0,1.1 0.9,2 2,2h1.45l-3.45,-8.34v6.34z"/> | ||||
| </vector> | ||||
| @ -222,6 +222,50 @@ | ||||
|                     </androidx.constraintlayout.widget.ConstraintLayout> | ||||
|                 </LinearLayout> | ||||
|  | ||||
|                 <LinearLayout | ||||
|                     android:id="@+id/linear_theme" | ||||
|                     android:layout_width="match_parent" | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:layout_margin="7dp" | ||||
|                     android:gravity="center" | ||||
|                     android:orientation="horizontal"> | ||||
|  | ||||
|                     <ImageView | ||||
|                         android:id="@+id/imageViewTheme" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content" | ||||
|                         android:contentDescription="@string/account" | ||||
|                         android:minWidth="48dp" | ||||
|                         android:minHeight="48dp" | ||||
|                         android:padding="9dp" | ||||
|                         android:scaleType="fitXY" | ||||
|                         android:src="@drawable/ic_baseline_style_24" | ||||
|                         app:tint="?iconNoAction" /> | ||||
|  | ||||
|                     <LinearLayout | ||||
|                         android:layout_width="match_parent" | ||||
|                         android:layout_height="match_parent" | ||||
|                         android:orientation="vertical"> | ||||
|  | ||||
|                         <TextView | ||||
|                             android:id="@+id/text_theme" | ||||
|                             android:layout_width="match_parent" | ||||
|                             android:layout_height="wrap_content" | ||||
|                             android:layout_weight="1" | ||||
|                             android:text="@string/theme" | ||||
|                             android:textSize="16sp" /> | ||||
|  | ||||
|                         <TextView | ||||
|                             android:id="@+id/text_theme_selected" | ||||
|                             android:layout_width="match_parent" | ||||
|                             android:layout_height="wrap_content" | ||||
|                             android:layout_weight="1" | ||||
|                             android:text="@string/theme_light" | ||||
|                             android:textColor="?textSecondary" /> | ||||
|                     </LinearLayout> | ||||
|  | ||||
|                 </LinearLayout> | ||||
|  | ||||
|             </LinearLayout> | ||||
|  | ||||
|             <LinearLayout | ||||
|  | ||||
| @ -31,6 +31,9 @@ | ||||
|     <string name="settings_secondary_desc">Untertitle-Stream verwenden, sofern vorhanden</string> | ||||
|     <string name="settings_autoplay">Autoplay</string> | ||||
|     <string name="settings_autoplay_desc">Nächste Episode automatisch abspielen</string> | ||||
|     <string name="theme">Design</string> | ||||
|     <string name="theme_light">Hell</string> | ||||
|     <string name="theme_dark">Dunkel</string> | ||||
|  | ||||
|     <!-- player --> | ||||
|     <string name="close_player">Player schließen</string> | ||||
|  | ||||
| @ -40,6 +40,10 @@ | ||||
|     <string name="settings_secondary_desc">Use the subtitles stream if present</string> | ||||
|     <string name="settings_autoplay">Autoplay</string> | ||||
|     <string name="settings_autoplay_desc">Play next episode automatically</string> | ||||
|     <string name="theme">Theme</string> | ||||
|     <string name="theme_light">Light</string> | ||||
|     <string name="theme_dark">Dark</string> | ||||
|  | ||||
|  | ||||
|     <!-- player --> | ||||
|     <string name="close_player">close player</string> | ||||
| @ -69,6 +73,7 @@ | ||||
|     <string name="save_key_user_password" translatable="false">org.mosad.teapod.user_password</string> | ||||
|     <string name="save_key_prefer_secondary" translatable="false">org.mosad.teapod.prefer_secondary</string> | ||||
|     <string name="save_key_autoplay" translatable="false">org.mosad.teapod.autoplay</string> | ||||
|     <string name="save_key_theme" translatable="false">org.mosad.teapod.theme</string> | ||||
|  | ||||
|     <!-- intents & states --> | ||||
|     <string name="intent_media_id" translatable="false">intent_media_id</string> | ||||
|  | ||||
| @ -18,7 +18,6 @@ | ||||
|         <item name="iconNoAction">@color/iconNoActionLight</item> | ||||
|         <item name="buttonBackground">@color/buttonBackgroundLight</item> | ||||
|         <item name="md_background_color">@color/themeSecondaryLight</item> | ||||
|         <item name="md_color_title">@color/textPrimaryLight</item> | ||||
|         <item name="md_color_content">@color/textSecondaryLight</item> | ||||
|     </style> | ||||
|  | ||||
| @ -34,8 +33,10 @@ | ||||
|         <item name="iconNoAction">@color/iconNoActionDark</item> | ||||
|         <item name="buttonBackground">@color/buttonBackgroundDark</item> | ||||
|         <item name="md_background_color">@color/themeSecondaryDark</item> | ||||
|         <item name="md_color_title">@color/textPrimaryDark</item> | ||||
|         <item name="md_color_content">@color/textSecondaryDark</item> | ||||
|  | ||||
|         <!-- without this, the unchecked single choice buttons while be black --> | ||||
|         <item name="md_color_widget_unchecked">@color/textSecondaryDark</item> | ||||
|     </style> | ||||
|  | ||||
|     <style name="LicensesDialogTheme.Dark" parent="Theme.AppCompat.Dialog"> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user