Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
00eb624
feat: update base theme to DayNight for dark mode support
phillip9933 Sep 2, 2026
fc3ae7d
feat: add system light dark appearance setting and tests
phillip9933 Sep 2, 2026
48006c1
feat: add semantic DayNight color tokens and theme attributes
phillip9933 Sep 2, 2026
f163a03
feat: apply DayNight attributes to shell and navigation layouts
phillip9933 Sep 2, 2026
1f8150c
feat: apply DayNight attributes to file browser and spaces layouts
phillip9933 Sep 2, 2026
8268d26
feat: apply DayNight attributes to account management layouts
phillip9933 Sep 2, 2026
dce7c5a
feat: apply DayNight attributes to security and passcode layouts
phillip9933 Sep 2, 2026
e86c383
feat: apply DayNight attributes to migration layouts
phillip9933 Sep 2, 2026
e184d01
feat: apply DayNight attributes to upload and transfer layouts
phillip9933 Sep 2, 2026
32fb3d1
feat: apply DayNight attributes to sharing layouts
phillip9933 Sep 2, 2026
7029c33
feat: apply DayNight attributes to dialogs sort ssl and log layouts
phillip9933 Sep 2, 2026
20d6788
feat: finalize semantic DayNight layout migration across remaining views
phillip9933 Sep 2, 2026
93e1527
fix: resolve missing colorBackground attribute error
phillip9933 Sep 2, 2026
291462e
fix: use platform colorBackground attribute in remaining layouts
phillip9933 Sep 2, 2026
3b2b08c
fix: remove hardcoded white background in file list adapter
phillip9933 Sep 2, 2026
98265cf
fix: resovle progress bar color coding
phillip9933 Sep 2, 2026
ed43571
fix: normalize invalid appearance preference values
phillip9933 Sep 4, 2026
6126767
fix: use DayNight themes for app dialogs
phillip9933 Sep 4, 2026
a128817
fix: use DayNight selection colors
phillip9933 Sep 4, 2026
e305823
fix: restore FileListAdapter color import
phillip9933 Sep 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import android.content.ClipboardManager
import android.content.Context
import androidx.fragment.app.testing.FragmentScenario
import androidx.fragment.app.testing.launchFragmentInContainer
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceManager
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
Expand All @@ -38,6 +40,7 @@ import eu.opencloud.android.R
import eu.opencloud.android.presentation.releasenotes.ReleaseNotesActivity
import eu.opencloud.android.presentation.settings.privacypolicy.PrivacyPolicyActivity
import eu.opencloud.android.presentation.settings.SettingsFragment
import eu.opencloud.android.presentation.settings.AppearanceMode
import eu.opencloud.android.presentation.releasenotes.ReleaseNotesViewModel
import eu.opencloud.android.presentation.settings.more.SettingsMoreViewModel
import eu.opencloud.android.presentation.settings.SettingsViewModel
Expand All @@ -61,6 +64,7 @@ class SettingsFragmentTest {
private lateinit var fragmentScenario: FragmentScenario<SettingsFragment>

private var subsectionSecurity: Preference? = null
private var prefAppearance: ListPreference? = null
private var subsectionLogging: Preference? = null
private var subsectionPictureUploads: Preference? = null
private var subsectionVideoUploads: Preference? = null
Expand All @@ -79,6 +83,7 @@ class SettingsFragmentTest {
@Before
fun setUp() {
context = InstrumentationRegistry.getInstrumentation().targetContext
PreferenceManager.getDefaultSharedPreferences(context).edit().remove(AppearanceMode.PREFERENCE_KEY).commit()
settingsViewModel = mockk(relaxed = true)
moreViewModel = mockk(relaxed = true)
releaseNotesViewModel = mockk(relaxed = true)
Expand Down Expand Up @@ -134,6 +139,7 @@ class SettingsFragmentTest {
fragmentScenario = launchFragmentInContainer(themeResId = R.style.Theme_openCloud)
fragmentScenario.onFragment { fragment ->
subsectionSecurity = fragment.findPreference(SUBSECTION_SECURITY)
prefAppearance = fragment.findPreference(AppearanceMode.PREFERENCE_KEY)
subsectionLogging = fragment.findPreference(SUBSECTION_LOGGING)
subsectionPictureUploads = fragment.findPreference(SUBSECTION_PICTURE_UPLOADS)
subsectionVideoUploads = fragment.findPreference(SUBSECTION_VIDEO_UPLOADS)
Expand All @@ -148,6 +154,24 @@ class SettingsFragmentTest {
fun settingsViewCommon() {
launchTest(attachedAccount = false)

assertEquals(
listOf(
context.getString(R.string.prefs_appearance_system),
context.getString(R.string.prefs_appearance_light),
context.getString(R.string.prefs_appearance_dark)
),
prefAppearance?.entries?.toList()
)
assertEquals(AppearanceMode.entries.map { it.name }, prefAppearance?.entryValues?.map { it.toString() })
assertEquals(AppearanceMode.SYSTEM.name, prefAppearance?.value)
prefAppearance?.verifyPreference(
keyPref = AppearanceMode.PREFERENCE_KEY,
titlePref = context.getString(R.string.prefs_appearance),
summaryPref = context.getString(R.string.prefs_appearance_system),
visible = true,
enabled = true
)

subsectionSecurity?.verifyPreference(
keyPref = SUBSECTION_SECURITY,
titlePref = context.getString(R.string.prefs_subsection_security),
Expand Down Expand Up @@ -195,6 +219,24 @@ class SettingsFragmentTest {
)
}

@Test
fun invalidAppearanceModeIsNormalizedToSystem() {
PreferenceManager.getDefaultSharedPreferences(context)
.edit()
.putString(AppearanceMode.PREFERENCE_KEY, "INVALID")
.commit()

launchTest(attachedAccount = false)

assertEquals(AppearanceMode.SYSTEM.name, prefAppearance?.value)
assertEquals(context.getString(R.string.prefs_appearance_system), prefAppearance?.summary)
assertEquals(
AppearanceMode.SYSTEM.name,
PreferenceManager.getDefaultSharedPreferences(context)
.getString(AppearanceMode.PREFERENCE_KEY, null)
)
}

@Test
fun settingsViewNoAccountAttached() {
launchTest(attachedAccount = false)
Expand Down
10 changes: 10 additions & 0 deletions opencloudApp/src/main/java/eu/opencloud/android/MainApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import android.os.Bundle
import android.view.WindowManager
import android.widget.CheckBox
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.pm.PackageInfoCompat
import eu.opencloud.android.data.providers.implementation.OCSharedPreferencesProvider

Expand Down Expand Up @@ -64,6 +65,7 @@ import eu.opencloud.android.presentation.security.passcode.PassCodeManager
import eu.opencloud.android.presentation.security.pattern.PatternActivity
import eu.opencloud.android.presentation.security.pattern.PatternManager
import eu.opencloud.android.presentation.settings.logging.SettingsLogsFragment.Companion.PREFERENCE_ENABLE_LOGGING
import eu.opencloud.android.presentation.settings.AppearanceMode
import eu.opencloud.android.providers.CoroutinesDispatcherProvider
import eu.opencloud.android.providers.LogsProvider
import eu.opencloud.android.providers.MdmProvider
Expand Down Expand Up @@ -103,6 +105,14 @@ class MainApp : Application() {

appContext = applicationContext

val appearancePreferences = androidx.preference.PreferenceManager.getDefaultSharedPreferences(appContext)
val storedAppearanceMode = appearancePreferences.getString(AppearanceMode.PREFERENCE_KEY, null)
val appearanceMode = AppearanceMode.fromPreferenceValue(storedAppearanceMode)
if (storedAppearanceMode != appearanceMode.name) {
appearancePreferences.edit().putString(AppearanceMode.PREFERENCE_KEY, appearanceMode.name).apply()
}
AppCompatDelegate.setDefaultNightMode(appearanceMode.nightMode)

// Ensure Logcat shows Timber logs in debug builds
if (BuildConfig.DEBUG) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import android.security.KeyChain
import android.view.ContextThemeWrapper
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
Expand Down Expand Up @@ -79,7 +78,7 @@ class ManageAccountsDialogFragment : DialogFragment(), ManageAccountsAdapter.Acc
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(ContextThemeWrapper(requireContext(), R.style.Theme_AppCompat_Dialog_Alert))
val builder = AlertDialog.Builder(requireContext())
val inflater = this.layoutInflater
dialogView = inflater.inflate(R.layout.manage_accounts_dialog, null)
builder.setView(dialogView)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@ class FileListAdapter(
private var fileListOption: FileListOption = FileListOption.ALL_FILES
private val disallowTouchesWithOtherWindows =
PreferenceUtils.shouldDisallowTouchesWithOtherVisibleWindows(context)
private val colorSurface by lazy {
context.obtainStyledAttributes(intArrayOf(R.attr.colorSurface)).run {
try {
getColor(0, Color.TRANSPARENT)
} finally {
recycle()
}
}
}
private val colorSelection by lazy {
context.obtainStyledAttributes(intArrayOf(R.attr.colorSelection)).run {
try {
getColor(0, Color.TRANSPARENT)
} finally {
recycle()
}
}
}

init {
setHasStableIds(true)
Expand Down Expand Up @@ -255,17 +273,17 @@ class FileListAdapter(
position = adapterPosition
)
}
holder.itemView.setBackgroundColor(Color.WHITE)
holder.itemView.setBackgroundColor(colorSurface)

val checkBoxV = holder.itemView.findViewById<ImageView>(R.id.custom_checkbox).apply {
isVisible = hasActiveSelection
}

if (isSelected(position)) {
holder.itemView.setBackgroundColor(ContextCompat.getColor(context, R.color.selected_item_background))
holder.itemView.setBackgroundColor(colorSelection)
checkBoxV.setImageResource(R.drawable.ic_checkbox_marked)
} else {
holder.itemView.setBackgroundColor(Color.WHITE)
holder.itemView.setBackgroundColor(colorSurface)
checkBoxV.setImageResource(R.drawable.ic_checkbox_blank_outline)
Comment on lines +276 to 287
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* openCloud Android client application
*
* Copyright (C) 2026 openCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package eu.opencloud.android.presentation.settings

import androidx.appcompat.app.AppCompatDelegate

enum class AppearanceMode(val nightMode: Int) {
SYSTEM(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM),
LIGHT(AppCompatDelegate.MODE_NIGHT_NO),
DARK(AppCompatDelegate.MODE_NIGHT_YES);

companion object {
const val PREFERENCE_KEY = "appearance_mode"

fun fromPreferenceValue(value: String?) = entries.firstOrNull { it.name == value } ?: SYSTEM
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen
Expand All @@ -47,6 +49,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
private val releaseNotesViewModel by viewModel<ReleaseNotesViewModel>()

private var settingsScreen: PreferenceScreen? = null
private var prefAppearance: ListPreference? = null
private var subsectionPictureUploads: Preference? = null
private var subsectionVideoUploads: Preference? = null
private var subsectionMore: Preference? = null
Expand All @@ -59,6 +62,22 @@ class SettingsFragment : PreferenceFragmentCompat() {
setPreferencesFromResource(R.xml.settings, rootKey)

settingsScreen = findPreference(SCREEN_SETTINGS)
prefAppearance = findPreference<ListPreference>(AppearanceMode.PREFERENCE_KEY)?.apply {
entries = arrayOf(
getString(R.string.prefs_appearance_system),
getString(R.string.prefs_appearance_light),
getString(R.string.prefs_appearance_dark)
)
entryValues = AppearanceMode.entries.map { it.name }.toTypedArray()
value = AppearanceMode.fromPreferenceValue(value).name
summary = entry
setOnPreferenceChangeListener { preference, newValue ->
val appearanceMode = AppearanceMode.fromPreferenceValue(newValue as String)
preference.summary = entries[findIndexOfValue(appearanceMode.name)]
AppCompatDelegate.setDefaultNightMode(appearanceMode.nightMode)
true
}
}
subsectionPictureUploads = findPreference(SUBSECTION_PICTURE_UPLOADS)
subsectionVideoUploads = findPreference(SUBSECTION_VIDEO_UPLOADS)
subsectionMore = findPreference(SUBSECTION_MORE)
Expand Down
6 changes: 3 additions & 3 deletions opencloudApp/src/main/res/drawable/list_selector.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@

<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_mediumAnimTime">

<item android:drawable="@color/opencloud_blue_bright" android:state_pressed="true" />
<item android:drawable="@color/opencloud_blue_bright" android:state_focused="true" />
<item android:drawable="@color/background_color" />
<item android:drawable="?attr/colorSelection" android:state_pressed="true" />
<item android:drawable="?attr/colorSelection" android:state_focused="true" />
<item android:drawable="?android:attr/colorBackground" />

</selector>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/white_pressed" />
<solid android:color="?attr/colorSelection" />
</shape>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<item
android:id="@android:id/background"
android:drawable="@color/background_color" />
android:drawable="?attr/colorSurface" />
<item android:id="@android:id/secondaryProgress">
<scale
android:drawable="@color/actionbar_start_color"
Expand Down
4 changes: 2 additions & 2 deletions opencloudApp/src/main/res/layout/account_action.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
app:layout_constraintEnd_toStartOf="@+id/name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/black" />
app:tint="?attr/colorOnSurface" />

<TextView
android:id="@+id/name"
Expand All @@ -44,7 +44,7 @@
android:gravity="center_vertical"
android:paddingEnd="@dimen/standard_padding"
android:text="@string/placeholder_filename"
android:textColor="@color/black"
android:textColor="?attr/colorOnSurface"
android:textSize="@dimen/two_line_primary_text_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
Expand Down
14 changes: 7 additions & 7 deletions opencloudApp/src/main/res/layout/account_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
android:gravity="bottom"
android:maxLines="1"
android:text="@string/placeholder_filename"
android:textColor="@color/textColor"
android:textColor="?attr/colorOnSurface"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/account"
Expand All @@ -80,7 +80,7 @@
android:layout_marginStart="8dp"
android:ellipsize="middle"
android:text="@string/placeholder_sentence"
android:textColor="@color/textColor"
android:textColor="?attr/colorOnSurfaceVariant"
android:textSize="14sp"
android:lines="1"
app:layout_constraintEnd_toStartOf="@+id/mtls_account_button"
Expand All @@ -103,7 +103,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/clean_account_local_storage_button"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/black" />
app:tint="?attr/colorOnSurface" />

<ImageView
android:id="@+id/clean_account_local_storage_button"
Expand All @@ -121,7 +121,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/removeButton"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/black" />
app:tint="?attr/colorOnSurface" />

<ImageView
android:id="@+id/removeButton"
Expand All @@ -139,7 +139,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:contentDescription="@string/content_description_remove_account"
app:tint="@color/black" />
app:tint="?attr/colorOnSurface" />

</androidx.constraintlayout.widget.ConstraintLayout>

Expand All @@ -156,7 +156,7 @@
android:text="@string/used_quota_title_manage_accounts"
android:layout_marginEnd="@dimen/item_file_grid_margin"
android:textSize="@dimen/two_line_secondary_text_size"
android:textColor="@color/textColor"/>
android:textColor="?attr/colorOnSurfaceVariant"/>

<ProgressBar
android:id="@+id/manage_accounts_quota_bar"
Expand All @@ -171,7 +171,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/drawer_loading_quota"
android:textColor="@color/textColor"
android:textColor="?attr/colorOnSurfaceVariant"
android:textSize="@dimen/two_line_secondary_text_size" />
</LinearLayout>

Expand Down
5 changes: 3 additions & 2 deletions opencloudApp/src/main/res/layout/activity_pattern_lock.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/background_color"
android:background="?android:attr/colorBackground"
android:paddingHorizontal="@dimen/standard_padding"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand All @@ -45,7 +45,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_margin"
android:text="@string/pass_code_enter_pass_code"
android:textColor="@android:color/black"
android:textColor="?attr/colorOnSurface"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand All @@ -59,6 +59,7 @@
android:gravity="center"
android:text="@string/pattern_configure_your_pattern_explanation"
android:textAppearance="@android:style/TextAppearance.Small"
android:textColor="?attr/colorOnSurfaceVariant"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
Expand Down
Loading
Loading