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/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/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..d96c91f2c0c8
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/activity/ExtendedSettingsActivity.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.owncloud.android.ui.model.ExtendedSettingsActivityDialog
+
+class ExtendedSettingsActivity : AppCompatActivity() {
+
+ private var dialogShown = false
+
+ @Suppress("ReturnCount")
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ if (savedInstanceState != null) {
+ dialogShown = savedInstanceState.getBoolean(KEY_DIALOG_SHOWN, false)
+ }
+
+ if (dialogShown) {
+ return
+ }
+
+ val dialogKey = intent.getStringExtra(EXTRA_DIALOG_TYPE) ?: run {
+ finish()
+ return
+ }
+
+ val dialogType = ExtendedSettingsActivityDialog.entries.find { it.key == dialogKey } ?: run {
+ finish()
+ return
+ }
+
+ dialogType.showDialog(this)
+ dialogShown = true
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putBoolean(KEY_DIALOG_SHOWN, dialogShown)
+ }
+
+ companion object {
+ private const val EXTRA_DIALOG_TYPE = "dialog_type"
+ private const val KEY_DIALOG_SHOWN = "dialog_shown"
+
+ 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 ba6db7333a81..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
@@ -70,6 +70,7 @@
import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask;
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 +81,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 +121,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 +878,42 @@ 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.ThemeSelection);
+ startActivityForResult(intent, ExtendedSettingsActivityDialog.ThemeSelection.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 -> getString(R.string.prefs_value_theme_light);
+ case DARK -> getString(R.string.prefs_value_theme_dark);
+ default -> getString(R.string.prefs_value_theme_system);
+ };
- return true;
- });
+ themePref.setSummary(summary);
}
private void setListBackground() {
@@ -1052,14 +1052,21 @@ 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);
storageMigration.setStorageMigrationProgressListener(this);
storageMigration.migrate();
}
+ } else if (requestCode == ExtendedSettingsActivityDialog.ThemeSelection.getResultId() && data != null) {
+ 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) {
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
new file mode 100644
index 000000000000..1d282c6943ab
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt
@@ -0,0 +1,100 @@
+/*
+ * 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 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.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
+
+class ThemeSelectionDialog :
+ DialogFragment(),
+ Injectable {
+
+ @Inject
+ lateinit var preferences: AppPreferences
+
+ @Inject
+ lateinit var viewThemeUtils: ViewThemeUtils
+
+ private lateinit var binding: DialogThemeSelectionBinding
+
+ override fun onStart() {
+ super.onStart()
+ val alertDialog = dialog as AlertDialog
+
+ val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton
+ positiveButton?.let {
+ viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton)
+ }
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ binding = DialogThemeSelectionBinding.inflate(layoutInflater)
+
+ val currentTheme = preferences.getDarkThemeMode() ?: DarkMode.SYSTEM
+ val radioGroup = binding.themeRadioGroup
+
+ viewThemeUtils.platform.run {
+ colorTextView(binding.dialogTitle)
+ themeRadioButton(binding.themeDark)
+ themeRadioButton(binding.themeLight)
+ themeRadioButton(binding.themeSystem)
+ }
+
+ 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)
+ }
+
+ 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
+ }
+
+ applyTheme(selectedMode)
+ }
+
+ val builder = MaterialAlertDialogBuilder(requireContext())
+ .setView(binding.root)
+ .setPositiveButton(R.string.common_ok) { _, _ ->
+ dismiss()
+ }
+
+ viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder)
+
+ 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/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..4316d78f7755
--- /dev/null
+++ b/app/src/main/java/com/owncloud/android/ui/model/ExtendedSettingsActivityDialog.kt
@@ -0,0 +1,50 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2026 Alper Ozturk
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+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
+
+@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)
+ }
+ }
+ }
+}
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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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" />
-