From 9bbfad13f2735b3a882794a010a0caaf1aa7e1bb Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 5 Feb 2026 16:33:31 +0100 Subject: [PATCH 1/7] feat(settings): m3 theme selection dialog Signed-off-by: alperozturk96 --- app/src/main/AndroidManifest.xml | 2 +- .../nextcloud/client/di/ComponentsModule.java | 4 + .../activity/ChooseStorageLocationActivity.kt | 38 ----- .../ui/activity/ExtendedSettingsActivity.kt | 111 +++++++++++++++ .../android/ui/activity/SettingsActivity.java | 72 ++++++---- .../android/ui/dialog/ThemeSelectionDialog.kt | 133 ++++++++++++++++++ .../model/ExtendedSettingsActivityDialog.kt | 16 +++ app/src/main/res/xml/preferences.xml | 2 +- 8 files changed, 309 insertions(+), 69 deletions(-) delete mode 100644 app/src/main/java/com/owncloud/android/ui/activity/ChooseStorageLocationActivity.kt create mode 100644 app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt create mode 100644 app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt create mode 100644 app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ee6e7fd2bc80..20c10607b707 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -358,7 +358,7 @@ android:exported="false" android:launchMode="singleInstance" /> diff --git a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java index dc7194f78b0a..954fb16f8c3b 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -99,6 +99,7 @@ import com.owncloud.android.ui.dialog.SyncFileNotEnoughSpaceDialogFragment; import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment; import com.owncloud.android.ui.dialog.TermsOfServiceDialog; +import com.owncloud.android.ui.dialog.ThemeSelectionDialog; import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment; import com.owncloud.android.ui.fragment.ExtendedListFragment; import com.owncloud.android.ui.fragment.FeatureFragment; @@ -423,6 +424,9 @@ abstract class ComponentsModule { @ContributesAndroidInjector abstract ChooseStorageLocationDialogFragment chooseStorageLocationDialogFragment(); + @ContributesAndroidInjector + abstract ThemeSelectionDialog themeSelectionDialog(); + @ContributesAndroidInjector abstract SharePasswordDialogFragment sharePasswordDialogFragment(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ChooseStorageLocationActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ChooseStorageLocationActivity.kt deleted file mode 100644 index 8d13d53e7ddf..000000000000 --- a/app/src/main/java/com/owncloud/android/ui/activity/ChooseStorageLocationActivity.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2024 ZetaTom <70907959+ZetaTom@users.noreply.github.com> - * SPDX-License-Identifier: AGPL-3.0-or-later - */ - -package com.owncloud.android.ui.activity - -import android.content.Intent -import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity -import com.nextcloud.ui.ChooseStorageLocationDialogFragment - -class ChooseStorageLocationActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - val chooseStorageLocationDialogFragment = ChooseStorageLocationDialogFragment.newInstance() - supportFragmentManager.setFragmentResultListener( - KEY_RESULT_STORAGE_LOCATION, - this - ) { _, result -> - setResult( - ChooseStorageLocationDialogFragment.STORAGE_LOCATION_RESULT_CODE, - Intent().putExtra( - KEY_RESULT_STORAGE_LOCATION, - result.getString(KEY_RESULT_STORAGE_LOCATION) - ) - ) - } - chooseStorageLocationDialogFragment.show(supportFragmentManager, "choose_storage_location") - } - - companion object { - const val KEY_RESULT_STORAGE_LOCATION = ChooseStorageLocationDialogFragment.KEY_RESULT_STORAGE_LOCATION - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt new file mode 100644 index 000000000000..ca35dec46378 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt @@ -0,0 +1,111 @@ +package com.owncloud.android.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.nextcloud.ui.ChooseStorageLocationDialogFragment +import com.owncloud.android.ui.dialog.ThemeSelectionDialog +import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog + +class ExtendedSettingsActivity : AppCompatActivity() { + + private var dialogShown = false + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (savedInstanceState != null) { + dialogShown = savedInstanceState.getBoolean(KEY_DIALOG_SHOWN, false) + } + + if (dialogShown) { + return + } + + val dialogType = intent.getStringExtra(EXTRA_DIALOG_TYPE) ?: run { + finish() + return + } + + when (dialogType) { + ExtendedSettingsActivityDialog.StorageLocation.key -> { + setupStorageLocationDialog() + } + ExtendedSettingsActivityDialog.Theme.key -> { + setupThemeDialog() + } + else -> { + finish() + } + } + + dialogShown = true + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putBoolean(KEY_DIALOG_SHOWN, dialogShown) + } + + private fun setupStorageLocationDialog() { + if (supportFragmentManager.findFragmentByTag(TAG_STORAGE_DIALOG) != null) { + return + } + + val dialog = ChooseStorageLocationDialogFragment.newInstance() + + supportFragmentManager.setFragmentResultListener( + ExtendedSettingsActivityDialog.StorageLocation.key, + this + ) { _, result -> + setResult( + ChooseStorageLocationDialogFragment.STORAGE_LOCATION_RESULT_CODE, + Intent().putExtra( + ExtendedSettingsActivityDialog.StorageLocation.key, + result.getString(ExtendedSettingsActivityDialog.StorageLocation.key) + ) + ) + finish() + } + + dialog.show(supportFragmentManager, TAG_STORAGE_DIALOG) + } + + private fun setupThemeDialog() { + if (supportFragmentManager.findFragmentByTag(TAG_THEME_DIALOG) != null) { + return + } + + val dialog = ThemeSelectionDialog.newInstance() + + supportFragmentManager.setFragmentResultListener( + ThemeSelectionDialog.RESULT_KEY, + this + ) { _, result -> + setResult( + RESULT_OK, + Intent().putExtra( + ThemeSelectionDialog.RESULT_KEY, + result.getString(ThemeSelectionDialog.RESULT_KEY) + ) + ) + finish() + } + + dialog.show(supportFragmentManager, TAG_THEME_DIALOG) + } + + companion object { + private const val EXTRA_DIALOG_TYPE = "dialog_type" + private const val KEY_DIALOG_SHOWN = "dialog_shown" + private const val TAG_STORAGE_DIALOG = "choose_storage_location" + private const val TAG_THEME_DIALOG = "theme_selection" + + fun createIntent(context: Context, dialogType: ExtendedSettingsActivityDialog): Intent { + return Intent(context, ExtendedSettingsActivity::class.java).apply { + putExtra(EXTRA_DIALOG_TYPE, dialogType.key) + } + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index ba6db7333a81..02fad9543aa4 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -68,8 +68,10 @@ import com.owncloud.android.ui.ListPreferenceDialog; import com.owncloud.android.ui.ThemeableSwitchPreference; import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask; +import com.owncloud.android.ui.dialog.ThemeSelectionDialog; import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment; import com.owncloud.android.ui.helpers.FileOperationsHelper; +import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog; import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DeviceCredentialUtils; import com.owncloud.android.utils.DisplayUtils; @@ -80,7 +82,6 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; -import java.util.List; import java.util.Objects; import javax.inject.Inject; @@ -121,7 +122,6 @@ public class SettingsActivity extends PreferenceActivity private static final int ACTION_REQUEST_CODE_DAVDROID_SETUP = 10; private static final int ACTION_SHOW_MNEMONIC = 11; private static final int ACTION_E2E = 12; - private static final int ACTION_SET_STORAGE_LOCATION = 13; private static final int TRUE_VALUE = 1; private static final String DAV_PATH = "/remote.php/dav"; @@ -879,41 +879,50 @@ private void setupGeneralCategory() { prefDataLoc = findPreference(AppPreferencesImpl.DATA_STORAGE_LOCATION); if (prefDataLoc != null) { prefDataLoc.setOnPreferenceClickListener(p -> { - Intent intent = new Intent(MainApp.getAppContext(), ChooseStorageLocationActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivityForResult(intent, ACTION_SET_STORAGE_LOCATION); + Intent intent = ExtendedSettingsActivity.Companion.createIntent(this, ExtendedSettingsActivityDialog.StorageLocation); + startActivityForResult(intent, ExtendedSettingsActivityDialog.StorageLocation.getResultId()); return true; }); } - ListPreference themePref = (ListPreference) findPreference("darkMode"); + final var themePref = findPreference("darkMode"); + if (themePref != null) { + updateThemePreferenceSummary(preferences.getDarkThemeMode().name()); - List themeEntries = new ArrayList<>(3); - themeEntries.add(getString(R.string.prefs_value_theme_light)); - themeEntries.add(getString(R.string.prefs_value_theme_dark)); - themeEntries.add(getString(R.string.prefs_value_theme_system)); - - List themeValues = new ArrayList<>(3); - themeValues.add(DarkMode.LIGHT.name()); - themeValues.add(DarkMode.DARK.name()); - themeValues.add(DarkMode.SYSTEM.name()); + themePref.setOnPreferenceClickListener(preference -> { + Intent intent = ExtendedSettingsActivity.Companion.createIntent(this, ExtendedSettingsActivityDialog.Theme); + startActivityForResult(intent, ExtendedSettingsActivityDialog.Theme.getResultId()); + return true; + }); + } + } - themePref.setEntries(themeEntries.toArray(new String[0])); - themePref.setEntryValues(themeValues.toArray(new String[0])); + private void updateThemePreferenceSummary(String themeValue) { + Preference themePref = findPreference("darkMode"); + if (themePref == null) return; - if (TextUtils.isEmpty(themePref.getEntry())) { - themePref.setValue(DarkMode.SYSTEM.name()); - themePref.setSummary(TextUtils.isEmpty(themePref.getEntry()) ? DarkMode.SYSTEM.name() : themePref.getEntry()); + DarkMode mode; + try { + mode = DarkMode.valueOf(themeValue); + } catch (IllegalArgumentException e) { + mode = DarkMode.SYSTEM; } - themePref.setOnPreferenceChangeListener((preference, newValue) -> { - DarkMode mode = DarkMode.valueOf((String) newValue); - preferences.setDarkThemeMode(mode); - MainApp.setAppTheme(mode); - setListBackground(); + String summary; + switch (mode) { + case LIGHT: + summary = getString(R.string.prefs_value_theme_light); + break; + case DARK: + summary = getString(R.string.prefs_value_theme_dark); + break; + case SYSTEM: + default: + summary = getString(R.string.prefs_value_theme_system); + break; + } - return true; - }); + themePref.setSummary(summary); } private void setListBackground() { @@ -1052,8 +1061,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else if (requestCode == ACTION_E2E && data != null && data.getBooleanExtra(SetupEncryptionDialogFragment.SUCCESS, false)) { Intent i = new Intent(this, SettingsActivity.class); startActivity(i); - } else if (requestCode == ACTION_SET_STORAGE_LOCATION && data != null) { - String newPath = data.getStringExtra(ChooseStorageLocationActivity.KEY_RESULT_STORAGE_LOCATION); + } else if (requestCode == ExtendedSettingsActivityDialog.StorageLocation.getResultId() && data != null) { + String newPath = data.getStringExtra(ExtendedSettingsActivityDialog.StorageLocation.getKey()); if (storagePath != null && !storagePath.equals(newPath)) { StorageMigration storageMigration = new StorageMigration(this, user, storagePath, newPath, viewThemeUtils); @@ -1063,6 +1072,11 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else if (requestCode == REQ_ALL_FILES_ACCESS) { final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync"); setupAllFilesAccessPreference(preferenceCategorySync); + } else if (requestCode == ExtendedSettingsActivityDialog.StorageLocation.getResultId() && data != null) { + String selectedTheme = data.getStringExtra(ThemeSelectionDialog.RESULT_KEY); + if (selectedTheme != null) { + updateThemePreferenceSummary(selectedTheme); + } } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt new file mode 100644 index 000000000000..15d276eee269 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -0,0 +1,133 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.dialog + +import android.app.Dialog +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import android.widget.RadioButton +import androidx.fragment.app.DialogFragment +import androidx.appcompat.app.AlertDialog +import androidx.core.os.bundleOf +import androidx.fragment.app.setFragmentResult +import com.google.android.material.button.MaterialButton +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.client.preferences.AppPreferencesImpl +import com.nextcloud.client.preferences.DarkMode +import com.owncloud.android.MainApp +import com.owncloud.android.R +import com.nextcloud.client.di.Injectable +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject + +class ThemeSelectionDialog : DialogFragment(), Injectable { + + @Inject + lateinit var preferences: AppPreferences + + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + + override fun onStart() { + super.onStart() + colorButtons() + colorRadioButtons() + } + + private fun colorButtons() { + val dialog = dialog + + if (dialog is AlertDialog) { + val positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton + positiveButton?.let { + viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) + } + } + } + + private fun colorRadioButtons() { + val dialog = dialog + if (dialog is AlertDialog) { + val listView = dialog.listView ?: return + + for (i in 0 until listView.childCount) { + val row = listView.getChildAt(i) + + val radioButton = findRadioButtonInView(row) + radioButton?.let { + viewThemeUtils.platform.themeRadioButton(it) + } + } + } + } + + private fun findRadioButtonInView(view: View): RadioButton? { + if (view is RadioButton) return view + if (view is ViewGroup) { + for (i in 0 until view.childCount) { + findRadioButtonInView(view.getChildAt(i))?.let { return it } + } + } + return null + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + preferences = AppPreferencesImpl.fromContext(context) + + val themeEntries = arrayOf( + getString(R.string.prefs_value_theme_light), + getString(R.string.prefs_value_theme_dark), + getString(R.string.prefs_value_theme_system) + ) + + val themeValues = arrayOf( + DarkMode.LIGHT.name, + DarkMode.DARK.name, + DarkMode.SYSTEM.name + ) + + val currentTheme = preferences.getDarkThemeMode()?.name ?: DarkMode.SYSTEM.name + val selectedIndex = themeValues.indexOf(currentTheme) + + val builder = MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.prefs_theme_title) + .setSingleChoiceItems(themeEntries, selectedIndex) { dialog, which -> + if (which >= 0 && which < themeValues.size) { + val selectedValue = themeValues[which] + val mode = DarkMode.valueOf(selectedValue) + + preferences.setDarkThemeMode(mode) + MainApp.setAppTheme(mode) + + setFragmentResult( + RESULT_KEY, + bundleOf(RESULT_KEY to selectedValue) + ) + + dialog.dismiss() + } + } + .setPositiveButton(R.string.common_cancel) { _, _ -> + dismiss() + } + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) + + return builder.create() + } + + companion object { + const val RESULT_KEY = "theme_selection_result" + + fun newInstance(): ThemeSelectionDialog { + return ThemeSelectionDialog() + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt b/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt new file mode 100644 index 000000000000..e456b098e996 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt @@ -0,0 +1,16 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui.model + +import com.nextcloud.ui.ChooseStorageLocationDialogFragment +import com.owncloud.android.ui.dialog.ThemeSelectionDialog + +enum class ExtendedSettingsActivityDialog(val key: String, val resultId: Int) { + StorageLocation(ChooseStorageLocationDialogFragment.KEY_RESULT_STORAGE_LOCATION, 13), + Theme(ThemeSelectionDialog.RESULT_KEY, 14) +} diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index adada5180474..ff17922ff1f8 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -17,7 +17,7 @@ android:title="@string/prefs_data_storage_location" android:key="data_storage_location" android:summary="@string/prefs_data_storage_location_summary" /> - From c4e598bf68d9ce14367d942459151e6df77e5f2d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 5 Feb 2026 16:34:53 +0100 Subject: [PATCH 2/7] feat(settings): m3 theme selection dialog Signed-off-by: alperozturk96 --- .../android/ui/activity/SettingsActivity.java | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index 02fad9543aa4..66e3f851dc50 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -908,19 +908,11 @@ private void updateThemePreferenceSummary(String themeValue) { mode = DarkMode.SYSTEM; } - String summary; - switch (mode) { - case LIGHT: - summary = getString(R.string.prefs_value_theme_light); - break; - case DARK: - summary = getString(R.string.prefs_value_theme_dark); - break; - case SYSTEM: - default: - summary = getString(R.string.prefs_value_theme_system); - break; - } + String summary = switch (mode) { + case LIGHT -> getString(R.string.prefs_value_theme_light); + case DARK -> getString(R.string.prefs_value_theme_dark); + default -> getString(R.string.prefs_value_theme_system); + }; themePref.setSummary(summary); } From 3d206ae3e2c377d34a48f1555da6df1be34ce45d Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Thu, 5 Feb 2026 16:37:14 +0100 Subject: [PATCH 3/7] feat(settings): m3 theme selection dialog Signed-off-by: alperozturk96 --- .../java/com/owncloud/android/ui/activity/SettingsActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index 66e3f851dc50..cbd7746c3dd2 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -1064,7 +1064,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else if (requestCode == REQ_ALL_FILES_ACCESS) { final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync"); setupAllFilesAccessPreference(preferenceCategorySync); - } else if (requestCode == ExtendedSettingsActivityDialog.StorageLocation.getResultId() && data != null) { + } else if (requestCode == ExtendedSettingsActivityDialog.Theme.getResultId() && data != null) { String selectedTheme = data.getStringExtra(ThemeSelectionDialog.RESULT_KEY); if (selectedTheme != null) { updateThemePreferenceSummary(selectedTheme); From b9bd896195a74e445c38e3a0bb057a362dc171ed Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 6 Feb 2026 09:04:56 +0100 Subject: [PATCH 4/7] simplify code Signed-off-by: alperozturk96 --- .../ui/ChooseStorageLocationDialogFragment.kt | 11 +-- .../ui/activity/ExtendedSettingsActivity.kt | 81 ++++--------------- .../android/ui/activity/SettingsActivity.java | 16 ++-- .../android/ui/dialog/ThemeSelectionDialog.kt | 25 +++--- .../model/ExtendedSettingsActivityDialog.kt | 40 ++++++++- 5 files changed, 71 insertions(+), 102 deletions(-) diff --git a/app/src/main/java/com/nextcloud/ui/ChooseStorageLocationDialogFragment.kt b/app/src/main/java/com/nextcloud/ui/ChooseStorageLocationDialogFragment.kt index fc9760fd92b9..5b95203c6900 100644 --- a/app/src/main/java/com/nextcloud/ui/ChooseStorageLocationDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/ChooseStorageLocationDialogFragment.kt @@ -25,6 +25,7 @@ import com.owncloud.android.datastorage.DataStorageProvider import com.owncloud.android.datastorage.StoragePoint import com.owncloud.android.datastorage.StoragePoint.PrivacyType import com.owncloud.android.datastorage.StoragePoint.StorageType +import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File @@ -151,19 +152,13 @@ class ChooseStorageLocationDialogFragment : ?: return val resultBundle = Bundle().apply { - putString(KEY_RESULT_STORAGE_LOCATION, newPath.path) + putString(ExtendedSettingsActivityDialog.StorageLocation.key, newPath.path) } - parentFragmentManager.setFragmentResult(KEY_RESULT_STORAGE_LOCATION, resultBundle) + parentFragmentManager.setFragmentResult(ExtendedSettingsActivityDialog.StorageLocation.key, resultBundle) } companion object { - const val KEY_RESULT_STORAGE_LOCATION = "KEY_RESULT_STORAGE_LOCATION" - const val STORAGE_LOCATION_RESULT_CODE = 100 - - @JvmStatic - fun newInstance() = ChooseStorageLocationDialogFragment() - @JvmStatic val TAG: String = Companion::class.java.simpleName } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt index ca35dec46378..d96c91f2c0c8 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt @@ -1,17 +1,23 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + package com.owncloud.android.ui.activity import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AppCompatActivity -import com.nextcloud.ui.ChooseStorageLocationDialogFragment -import com.owncloud.android.ui.dialog.ThemeSelectionDialog import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog class ExtendedSettingsActivity : AppCompatActivity() { private var dialogShown = false + @Suppress("ReturnCount") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -23,23 +29,17 @@ class ExtendedSettingsActivity : AppCompatActivity() { return } - val dialogType = intent.getStringExtra(EXTRA_DIALOG_TYPE) ?: run { + val dialogKey = intent.getStringExtra(EXTRA_DIALOG_TYPE) ?: run { finish() return } - when (dialogType) { - ExtendedSettingsActivityDialog.StorageLocation.key -> { - setupStorageLocationDialog() - } - ExtendedSettingsActivityDialog.Theme.key -> { - setupThemeDialog() - } - else -> { - finish() - } + val dialogType = ExtendedSettingsActivityDialog.entries.find { it.key == dialogKey } ?: run { + finish() + return } + dialogType.showDialog(this) dialogShown = true } @@ -48,64 +48,13 @@ class ExtendedSettingsActivity : AppCompatActivity() { outState.putBoolean(KEY_DIALOG_SHOWN, dialogShown) } - private fun setupStorageLocationDialog() { - if (supportFragmentManager.findFragmentByTag(TAG_STORAGE_DIALOG) != null) { - return - } - - val dialog = ChooseStorageLocationDialogFragment.newInstance() - - supportFragmentManager.setFragmentResultListener( - ExtendedSettingsActivityDialog.StorageLocation.key, - this - ) { _, result -> - setResult( - ChooseStorageLocationDialogFragment.STORAGE_LOCATION_RESULT_CODE, - Intent().putExtra( - ExtendedSettingsActivityDialog.StorageLocation.key, - result.getString(ExtendedSettingsActivityDialog.StorageLocation.key) - ) - ) - finish() - } - - dialog.show(supportFragmentManager, TAG_STORAGE_DIALOG) - } - - private fun setupThemeDialog() { - if (supportFragmentManager.findFragmentByTag(TAG_THEME_DIALOG) != null) { - return - } - - val dialog = ThemeSelectionDialog.newInstance() - - supportFragmentManager.setFragmentResultListener( - ThemeSelectionDialog.RESULT_KEY, - this - ) { _, result -> - setResult( - RESULT_OK, - Intent().putExtra( - ThemeSelectionDialog.RESULT_KEY, - result.getString(ThemeSelectionDialog.RESULT_KEY) - ) - ) - finish() - } - - dialog.show(supportFragmentManager, TAG_THEME_DIALOG) - } - companion object { private const val EXTRA_DIALOG_TYPE = "dialog_type" private const val KEY_DIALOG_SHOWN = "dialog_shown" - private const val TAG_STORAGE_DIALOG = "choose_storage_location" - private const val TAG_THEME_DIALOG = "theme_selection" - fun createIntent(context: Context, dialogType: ExtendedSettingsActivityDialog): Intent { - return Intent(context, ExtendedSettingsActivity::class.java).apply { + fun createIntent(context: Context, dialogType: ExtendedSettingsActivityDialog): Intent = + Intent(context, ExtendedSettingsActivity::class.java).apply { putExtra(EXTRA_DIALOG_TYPE, dialogType.key) } - } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index cbd7746c3dd2..ae070dbdd918 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -68,7 +68,6 @@ import com.owncloud.android.ui.ListPreferenceDialog; import com.owncloud.android.ui.ThemeableSwitchPreference; import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask; -import com.owncloud.android.ui.dialog.ThemeSelectionDialog; import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog; @@ -890,8 +889,8 @@ private void setupGeneralCategory() { updateThemePreferenceSummary(preferences.getDarkThemeMode().name()); themePref.setOnPreferenceClickListener(preference -> { - Intent intent = ExtendedSettingsActivity.Companion.createIntent(this, ExtendedSettingsActivityDialog.Theme); - startActivityForResult(intent, ExtendedSettingsActivityDialog.Theme.getResultId()); + Intent intent = ExtendedSettingsActivity.Companion.createIntent(this, ExtendedSettingsActivityDialog.ThemeSelection); + startActivityForResult(intent, ExtendedSettingsActivityDialog.ThemeSelection.getResultId()); return true; }); } @@ -1055,20 +1054,19 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { startActivity(i); } else if (requestCode == ExtendedSettingsActivityDialog.StorageLocation.getResultId() && data != null) { String newPath = data.getStringExtra(ExtendedSettingsActivityDialog.StorageLocation.getKey()); - if (storagePath != null && !storagePath.equals(newPath)) { StorageMigration storageMigration = new StorageMigration(this, user, storagePath, newPath, viewThemeUtils); storageMigration.setStorageMigrationProgressListener(this); storageMigration.migrate(); } - } else if (requestCode == REQ_ALL_FILES_ACCESS) { - final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync"); - setupAllFilesAccessPreference(preferenceCategorySync); - } else if (requestCode == ExtendedSettingsActivityDialog.Theme.getResultId() && data != null) { - String selectedTheme = data.getStringExtra(ThemeSelectionDialog.RESULT_KEY); + } else if (requestCode == ExtendedSettingsActivityDialog.ThemeSelection.getResultId() && data != null) { + String selectedTheme = data.getStringExtra(ExtendedSettingsActivityDialog.ThemeSelection.getKey()); if (selectedTheme != null) { updateThemePreferenceSummary(selectedTheme); } + } else if (requestCode == REQ_ALL_FILES_ACCESS) { + final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync"); + setupAllFilesAccessPreference(preferenceCategorySync); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt index 15d276eee269..276385ad5de4 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -12,22 +12,24 @@ import android.os.Bundle import android.view.View import android.view.ViewGroup import android.widget.RadioButton -import androidx.fragment.app.DialogFragment import androidx.appcompat.app.AlertDialog import androidx.core.os.bundleOf +import androidx.fragment.app.DialogFragment import androidx.fragment.app.setFragmentResult import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.client.preferences.AppPreferencesImpl import com.nextcloud.client.preferences.DarkMode import com.owncloud.android.MainApp import com.owncloud.android.R -import com.nextcloud.client.di.Injectable +import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject -class ThemeSelectionDialog : DialogFragment(), Injectable { +class ThemeSelectionDialog : + DialogFragment(), + Injectable { @Inject lateinit var preferences: AppPreferences @@ -68,6 +70,7 @@ class ThemeSelectionDialog : DialogFragment(), Injectable { } } + @Suppress("ReturnCount") private fun findRadioButtonInView(view: View): RadioButton? { if (view is RadioButton) return view if (view is ViewGroup) { @@ -79,8 +82,6 @@ class ThemeSelectionDialog : DialogFragment(), Injectable { } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - preferences = AppPreferencesImpl.fromContext(context) - val themeEntries = arrayOf( getString(R.string.prefs_value_theme_light), getString(R.string.prefs_value_theme_dark), @@ -107,8 +108,8 @@ class ThemeSelectionDialog : DialogFragment(), Injectable { MainApp.setAppTheme(mode) setFragmentResult( - RESULT_KEY, - bundleOf(RESULT_KEY to selectedValue) + ExtendedSettingsActivityDialog.ThemeSelection.key, + bundleOf(ExtendedSettingsActivityDialog.ThemeSelection.key to selectedValue) ) dialog.dismiss() @@ -122,12 +123,4 @@ class ThemeSelectionDialog : DialogFragment(), Injectable { return builder.create() } - - companion object { - const val RESULT_KEY = "theme_selection_result" - - fun newInstance(): ThemeSelectionDialog { - return ThemeSelectionDialog() - } - } } diff --git a/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt b/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt index e456b098e996..4316d78f7755 100644 --- a/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt @@ -7,10 +7,44 @@ package com.owncloud.android.ui.model +import android.app.Activity.RESULT_OK +import android.content.Intent import com.nextcloud.ui.ChooseStorageLocationDialogFragment +import com.owncloud.android.ui.activity.ExtendedSettingsActivity import com.owncloud.android.ui.dialog.ThemeSelectionDialog -enum class ExtendedSettingsActivityDialog(val key: String, val resultId: Int) { - StorageLocation(ChooseStorageLocationDialogFragment.KEY_RESULT_STORAGE_LOCATION, 13), - Theme(ThemeSelectionDialog.RESULT_KEY, 14) +@Suppress("MagicNumber") +enum class ExtendedSettingsActivityDialog(val tag: String, val key: String, val resultId: Int) { + StorageLocation("choose_storage_location", "storage_selection_result", 13), + ThemeSelection("theme_selection", "theme_selection_result", 14); + + fun showDialog(activity: ExtendedSettingsActivity) { + activity.run { + if (supportFragmentManager.findFragmentByTag(tag) != null) { + return + } + + supportFragmentManager.setFragmentResultListener( + key, + this + ) { _, result -> + setResult( + RESULT_OK, + Intent().putExtra( + key, + result.getString(key) + ) + ) + finish() + } + + if (this@ExtendedSettingsActivityDialog == StorageLocation) { + ChooseStorageLocationDialogFragment() + } else { + ThemeSelectionDialog() + }.run { + show(supportFragmentManager, tag) + } + } + } } From 542f785988cb1b9c4a4475dc8e8ff4ca73d79934 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 6 Feb 2026 09:08:43 +0100 Subject: [PATCH 5/7] simplify code Signed-off-by: alperozturk96 --- .../java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt index 276385ad5de4..1d7f619bf1f6 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -115,7 +115,7 @@ class ThemeSelectionDialog : dialog.dismiss() } } - .setPositiveButton(R.string.common_cancel) { _, _ -> + .setPositiveButton(R.string.common_ok) { _, _ -> dismiss() } From 17c4356b082f08ef9bd510c2ec980b8831b4c380 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 6 Feb 2026 09:26:09 +0100 Subject: [PATCH 6/7] color dialog Signed-off-by: alperozturk96 --- .../android/ui/activity/SettingsActivity.java | 1 + .../android/ui/dialog/ThemeSelectionDialog.kt | 106 +++++++----------- .../res/layout/dialog_theme_selection.xml | 65 +++++++++++ 3 files changed, 106 insertions(+), 66 deletions(-) create mode 100644 app/src/main/res/layout/dialog_theme_selection.xml diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index ae070dbdd918..c29605b62d07 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -1063,6 +1063,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { String selectedTheme = data.getStringExtra(ExtendedSettingsActivityDialog.ThemeSelection.getKey()); if (selectedTheme != null) { updateThemePreferenceSummary(selectedTheme); + recreate(); } } else if (requestCode == REQ_ALL_FILES_ACCESS) { final PreferenceCategory preferenceCategorySync = (PreferenceCategory) findPreference("sync"); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt index 1d7f619bf1f6..1d282c6943ab 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -9,9 +9,6 @@ package com.owncloud.android.ui.dialog import android.app.Dialog import android.os.Bundle -import android.view.View -import android.view.ViewGroup -import android.widget.RadioButton import androidx.appcompat.app.AlertDialog import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment @@ -23,6 +20,7 @@ import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.DarkMode import com.owncloud.android.MainApp import com.owncloud.android.R +import com.owncloud.android.databinding.DialogThemeSelectionBinding import com.owncloud.android.ui.model.ExtendedSettingsActivityDialog import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -37,84 +35,50 @@ class ThemeSelectionDialog : @Inject lateinit var viewThemeUtils: ViewThemeUtils + private lateinit var binding: DialogThemeSelectionBinding + override fun onStart() { super.onStart() - colorButtons() - colorRadioButtons() - } - - private fun colorButtons() { - val dialog = dialog + val alertDialog = dialog as AlertDialog - if (dialog is AlertDialog) { - val positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton - positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) - } + val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton + positiveButton?.let { + viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton) } } - private fun colorRadioButtons() { - val dialog = dialog - if (dialog is AlertDialog) { - val listView = dialog.listView ?: return + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + binding = DialogThemeSelectionBinding.inflate(layoutInflater) - for (i in 0 until listView.childCount) { - val row = listView.getChildAt(i) + val currentTheme = preferences.getDarkThemeMode() ?: DarkMode.SYSTEM + val radioGroup = binding.themeRadioGroup - val radioButton = findRadioButtonInView(row) - radioButton?.let { - viewThemeUtils.platform.themeRadioButton(it) - } - } + viewThemeUtils.platform.run { + colorTextView(binding.dialogTitle) + themeRadioButton(binding.themeDark) + themeRadioButton(binding.themeLight) + themeRadioButton(binding.themeSystem) } - } - @Suppress("ReturnCount") - private fun findRadioButtonInView(view: View): RadioButton? { - if (view is RadioButton) return view - if (view is ViewGroup) { - for (i in 0 until view.childCount) { - findRadioButtonInView(view.getChildAt(i))?.let { return it } - } + when (currentTheme) { + DarkMode.LIGHT -> radioGroup.check(R.id.theme_light) + DarkMode.DARK -> radioGroup.check(R.id.theme_dark) + DarkMode.SYSTEM -> radioGroup.check(R.id.theme_system) } - return null - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val themeEntries = arrayOf( - getString(R.string.prefs_value_theme_light), - getString(R.string.prefs_value_theme_dark), - getString(R.string.prefs_value_theme_system) - ) - val themeValues = arrayOf( - DarkMode.LIGHT.name, - DarkMode.DARK.name, - DarkMode.SYSTEM.name - ) + radioGroup.setOnCheckedChangeListener { _, checkedId -> + val selectedMode = when (checkedId) { + R.id.theme_light -> DarkMode.LIGHT + R.id.theme_dark -> DarkMode.DARK + R.id.theme_system -> DarkMode.SYSTEM + else -> DarkMode.SYSTEM + } - val currentTheme = preferences.getDarkThemeMode()?.name ?: DarkMode.SYSTEM.name - val selectedIndex = themeValues.indexOf(currentTheme) + applyTheme(selectedMode) + } val builder = MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.prefs_theme_title) - .setSingleChoiceItems(themeEntries, selectedIndex) { dialog, which -> - if (which >= 0 && which < themeValues.size) { - val selectedValue = themeValues[which] - val mode = DarkMode.valueOf(selectedValue) - - preferences.setDarkThemeMode(mode) - MainApp.setAppTheme(mode) - - setFragmentResult( - ExtendedSettingsActivityDialog.ThemeSelection.key, - bundleOf(ExtendedSettingsActivityDialog.ThemeSelection.key to selectedValue) - ) - - dialog.dismiss() - } - } + .setView(binding.root) .setPositiveButton(R.string.common_ok) { _, _ -> dismiss() } @@ -123,4 +87,14 @@ class ThemeSelectionDialog : return builder.create() } + + private fun applyTheme(mode: DarkMode) { + preferences.setDarkThemeMode(mode) + MainApp.setAppTheme(mode) + + setFragmentResult( + ExtendedSettingsActivityDialog.ThemeSelection.key, + bundleOf(ExtendedSettingsActivityDialog.ThemeSelection.key to mode.name) + ) + } } diff --git a/app/src/main/res/layout/dialog_theme_selection.xml b/app/src/main/res/layout/dialog_theme_selection.xml new file mode 100644 index 000000000000..447ccc7c83eb --- /dev/null +++ b/app/src/main/res/layout/dialog_theme_selection.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + From 4f73b4ab07bc2b4a06dd5e3b047c52e11146da12 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Fri, 6 Feb 2026 09:34:01 +0100 Subject: [PATCH 7/7] color dialog Signed-off-by: alperozturk96 --- .../java/com/owncloud/android/ui/activity/SettingsActivity.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index c29605b62d07..65e70c062977 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -1063,6 +1063,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { String selectedTheme = data.getStringExtra(ExtendedSettingsActivityDialog.ThemeSelection.getKey()); if (selectedTheme != null) { updateThemePreferenceSummary(selectedTheme); + + // needed for to change status bar color recreate(); } } else if (requestCode == REQ_ALL_FILES_ACCESS) {