WIP: Manage user settings

This commit is contained in:
Philipp Heckel 2022-01-28 14:40:09 -05:00
parent 437bc76b8c
commit 678e5625dd
6 changed files with 110 additions and 6 deletions

View file

@ -65,9 +65,9 @@ dependencies {
implementation "androidx.core:core-ktx:1.7.0" implementation "androidx.core:core-ktx:1.7.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.3" implementation "androidx.constraintlayout:constraintlayout:2.1.3"
implementation "androidx.activity:activity-ktx:1.4.0" implementation "androidx.activity:activity-ktx:1.4.0"
implementation "androidx.fragment:fragment-ktx:1.4.0" implementation "androidx.fragment:fragment-ktx:1.4.1"
implementation "androidx.work:work-runtime-ktx:2.7.1" implementation "androidx.work:work-runtime-ktx:2.7.1"
implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.preference:preference-ktx:1.2.0'
// JSON serialization // JSON serialization
implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.code.gson:gson:2.8.9'

View file

@ -22,10 +22,12 @@ import com.google.gson.Gson
import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.BuildConfig
import io.heckel.ntfy.R import io.heckel.ntfy.R
import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Repository
import io.heckel.ntfy.db.User
import io.heckel.ntfy.log.Log import io.heckel.ntfy.log.Log
import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.service.SubscriberService
import io.heckel.ntfy.util.formatBytes import io.heckel.ntfy.util.formatBytes
import io.heckel.ntfy.util.formatDateShort import io.heckel.ntfy.util.formatDateShort
import io.heckel.ntfy.util.shortUrl
import io.heckel.ntfy.util.toPriorityString import io.heckel.ntfy.util.toPriorityString
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -35,7 +37,13 @@ import okhttp3.RequestBody.Companion.toRequestBody
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class SettingsActivity : AppCompatActivity() { /**
* Main settings
*
* The "nested screen" navigation stuff (for user management) has been taken from
* https://github.com/googlearchive/android-preferences/blob/master/app/src/main/java/com/example/androidx/preference/sample/MainActivity.kt
*/
class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
private lateinit var fragment: SettingsFragment private lateinit var fragment: SettingsFragment
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -50,15 +58,58 @@ class SettingsActivity : AppCompatActivity() {
.beginTransaction() .beginTransaction()
.replace(R.id.settings_layout, fragment) .replace(R.id.settings_layout, fragment)
.commit() .commit()
} else {
title = savedInstanceState.getCharSequence(TITLE_TAG)
}
supportFragmentManager.addOnBackStackChangedListener {
if (supportFragmentManager.backStackEntryCount == 0) {
setTitle(R.string.settings_title)
}
} }
// Action bar // Action bar
title = getString(R.string.settings_title) //title = getString(R.string.settings_title)
// Show 'Back' button // Show 'Back' button
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
} }
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// Save current activity title so we can set it again after a configuration change
outState.putCharSequence(TITLE_TAG, title)
}
override fun onSupportNavigateUp(): Boolean {
if (supportFragmentManager.popBackStackImmediate()) {
return true
}
return super.onSupportNavigateUp()
}
override fun onPreferenceStartFragment(
caller: PreferenceFragmentCompat,
pref: Preference
): Boolean {
// Instantiate the new Fragment
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment!!
).apply {
arguments = args
setTargetFragment(caller, 0)
}
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.settings_layout, fragment)
.addToBackStack(null)
.commit()
title = pref.title
return true
}
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var repository: Repository private lateinit var repository: Repository
private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET private var autoDownloadSelection = AUTO_DOWNLOAD_SELECTION_NOT_SET
@ -463,6 +514,41 @@ class SettingsActivity : AppCompatActivity() {
data class NopasteResponse(val url: String) data class NopasteResponse(val url: String)
} }
class UserSettingsFragment : PreferenceFragmentCompat() {
private lateinit var repository: Repository
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.user_preferences, rootKey)
// Dependencies (Fragments need a default constructor)
repository = Repository.getInstance(requireActivity())
lifecycleScope.launch(Dispatchers.IO) {
val usersByBaseUrl = repository.getUsers().groupBy { it.baseUrl }
activity?.runOnUiThread {
addUserPreferences(usersByBaseUrl)
}
}
}
private fun addUserPreferences(usersByBaseUrl: Map<String, List<User>>) {
usersByBaseUrl.forEach { entry ->
val baseUrl = entry.key
val users = entry.value
val preferenceCategory = PreferenceCategory(preferenceScreen.context)
preferenceCategory.title = shortUrl(baseUrl)
preferenceScreen.addPreference(preferenceCategory)
users.forEach { user ->
val preference = Preference(preferenceScreen.context)
preference.title = user.username
preferenceCategory.addPreference(preference)
}
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_AUTO_DOWNLOAD) { if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_AUTO_DOWNLOAD) {
@ -479,6 +565,7 @@ class SettingsActivity : AppCompatActivity() {
companion object { companion object {
private const val TAG = "NtfySettingsActivity" private const val TAG = "NtfySettingsActivity"
private const val TITLE_TAG = "title"
private const val REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_AUTO_DOWNLOAD = 2586 private const val REQUEST_CODE_WRITE_EXTERNAL_STORAGE_PERMISSION_FOR_AUTO_DOWNLOAD = 2586
private const val AUTO_DOWNLOAD_SELECTION_NOT_SET = -99L private const val AUTO_DOWNLOAD_SELECTION_NOT_SET = -99L
private const val EXPORT_LOGS_COPY = "copy" private const val EXPORT_LOGS_COPY = "copy"

View file

@ -238,6 +238,11 @@
<string name="settings_appearance_dark_mode_entry_system">Use system default</string> <string name="settings_appearance_dark_mode_entry_system">Use system default</string>
<string name="settings_appearance_dark_mode_entry_light">Light mode</string> <string name="settings_appearance_dark_mode_entry_light">Light mode</string>
<string name="settings_appearance_dark_mode_entry_dark">Dark mode</string> <string name="settings_appearance_dark_mode_entry_dark">Dark mode</string>
<string name="settings_users_header">Users</string>
<string name="settings_users_key">ManageUsers</string>
<string name="settings_users_title">Manage users</string>
<string name="settings_users_summary">Add or remove users used for protected topics</string>
<string name="settings_users_prefs_title">Users</string>
<string name="settings_unified_push_header">UnifiedPush</string> <string name="settings_unified_push_header">UnifiedPush</string>
<string name="settings_unified_push_header_summary">Allows other apps to use ntfy as a message distributor. Find out more at unifiedpush.org.</string> <string name="settings_unified_push_header_summary">Allows other apps to use ntfy as a message distributor. Find out more at unifiedpush.org.</string>
<string name="settings_unified_push_enabled_key">UnifiedPushEnabled</string> <string name="settings_unified_push_enabled_key">UnifiedPushEnabled</string>

View file

@ -32,6 +32,15 @@
app:entryValues="@array/settings_appearance_dark_mode_values" app:entryValues="@array/settings_appearance_dark_mode_values"
app:defaultValue="-1"/> app:defaultValue="-1"/>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory
app:title="@string/settings_users_header"
app:layout="@layout/preference_category_material_edited">
<Preference
app:key="@string/settings_users_key"
app:title="@string/settings_users_title"
app:summary="@string/settings_users_summary"
app:fragment="io.heckel.ntfy.ui.SettingsActivity$UserSettingsFragment"/>
</PreferenceCategory>
<PreferenceCategory <PreferenceCategory
app:title="@string/settings_unified_push_header" app:title="@string/settings_unified_push_header"
app:summary="@string/settings_unified_push_header_summary" app:summary="@string/settings_unified_push_header_summary"

View file

@ -0,0 +1,3 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
app:title="@string/settings_users_prefs_title">
</PreferenceScreen>

View file

@ -1,3 +1,3 @@
Bug fixes: Bug fixes:
* Fix download issues on SDK 29 "Movement not allowed" (#116) * Fix download issues on SDK 29 "Movement not allowed" (#116, thanks Jakob)
* Fix for Android 12 crashes (#124) * Fix for Android 12 crashes (#124, thanks @eskilop)