Skip to content

Commit 5fc8059

Browse files
update settings
- new fragment based categories - allow to control update check interval Known issue: - licenses screen is now an activity but may not respect user theme if it doesn't match system Signed-off-by: androidacy-user <[email protected]>
1 parent b429b7c commit 5fc8059

30 files changed

+2725
-2220
lines changed

app/build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ android {
119119
renderscriptOptimLevel = 3
120120
signingConfig = signingConfigs.getByName("release")
121121
multiDexEnabled = true
122+
isDebuggable = false
123+
isJniDebuggable = false
124+
isRenderscriptDebuggable = false
122125
}
123126
getByName("debug") {
124127
applicationIdSuffix = ".debug"
@@ -462,7 +465,7 @@ dependencies {
462465
implementation("com.github.KieronQuinn:MonetCompat:0.4.1")
463466
implementation("com.github.Fox2Code.FoxCompat:foxcompat:1.2.14")
464467
implementation("com.github.Fox2Code.FoxCompat:hiddenapis:1.2.14")
465-
implementation("com.mikepenz:aboutlibraries:10.8.2")
468+
implementation("com.mikepenz:aboutlibraries:10.8.3")
466469

467470
// Utils
468471
implementation("androidx.work:work-runtime:2.8.1")

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@
162162
</activity>
163163
<activity
164164
android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
165-
tools:node="remove" />
165+
android:exported="false"
166+
android:parentActivityName=".settings.SettingsActivity"
167+
android:theme="@style/Theme.MagiskModuleManager.NoActionBar" />
166168

167169
<provider
168170
android:name="androidx.startup.InitializationProvider"

app/src/main/kotlin/com/fox2code/mmm/background/BackgroundUpdateChecker.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,16 @@ class BackgroundUpdateChecker(context: Context, workerParams: WorkerParameters)
420420
).build()
421421
)
422422
notificationManagerCompat.cancel(NOTIFICATION_ID_ONGOING)
423-
// schedule periodic check for updates every 6 hours (6 * 60 * 60 = 21600) and not on low battery
424423
Timber.d("Scheduling periodic background check")
424+
// use pref_background_update_check_frequency to set frequency. value is in minutes
425+
val frequency = MainApplication.getSharedPreferences("mmm")!!
426+
.getInt("pref_background_update_check_frequency", 60).toLong()
427+
Timber.d("Frequency: $frequency minutes")
425428
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
426429
"background_checker",
427430
ExistingPeriodicWorkPolicy.UPDATE,
428431
PeriodicWorkRequest.Builder(
429-
BackgroundUpdateChecker::class.java, 21600, TimeUnit.SECONDS
432+
BackgroundUpdateChecker::class.java, frequency, TimeUnit.MINUTES
430433
).setConstraints(
431434
Constraints.Builder().setRequiresBatteryNotLow(true).build()
432435
).build()
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
package com.fox2code.mmm.settings
2+
3+
import android.content.ClipData
4+
import android.content.ClipboardManager
5+
import android.content.Context
6+
import android.content.DialogInterface
7+
import android.content.Intent
8+
import android.content.SharedPreferences
9+
import android.net.Uri
10+
import android.os.Build
11+
import android.os.Bundle
12+
import android.widget.Toast
13+
import androidx.preference.ListPreference
14+
import androidx.preference.Preference
15+
import androidx.preference.PreferenceFragmentCompat
16+
import androidx.preference.TwoStatePreference
17+
import androidx.security.crypto.EncryptedSharedPreferences
18+
import androidx.security.crypto.MasterKey
19+
import com.fox2code.foxcompat.app.FoxActivity
20+
import com.fox2code.mmm.MainApplication
21+
import com.fox2code.mmm.R
22+
import com.fox2code.rosettax.LanguageSwitcher
23+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
24+
import com.topjohnwu.superuser.internal.UiThreadHandler
25+
import timber.log.Timber
26+
27+
class AppearanceFragment : PreferenceFragmentCompat() {
28+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
29+
val name = "mmmx"
30+
val context: Context? = MainApplication.INSTANCE
31+
val masterKey: MasterKey
32+
val preferenceManager = preferenceManager
33+
val dataStore: SharedPreferenceDataStore
34+
val editor: SharedPreferences.Editor
35+
try {
36+
masterKey =
37+
MasterKey.Builder(context!!).setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
38+
.build()
39+
dataStore = SharedPreferenceDataStore(
40+
EncryptedSharedPreferences.create(
41+
context,
42+
name,
43+
masterKey,
44+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
45+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
46+
)
47+
)
48+
preferenceManager!!.preferenceDataStore = dataStore
49+
preferenceManager.sharedPreferencesName = "mmm"
50+
editor = dataStore.sharedPreferences.edit()
51+
} catch (e: Exception) {
52+
Timber.e(e, "Failed to create encrypted shared preferences")
53+
throw RuntimeException(getString(R.string.error_encrypted_shared_preferences))
54+
}
55+
setPreferencesFromResource(R.xml.theme_preferences, rootKey)
56+
57+
RepoFragment.applyMaterial3(preferenceScreen)
58+
val themePreference = findPreference<ListPreference>("pref_theme")
59+
// If transparent theme(s) are set, disable monet
60+
if (themePreference!!.value == "transparent_light") {
61+
Timber.d("disabling monet")
62+
findPreference<Preference>("pref_enable_monet")!!.isEnabled = false
63+
// Toggle monet off
64+
(findPreference<Preference>("pref_enable_monet") as TwoStatePreference?)!!.isChecked =
65+
false
66+
editor.putBoolean("pref_enable_monet", false).apply()
67+
// Set summary
68+
findPreference<Preference>("pref_enable_monet")!!.setSummary(R.string.monet_disabled_summary)
69+
// Same for blur
70+
findPreference<Preference>("pref_enable_blur")!!.isEnabled = false
71+
(findPreference<Preference>("pref_enable_blur") as TwoStatePreference?)!!.isChecked =
72+
false
73+
editor.putBoolean("pref_enable_blur", false).apply()
74+
findPreference<Preference>("pref_enable_blur")!!.setSummary(R.string.blur_disabled_summary)
75+
}
76+
themePreference.summaryProvider =
77+
Preference.SummaryProvider { _: Preference? -> themePreference.entry }
78+
themePreference.onPreferenceChangeListener =
79+
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
80+
Timber.d("refreshing activity. New value: %s", newValue)
81+
editor.putString("pref_theme", newValue as String).apply()
82+
// If theme contains "transparent" then disable monet
83+
if (newValue.toString().contains("transparent")) {
84+
Timber.d("disabling monet")
85+
// Show a dialogue warning the user about issues with transparent themes and
86+
// that blur/monet will be disabled
87+
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.transparent_theme_dialogue_title)
88+
.setMessage(
89+
R.string.transparent_theme_dialogue_message
90+
).setPositiveButton(R.string.ok) { _: DialogInterface?, _: Int ->
91+
// Toggle monet off
92+
(findPreference<Preference>("pref_enable_monet") as TwoStatePreference?)!!.isChecked =
93+
false
94+
editor.putBoolean("pref_enable_monet", false).apply()
95+
// Set summary
96+
findPreference<Preference>("pref_enable_monet")!!.setSummary(R.string.monet_disabled_summary)
97+
// Same for blur
98+
(findPreference<Preference>("pref_enable_blur") as TwoStatePreference?)!!.isChecked =
99+
false
100+
editor.putBoolean("pref_enable_blur", false).apply()
101+
findPreference<Preference>("pref_enable_blur")!!.setSummary(R.string.blur_disabled_summary)
102+
// Refresh activity
103+
UiThreadHandler.handler.postDelayed({
104+
MainApplication.INSTANCE!!.updateTheme()
105+
FoxActivity.getFoxActivity(this)
106+
.setThemeRecreate(MainApplication.INSTANCE!!.getManagerThemeResId())
107+
}, 1)
108+
val intent = Intent(requireContext(), SettingsActivity::class.java)
109+
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
110+
startActivity(intent)
111+
}.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int ->
112+
// Revert to system theme
113+
(findPreference<Preference>("pref_theme") as ListPreference?)!!.value =
114+
"system"
115+
// Refresh activity
116+
}.show()
117+
} else {
118+
findPreference<Preference>("pref_enable_monet")!!.isEnabled = true
119+
findPreference<Preference>("pref_enable_monet")?.summary = ""
120+
findPreference<Preference>("pref_enable_blur")!!.isEnabled = true
121+
findPreference<Preference>("pref_enable_blur")?.summary = ""
122+
}
123+
UiThreadHandler.handler.postDelayed({
124+
MainApplication.INSTANCE!!.updateTheme()
125+
FoxActivity.getFoxActivity(this).setThemeRecreate(MainApplication.INSTANCE!!.getManagerThemeResId())
126+
}, 1)
127+
true
128+
}
129+
130+
val disableMonet = findPreference<Preference>("pref_enable_monet")
131+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
132+
disableMonet!!.setSummary(R.string.require_android_12)
133+
disableMonet.isEnabled = false
134+
}
135+
disableMonet!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
136+
UiThreadHandler.handler.postDelayed({
137+
MainApplication.INSTANCE!!.updateTheme()
138+
(requireActivity() as FoxActivity).setThemeRecreate(MainApplication.INSTANCE!!.getManagerThemeResId())
139+
}, 1)
140+
true
141+
}
142+
143+
144+
val enableBlur = findPreference<Preference>("pref_enable_blur")
145+
// Disable blur on low performance devices
146+
if (SettingsActivity.devicePerformanceClass < SettingsActivity.PERFORMANCE_CLASS_AVERAGE) {
147+
// Show a warning
148+
enableBlur!!.onPreferenceChangeListener =
149+
Preference.OnPreferenceChangeListener { _: Preference?, newValue: Any ->
150+
if (newValue == true) {
151+
MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.low_performance_device_dialogue_title)
152+
.setMessage(
153+
R.string.low_performance_device_dialogue_message
154+
).setPositiveButton(R.string.ok) { _: DialogInterface?, _: Int ->
155+
// Toggle blur on
156+
(findPreference<Preference>("pref_enable_blur") as TwoStatePreference?)!!.isChecked =
157+
true
158+
editor.putBoolean("pref_enable_blur", true).apply()
159+
// Set summary
160+
findPreference<Preference>("pref_enable_blur")!!.setSummary(R.string.blur_disabled_summary)
161+
}
162+
.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int ->
163+
// Revert to blur on
164+
(findPreference<Preference>("pref_enable_blur") as TwoStatePreference?)!!.isChecked =
165+
false
166+
editor.putBoolean("pref_enable_blur", false).apply()
167+
// Set summary
168+
findPreference<Preference>("pref_enable_blur")?.summary =
169+
getString(R.string.blur_performance_warning_summary)
170+
}.show()
171+
}
172+
true
173+
}
174+
}
175+
176+
177+
// Handle pref_language_selector_cta by taking user to https://translate.nift4.org/engage/foxmmm/
178+
val languageSelectorCta =
179+
findPreference<LongClickablePreference>("pref_language_selector_cta")
180+
languageSelectorCta!!.onPreferenceClickListener =
181+
Preference.OnPreferenceClickListener { _: Preference? ->
182+
val browserIntent = Intent(
183+
Intent.ACTION_VIEW, Uri.parse("https://translate.nift4.org/engage/foxmmm/")
184+
)
185+
startActivity(browserIntent)
186+
true
187+
}
188+
189+
190+
val languageSelector = findPreference<Preference>("pref_language_selector")
191+
languageSelector!!.onPreferenceClickListener =
192+
Preference.OnPreferenceClickListener { _: Preference? ->
193+
val ls = LanguageSwitcher(
194+
requireActivity()
195+
)
196+
ls.setSupportedStringLocales(MainApplication.supportedLocales)
197+
ls.showChangeLanguageDialog(activity)
198+
true
199+
}
200+
201+
// Long click to copy url
202+
languageSelectorCta.onPreferenceLongClickListener =
203+
LongClickablePreference.OnPreferenceLongClickListener { _: Preference? ->
204+
val clipboard =
205+
requireContext().getSystemService(FoxActivity.CLIPBOARD_SERVICE) as ClipboardManager
206+
val clip =
207+
ClipData.newPlainText("URL", "https://translate.nift4.org/engage/foxmmm/")
208+
clipboard.setPrimaryClip(clip)
209+
Toast.makeText(requireContext(), R.string.link_copied, Toast.LENGTH_SHORT)
210+
.show()
211+
true
212+
}
213+
214+
val translatedBy = this.getString(R.string.language_translated_by)
215+
// I don't "translate" english
216+
if (!("Translated by Fox2Code (Put your name here)" == translatedBy || "Translated by Fox2Code" == translatedBy)) {
217+
languageSelector.setSummary(R.string.language_translated_by)
218+
} else {
219+
languageSelector.summary = null
220+
}
221+
}
222+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package com.fox2code.mmm.settings
2+
3+
import android.content.ClipData
4+
import android.content.ClipboardManager
5+
import android.content.Context
6+
import android.os.Bundle
7+
import android.widget.Toast
8+
import androidx.preference.Preference
9+
import androidx.preference.PreferenceFragmentCompat
10+
import androidx.security.crypto.EncryptedSharedPreferences
11+
import androidx.security.crypto.MasterKey
12+
import com.fox2code.foxcompat.app.FoxActivity
13+
import com.fox2code.mmm.BuildConfig
14+
import com.fox2code.mmm.MainApplication
15+
import com.fox2code.mmm.R
16+
import com.fox2code.mmm.utils.IntentHelper
17+
import timber.log.Timber
18+
19+
class CreditsFragment : PreferenceFragmentCompat() {
20+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
21+
22+
val name = "mmmx"
23+
val context: Context? = MainApplication.INSTANCE
24+
val masterKey: MasterKey
25+
val preferenceManager = preferenceManager
26+
val dataStore: SharedPreferenceDataStore
27+
try {
28+
masterKey =
29+
MasterKey.Builder(context!!).setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
30+
.build()
31+
dataStore = SharedPreferenceDataStore(
32+
EncryptedSharedPreferences.create(
33+
context,
34+
name,
35+
masterKey,
36+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
37+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
38+
)
39+
)
40+
preferenceManager!!.preferenceDataStore = dataStore
41+
preferenceManager.sharedPreferencesName = "mmm"
42+
} catch (e: Exception) {
43+
Timber.e(e, "Failed to create encrypted shared preferences")
44+
throw RuntimeException(getString(R.string.error_encrypted_shared_preferences))
45+
}
46+
47+
setPreferencesFromResource(R.xml.credits_preferences, rootKey)
48+
49+
50+
51+
val clipboard = requireContext().getSystemService(FoxActivity.CLIPBOARD_SERVICE) as ClipboardManager
52+
53+
// pref_contributors should lead to the contributors page
54+
var linkClickable: LongClickablePreference? = findPreference("pref_contributors")
55+
linkClickable!!.onPreferenceClickListener =
56+
Preference.OnPreferenceClickListener { p: Preference ->
57+
// Remove the .git if it exists and add /graphs/contributors
58+
var url = BuildConfig.REMOTE_URL
59+
if (url.endsWith(".git")) {
60+
url = url.substring(0, url.length - 4)
61+
}
62+
url += "/graphs/contributors"
63+
IntentHelper.openUrl(p.context, url)
64+
true
65+
}
66+
linkClickable.onPreferenceLongClickListener =
67+
LongClickablePreference.OnPreferenceLongClickListener { _: Preference? ->
68+
val toastText = requireContext().getString(R.string.link_copied)
69+
// Remove the .git if it exists and add /graphs/contributors
70+
var url = BuildConfig.REMOTE_URL
71+
if (url.endsWith(".git")) {
72+
url = url.substring(0, url.length - 4)
73+
}
74+
url += "/graphs/contributors"
75+
clipboard.setPrimaryClip(ClipData.newPlainText(toastText, url))
76+
Toast.makeText(requireContext(), toastText, Toast.LENGTH_SHORT).show()
77+
true
78+
}
79+
80+
81+
// Next, the pref_androidacy_thanks should lead to the androidacy website
82+
linkClickable = findPreference("pref_androidacy_thanks")
83+
linkClickable!!.onPreferenceClickListener =
84+
Preference.OnPreferenceClickListener { p: Preference ->
85+
IntentHelper.openUrl(
86+
p.context,
87+
"https://www.androidacy.com?utm_source=FoxMagiskModuleManager&utm_medium=app&utm_campaign=FoxMagiskModuleManager"
88+
)
89+
true
90+
}
91+
linkClickable.onPreferenceLongClickListener =
92+
LongClickablePreference.OnPreferenceLongClickListener { _: Preference? ->
93+
val toastText = requireContext().getString(R.string.link_copied)
94+
clipboard.setPrimaryClip(
95+
ClipData.newPlainText(
96+
toastText,
97+
"https://www.androidacy.com?utm_source=FoxMagiskModuleManager&utm_medium=app&utm_campaign=FoxMagiskModuleManager"
98+
)
99+
)
100+
Toast.makeText(requireContext(), toastText, Toast.LENGTH_SHORT).show()
101+
true
102+
}
103+
// pref_fox2code_thanks should lead to https://github.com/Fox2Code
104+
linkClickable = findPreference("pref_fox2code_thanks")
105+
linkClickable!!.onPreferenceClickListener =
106+
Preference.OnPreferenceClickListener { p: Preference ->
107+
IntentHelper.openUrl(p.context, "https://github.com/Fox2Code")
108+
true
109+
}
110+
linkClickable.onPreferenceLongClickListener =
111+
LongClickablePreference.OnPreferenceLongClickListener { _: Preference? ->
112+
val toastText = requireContext().getString(R.string.link_copied)
113+
clipboard.setPrimaryClip(
114+
ClipData.newPlainText(
115+
toastText, "https://github.com/Fox2Code"
116+
)
117+
)
118+
Toast.makeText(requireContext(), toastText, Toast.LENGTH_SHORT).show()
119+
true
120+
}
121+
}
122+
123+
}

0 commit comments

Comments
 (0)