diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a5c3d1133a..95b1bd2f04 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -31,7 +31,7 @@ jobs: with: languages: ${{ matrix.language }} - name: Set up JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: "temurin" java-version: 11 diff --git a/app/build.gradle b/app/build.gradle index b60b9cfadd..44db9588a5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,7 @@ import org.gradle.internal.jvm.Jvm buildscript { dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:7.3.1' classpath 'com.hiya:jacoco-android:0.2' classpath 'com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.12' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" @@ -112,7 +112,7 @@ android { buildTypes { debug { - testCoverageEnabled (project.hasProperty('coverage')) + testCoverageEnabled(project.hasProperty('coverage')) } } @@ -218,7 +218,7 @@ dependencies { // dependencies for app building implementation 'androidx.multidex:multidex:2.0.1' // implementation project('nextcloud-android-library') - implementation ("com.github.nextcloud:android-library:$androidLibraryVersion") { + implementation("com.github.nextcloud:android-library:$androidLibraryVersion") { exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version } @@ -281,7 +281,7 @@ dependencies { implementation "com.google.android.exoplayer:extension-okhttp:$exoplayerVersion" implementation 'me.zhanghai.android.fastscroll:library:1.1.8' - + // Shimmer animation implementation 'io.github.elye:loaderviewlibrary:3.0.0' @@ -296,8 +296,8 @@ dependencies { implementation "io.noties:prism4j:$prismVersion" kapt "io.noties:prism4j-bundler:$prismVersion" - implementation ('org.mnode.ical4j:ical4j:3.0.0') { - ['org.apache.commons','commons-logging'].each { + implementation('org.mnode.ical4j:ical4j:3.0.0') { + ['org.apache.commons', 'commons-logging'].each { exclude group: "$it" } } @@ -352,10 +352,12 @@ dependencies { // upon each update first test: new registration, receive push gplayImplementation "com.google.firebase:firebase-messaging:23.0.7" + + implementation 'com.github.nextcloud.android-common:ui:0.2.0' } configurations.all { - resolutionStrategy{ + resolutionStrategy { cacheChangingModulesFor 0, 'seconds' force 'org.objenesis:objenesis:2.6' eachDependency { details -> @@ -400,7 +402,7 @@ shot { showOnlyFailingTestsInReports = ciBuild // CI environment renders some shadows slightly different from local VMs // Add a 0.5% tolerance to account for that - tolerance = ciBuild ? 0.5: 0 + tolerance = ciBuild ? 0.5 : 0 } jacoco { @@ -413,7 +415,7 @@ spotbugs { reportLevel = "medium" } -tasks.withType(SpotBugsTask){task -> +tasks.withType(SpotBugsTask) { task -> String variantNameCap = task.name.replace("spotbugs", "") String variantName = variantNameCap.substring(0, 1).toLowerCase() + variantNameCap.substring(1) diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_empty.png b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_empty.png index 5216453894..dd1710e059 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_empty.png and b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_empty.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_error.png b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_error.png index 56858428ea..196a8e04cc 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_error.png and b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_error.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_loading.png b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_loading.png index 4446e0cb28..6e705fabd6 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_loading.png and b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_loading.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png index 3a485bb5ec..f428388ffe 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png and b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_openDrawer.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_showActivities.png b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_showActivities.png index 65ac34ec10..008f4a489c 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_showActivities.png and b/app/screenshots/gplay/debug/com.nextcloud.client.ActivitiesActivityIT_showActivities.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.AuthenticatorActivityIT_login.png b/app/screenshots/gplay/debug/com.nextcloud.client.AuthenticatorActivityIT_login.png index 23f9324ca4..b832e03338 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.AuthenticatorActivityIT_login.png and b/app/screenshots/gplay/debug/com.nextcloud.client.AuthenticatorActivityIT_login.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.CommunityActivityIT_open.png b/app/screenshots/gplay/debug/com.nextcloud.client.CommunityActivityIT_open.png index cfe1a90beb..6160fc4005 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.CommunityActivityIT_open.png and b/app/screenshots/gplay/debug/com.nextcloud.client.CommunityActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png index 33898a2188..51bf23ef31 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png and b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_drawer.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png index 48290c2516..a2cae83323 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png and b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_showMediaThenAllFiles.png b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_showMediaThenAllFiles.png index 0e0ffdbf00..c3ad35c44b 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_showMediaThenAllFiles.png and b/app/screenshots/gplay/debug/com.nextcloud.client.FileDisplayActivityScreenshotIT_showMediaThenAllFiles.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.FirstRunActivityIT_open.png b/app/screenshots/gplay/debug/com.nextcloud.client.FirstRunActivityIT_open.png index ac2e60fa9e..ebb2c94490 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.FirstRunActivityIT_open.png and b/app/screenshots/gplay/debug/com.nextcloud.client.FirstRunActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_open.png b/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_open.png index b77a417166..47591b4ffc 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_open.png and b/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_showMnemonic_Error.png b/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_showMnemonic_Error.png index 9934ee50e6..aa62a6bfce 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_showMnemonic_Error.png and b/app/screenshots/gplay/debug/com.nextcloud.client.SettingsActivityIT_showMnemonic_Error.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_open.png b/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_open.png index d8df05d7a8..6cc302bdb7 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_open.png and b/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_testSyncedFolderDialog.png b/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_testSyncedFolderDialog.png index 8e14e17e4c..ee65e13bca 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_testSyncedFolderDialog.png and b/app/screenshots/gplay/debug/com.nextcloud.client.SyncedFoldersActivityIT_testSyncedFolderDialog.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png b/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png index d513b4751e..2cbc9f70e8 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png and b/app/screenshots/gplay/debug/com.nextcloud.client.UploadListActivityActivityIT_openDrawer.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_accounts.png b/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_accounts.png index e1f827ce7a..f4dc21659a 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_accounts.png and b/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_accounts.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_overview.png b/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_overview.png index 62db65b9ca..8f5afbf2bb 100644 Binary files a/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_overview.png and b/app/screenshots/gplay/debug/com.nextcloud.client.etm.EtmActivityTest_overview.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_glideSVG.png b/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_glideSVG.png new file mode 100644 index 0000000000..668c4cd0e8 Binary files /dev/null and b/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_glideSVG.png differ diff --git a/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_roundBitmap.png b/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_roundBitmap.png new file mode 100644 index 0000000000..0a5549bba0 Binary files /dev/null and b/app/screenshots/gplay/debug/com.nextcloud.ui.BitmapIT_roundBitmap.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepBoth.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepBoth.png index 6d5bc5dc28..47172a3da2 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepBoth.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepBoth.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepExisting.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepExisting.png index 546aec0426..8ad1818f86 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepExisting.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepExisting.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepNew.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepNew.png index 25d7336c10..e51fdd8144 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepNew.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_keepNew.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_screenshotTextFiles.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_screenshotTextFiles.png index ad45eb9469..336694046b 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_screenshotTextFiles.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ConflictsResolveActivityIT_screenshotTextFiles.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openContactsPreference.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openContactsPreference.png index 7717b32652..26c12663b7 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openContactsPreference.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openContactsPreference.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openVCF.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openVCF.png index f16e43539c..eadc8cdc37 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openVCF.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ContactsPreferenceActivityIT_openVCF.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.FolderPickerActivityIT_open.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.FolderPickerActivityIT_open.png index 930f2bed19..f619ffc11a 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.FolderPickerActivityIT_open.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.FolderPickerActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_open.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_open.png index 03294045df..36cbbc47b8 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_open.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png index 53b56c21c1..761c63a180 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ManageAccountsActivityIT_userInfoDetail.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_empty.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_empty.png index 49bca96fff..02bfad1c5e 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_empty.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_empty.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_error.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_error.png index 0430cdb1aa..8ce15fc125 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_error.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_error.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_showNotifications.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_showNotifications.png index eeddd15fc0..b11bd1cad2 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_showNotifications.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.NotificationsActivityIT_showNotifications.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_check.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_check.png index 768101c6d3..497107941f 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_check.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_check.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_delete.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_delete.png index 455a23711b..98f675eec0 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_delete.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_delete.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_request.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_request.png index fc90528a4a..02e0f1f84e 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_request.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.PassCodeActivityIT_request.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivityIT_open.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivityIT_open.png index f7cafa6bc4..9e03588cec 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivityIT_open.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.ReceiveExternalFilesActivityIT_open.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_localFolderPickerMode.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_localFolderPickerMode.png index b66bacedc9..fb6b40a5d6 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_localFolderPickerMode.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_localFolderPickerMode.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_noneSelected.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_noneSelected.png index 2dbf5b3fb3..2a7f2c9881 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_noneSelected.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UploadFilesActivityIT_noneSelected.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UserInfoActivityIT_fullUserInfoDetail.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UserInfoActivityIT_fullUserInfoDetail.png index 8dd3939822..338e8e3faa 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UserInfoActivityIT_fullUserInfoDetail.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.activity.UserInfoActivityIT_fullUserInfoDetail.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog.png index 41a6dd9ba2..de21099785 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialogWithStatusDisabled.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialogWithStatusDisabled.png index b16ca1b6c6..0f0607c869 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialogWithStatusDisabled.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialogWithStatusDisabled.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_away.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_away.png index d80891e9d8..971dd173a7 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_away.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_away.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_dnd.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_dnd.png index 057e2ae120..4ce6435418 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_dnd.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_dnd.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_fun.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_fun.png index 289513af23..6e5ea2afc6 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_fun.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_fun.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_offline.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_offline.png index 41a6dd9ba2..de21099785 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_offline.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_offline.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_online.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_online.png index 710f520ea3..f66a7ee1bd 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_online.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testAccountChooserDialog_online.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png index 0fa8ef00fa..de32f68c1f 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testBottomSheet.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testEnforcedPasswordDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testEnforcedPasswordDialog.png index a12ea9f52e..f0ebdef02c 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testEnforcedPasswordDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testEnforcedPasswordDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testLoadingDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testLoadingDialog.png index 36dba67673..509802a905 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testLoadingDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testLoadingDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testNewFolderDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testNewFolderDialog.png index 8847cef1ad..658eafbc80 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testNewFolderDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testNewFolderDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testOptionalPasswordDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testOptionalPasswordDialog.png index b6faaba8fe..96f049f238 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testOptionalPasswordDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testOptionalPasswordDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testProfileBottomSheet.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testProfileBottomSheet.png index f9749381b6..1c57c3c2d4 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testProfileBottomSheet.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testProfileBottomSheet.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png index 4b98224d13..c4bd33b4ab 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFileDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png index ae3c10105b..6681374612 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFilesDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png index ab0580ec09..1ef759d4f6 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFolderDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png index ae3c10105b..6681374612 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRemoveFoldersDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png index 8d93463ee5..9841f84a49 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.DialogFragmentIT_testRenameFileDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialogDifferentTypes_Screenshot.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialogDifferentTypes_Screenshot.png index bd3d20143b..1d3297face 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialogDifferentTypes_Screenshot.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialogDifferentTypes_Screenshot.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialog_Screenshot.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialog_Screenshot.png index bd3d20143b..1d3297face 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialog_Screenshot.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendFilesDialogTest_showDialog_Screenshot.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendShareDialogTest_showDialog.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendShareDialogTest_showDialog.png index ee28ab2ac6..0157dc5abd 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendShareDialogTest_showDialog.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SendShareDialogTest_showDialog.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_error.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_error.png index 4cd243fd4e..857de92bec 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_error.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_error.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_showMnemonic.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_showMnemonic.png index f3d172678b..7b5befd0c5 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_showMnemonic.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.dialog.SetupEncryptionDialogFragmentIT_showMnemonic.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarAndContactsList.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarAndContactsList.png index 71af22fc53..75ce4883e3 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarAndContactsList.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarAndContactsList.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarList.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarList.png index c85d01c276..2c126d903b 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarList.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showCalendarList.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showContactList.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showContactList.png index c61a0a17ce..d9a384843a 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showContactList.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showContactList.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showLoading.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showLoading.png index 7d12490a96..eadc8cdc37 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showLoading.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.BackupListFragmentIT_showLoading.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivities.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivities.png index 242f1e4c75..e5c5f911c9 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivities.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivities.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivitiesError.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivitiesError.png index bc18ef15b6..8b6c4ed1b8 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivitiesError.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsActivitiesError.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsSharing.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsSharing.png index 6df83daf4c..04a448a926 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsSharing.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showDetailsSharing.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png index b2c15b81e1..01ad7143ff 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailActivitiesFragment.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailSharingFragment.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailSharingFragment.png index d0e3d8e0b7..30e9b93259 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailSharingFragment.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailFragmentStaticServerIT_showFileDetailSharingFragment.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileAllShareTypes.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileAllShareTypes.png index cd0556f826..8ca0c15804 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileAllShareTypes.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileAllShareTypes.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileNone.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileNone.png index f7929097a0..6a67c501f4 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileNone.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileNone.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileResharingNotAllowed.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileResharingNotAllowed.png index d0e3d8e0b7..30e9b93259 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileResharingNotAllowed.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.FileDetailSharingFragmentIT_listSharesFileResharingNotAllowed.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showFolderTypes.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showFolderTypes.png index 453ff46dd7..c0d31d56ca 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showFolderTypes.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showFolderTypes.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png index 4dde9d5c1e..bc84c17781 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.fragment.OCFileListFragmentStaticServerIT_showSharedFiles.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.preview.PreviewBitmapScreenshotIT_showBitmap.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.preview.PreviewBitmapScreenshotIT_showBitmap.png index 3988117ffb..f159bacba6 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.preview.PreviewBitmapScreenshotIT_showBitmap.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.preview.PreviewBitmapScreenshotIT_showBitmap.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_empty.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_empty.png index 2bc1df9caa..0d6d1ead84 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_empty.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_empty.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_error.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_error.png index 0c7f183eff..af0ada9dbd 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_error.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_error.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_files.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_files.png index 4468ba0fda..1ba755826f 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_files.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_files.png differ diff --git a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png index ee2a02b6c9..9def340b43 100644 Binary files a/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png and b/app/screenshots/gplay/debug/com.owncloud.android.ui.trashbin.TrashbinActivityIT_loading.png differ diff --git a/app/src/androidTest/java/com/nextcloud/ui/BitmapIT.kt b/app/src/androidTest/java/com/nextcloud/ui/BitmapIT.kt new file mode 100644 index 0000000000..23bfb671c8 --- /dev/null +++ b/app/src/androidTest/java/com/nextcloud/ui/BitmapIT.kt @@ -0,0 +1,139 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.ui + +import android.graphics.BitmapFactory +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.test.espresso.intent.rule.IntentsTestRule +import com.nextcloud.client.TestActivity +import com.owncloud.android.AbstractIT +import com.owncloud.android.R +import com.owncloud.android.utils.BitmapUtils +import com.owncloud.android.utils.ScreenshotTest +import org.junit.Rule +import org.junit.Test + +class BitmapIT : AbstractIT() { + @get:Rule + val testActivityRule = IntentsTestRule(TestActivity::class.java, true, false) + + @Test + @ScreenshotTest + fun roundBitmap() { + val file = getFile("christine.jpg") + val bitmap = BitmapFactory.decodeFile(file.absolutePath) + + val activity = testActivityRule.launchActivity(null) + val imageView = ImageView(activity).apply { + setImageBitmap(bitmap) + } + + val bitmap2 = BitmapFactory.decodeFile(file.absolutePath) + val imageView2 = ImageView(activity).apply { + setImageBitmap(BitmapUtils.roundBitmap(bitmap2)) + } + + val linearLayout = LinearLayout(activity).apply { + orientation = LinearLayout.VERTICAL + setBackgroundColor(context.getColor(R.color.grey_200)) + } + linearLayout.addView(imageView, 200, 200) + linearLayout.addView(imageView2, 200, 200) + activity.addView(linearLayout) + + screenshot(activity) + } + + // @Test + // @ScreenshotTest + // fun glideSVG() { + // val activity = testActivityRule.launchActivity(null) + // val accountProvider = UserAccountManagerImpl.fromContext(activity) + // val clientFactory = ClientFactoryImpl(activity) + // + // val linearLayout = LinearLayout(activity).apply { + // orientation = LinearLayout.VERTICAL + // setBackgroundColor(context.getColor(R.color.grey_200)) + // } + // + // val file = getFile("christine.jpg") + // val bitmap = BitmapFactory.decodeFile(file.absolutePath) + // + // ImageView(activity).apply { + // setImageBitmap(bitmap) + // linearLayout.addView(this, 50, 50) + // } + // + // downloadIcon( + // client.baseUri.toString() + "/apps/files/img/app.svg", + // activity, + // linearLayout, + // accountProvider, + // clientFactory + // ) + // + // downloadIcon( + // client.baseUri.toString() + "/core/img/actions/group.svg", + // activity, + // linearLayout, + // accountProvider, + // clientFactory + // ) + // + // activity.addView(linearLayout) + // + // longSleep() + // + // screenshot(activity) + // } + // + // private fun downloadIcon( + // url: String, + // activity: TestActivity, + // linearLayout: LinearLayout, + // accountProvider: UserAccountManager, + // clientFactory: ClientFactory + // ) { + // val view = ImageView(activity).apply { + // linearLayout.addView(this, 50, 50) + // } + // val target = object : SimpleTarget() { + // override fun onResourceReady(resource: Drawable?, glideAnimation: GlideAnimation?) { + // view.setColorFilter(targetContext.getColor(R.color.dark), PorterDuff.Mode.SRC_ATOP) + // view.setImageDrawable(resource) + // } + // } + // + // testActivityRule.runOnUiThread { + // DisplayUtils.downloadIcon( + // accountProvider, + // clientFactory, + // activity, + // url, + // target, + // R.drawable.ic_user + // ) + // } + // } +} diff --git a/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java b/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java index 0424f66ea5..a5fb7319f7 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java +++ b/app/src/androidTest/java/com/owncloud/android/ui/activity/FolderPickerActivityIT.java @@ -22,6 +22,7 @@ package com.owncloud.android.ui.activity; */ import com.owncloud.android.AbstractIT; +import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.utils.ScreenshotTest; @@ -128,6 +129,10 @@ public class FolderPickerActivityIT extends AbstractIT { OCFile origin = new OCFile("/test/file.txt"); sut.setFile(origin); + sut.runOnUiThread(() -> { + sut.findViewById(R.id.folder_picker_btn_choose).requestFocus(); + }); + waitForIdleSync(); screenshot(sut); } } diff --git a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java index 4e8909fa3d..0583e46052 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java +++ b/app/src/androidTest/java/com/owncloud/android/ui/dialog/DialogFragmentIT.java @@ -30,6 +30,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.gson.Gson; import com.nextcloud.android.lib.resources.profile.Action; import com.nextcloud.android.lib.resources.profile.HoverCard; @@ -57,6 +59,7 @@ import com.owncloud.android.lib.resources.users.Status; import com.owncloud.android.lib.resources.users.StatusType; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.fragment.OCFileListBottomSheetActions; +import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog; import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialogFragment; import com.owncloud.android.ui.fragment.ProfileBottomSheetDialog; import com.owncloud.android.utils.MimeTypeUtil; @@ -402,7 +405,21 @@ public class DialogFragmentIT extends AbstractIT { user, ocFile); - showDialog(fda, sut); + sut.show(fda.getSupportFragmentManager(), ""); + + getInstrumentation().waitForIdleSync(); + shortSleep(); + + ((BottomSheetDialog) sut.requireDialog()).getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); + + getInstrumentation().waitForIdleSync(); + shortSleep(); + + ViewGroup viewGroup = sut.requireDialog().getWindow().findViewById(android.R.id.content); + hideCursors(viewGroup); + + screenshot(Objects.requireNonNull(sut.requireDialog().getWindow()).getDecorView()); + } @Test @@ -438,8 +455,7 @@ public class DialogFragmentIT extends AbstractIT { ProfileBottomSheetDialog sut = new ProfileBottomSheetDialog(fda, user, hoverCard, - fda.themeColorUtils, - fda.themeDrawableUtils); + fda.viewThemeUtils); fda.runOnUiThread(sut::show); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e389fb86cb..c78886a676 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -40,9 +40,7 @@ - - + @@ -151,6 +149,13 @@ + + + + + + + + + + + + + android:theme="@style/PreferenceTheme" /> - + - - - - + android:permission="android.permission.MANAGE_DOCUMENTS"> - - - - - - - - viewThemeUtilsProvider) { return new AppNotificationManagerImpl(context, context.getResources(), platformNotificationsManager, - themeColorUtils); + viewThemeUtilsProvider.get()); } @Provides 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 5c40179a5d..d0cd299ac0 100644 --- a/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java +++ b/app/src/main/java/com/nextcloud/client/di/ComponentsModule.java @@ -29,6 +29,9 @@ import com.nextcloud.client.media.PlayerService; import com.nextcloud.client.migrations.Migrations; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.client.onboarding.WhatsNewActivity; +import com.nextcloud.client.widget.DashboardWidgetConfigurationActivity; +import com.nextcloud.client.widget.DashboardWidgetProvider; +import com.nextcloud.client.widget.DashboardWidgetService; import com.nextcloud.ui.ChooseAccountDialogFragment; import com.nextcloud.ui.SetStatusDialogFragment; import com.owncloud.android.MainApp; @@ -100,16 +103,19 @@ import com.owncloud.android.ui.fragment.FeatureFragment; import com.owncloud.android.ui.fragment.FileDetailActivitiesFragment; import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.FileDetailSharingFragment; +import com.owncloud.android.ui.fragment.FileDetailsSharingProcessFragment; import com.owncloud.android.ui.fragment.GalleryFragment; +import com.owncloud.android.ui.fragment.GalleryFragmentBottomSheetDialog; import com.owncloud.android.ui.fragment.LocalFileListFragment; -import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialogFragment; import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog; +import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialogFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.ui.fragment.SharedListFragment; import com.owncloud.android.ui.fragment.UnifiedSearchFragment; import com.owncloud.android.ui.fragment.contactsbackup.BackupFragment; import com.owncloud.android.ui.fragment.contactsbackup.BackupListFragment; import com.owncloud.android.ui.preview.FileDownloadFragment; +import com.owncloud.android.ui.preview.PreviewBitmapActivity; import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; @@ -251,6 +257,9 @@ abstract class ComponentsModule { @ContributesAndroidInjector abstract FileDetailActivitiesFragment fileDetailActivitiesFragment(); + @ContributesAndroidInjector + abstract FileDetailsSharingProcessFragment fileDetailsSharingProcessFragment(); + @ContributesAndroidInjector abstract FileDetailSharingFragment fileDetailSharingFragment(); @@ -341,6 +350,9 @@ abstract class ComponentsModule { @ContributesAndroidInjector abstract FileSyncService fileSyncService(); + @ContributesAndroidInjector + abstract DashboardWidgetService dashboardWidgetService(); + @ContributesAndroidInjector abstract PreviewPdfFragment previewPDFFragment(); @@ -430,4 +442,16 @@ abstract class ComponentsModule { @ContributesAndroidInjector abstract SyncFileNotEnoughSpaceDialogFragment syncFileNotEnoughSpaceDialogFragment(); + + @ContributesAndroidInjector + abstract DashboardWidgetConfigurationActivity dashboardWidgetConfigurationActivity(); + + @ContributesAndroidInjector + abstract DashboardWidgetProvider dashboardWidgetProvider(); + + @ContributesAndroidInjector + abstract GalleryFragmentBottomSheetDialog galleryFragmentBottomSheetDialog(); + + @ContributesAndroidInjector + abstract PreviewBitmapActivity previewBitmapActivity(); } diff --git a/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt b/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt index 26e9c1a07d..eeed63f6c9 100644 --- a/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt +++ b/app/src/main/java/com/nextcloud/client/di/ThemeModule.kt @@ -20,112 +20,39 @@ */ package com.nextcloud.client.di -import android.content.Context -import com.owncloud.android.utils.theme.ThemeAvatarUtils -import com.owncloud.android.utils.theme.ThemeBarUtils -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeCheckableUtils +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.owncloud.android.utils.theme.MaterialSchemesProvider +import com.owncloud.android.utils.theme.MaterialSchemesProviderImpl import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils -import com.owncloud.android.utils.theme.ThemeFabUtils -import com.owncloud.android.utils.theme.ThemeLayoutUtils -import com.owncloud.android.utils.theme.ThemeMenuUtils -import com.owncloud.android.utils.theme.ThemeSnackbarUtils -import com.owncloud.android.utils.theme.ThemeTextInputUtils -import com.owncloud.android.utils.theme.ThemeTextUtils -import com.owncloud.android.utils.theme.ThemeToolbarUtils import com.owncloud.android.utils.theme.ThemeUtils +import dagger.Binds import dagger.Module import dagger.Provides import javax.inject.Singleton @Module -internal class ThemeModule { - @Provides - @Singleton - fun themeColorUtils(): ThemeColorUtils { - return ThemeColorUtils() - } +internal abstract class ThemeModule { - @Provides - @Singleton - fun themeFabUtils(themeColorUtils: ThemeColorUtils?, themeDrawableUtils: ThemeDrawableUtils?): ThemeFabUtils { - return ThemeFabUtils(themeColorUtils, themeDrawableUtils) - } + @Binds + abstract fun bindMaterialSchemesProvider(provider: MaterialSchemesProviderImpl): MaterialSchemesProvider - @Provides - @Singleton - fun themeLayoutUtils(themeColorUtils: ThemeColorUtils?): ThemeLayoutUtils { - return ThemeLayoutUtils(themeColorUtils) - } + companion object { - @Provides - @Singleton - fun themeToolbarUtils( - themeColorUtils: ThemeColorUtils?, - themeDrawableUtils: ThemeDrawableUtils?, - themeTextInputUtils: ThemeTextInputUtils? - ): ThemeToolbarUtils { - return ThemeToolbarUtils(themeColorUtils, themeDrawableUtils, themeTextInputUtils) - } + @Provides + @Singleton + fun themeColorUtils(): ThemeColorUtils { + return ThemeColorUtils() + } - @Provides - @Singleton - fun themeDrawableUtils(context: Context?): ThemeDrawableUtils { - return ThemeDrawableUtils(context) - } + @Provides + @Singleton + fun themeUtils(): ThemeUtils { + return ThemeUtils() + } - @Provides - @Singleton - fun themeUtils(): ThemeUtils { - return ThemeUtils() - } - - @Provides - @Singleton - fun themeMenuUtils(): ThemeMenuUtils { - return ThemeMenuUtils() - } - - @Provides - @Singleton - fun themeSnackbarUtils(): ThemeSnackbarUtils { - return ThemeSnackbarUtils() - } - - @Provides - @Singleton - fun themeTextUtils(): ThemeTextUtils { - return ThemeTextUtils() - } - - @Provides - @Singleton - fun themeButtonUtils(): ThemeButtonUtils { - return ThemeButtonUtils() - } - - @Provides - @Singleton - fun themeBarUtils(): ThemeBarUtils { - return ThemeBarUtils() - } - - @Provides - @Singleton - fun themeTextInputUtils(): ThemeTextInputUtils { - return ThemeTextInputUtils() - } - - @Provides - @Singleton - fun themeCheckableUtils(): ThemeCheckableUtils { - return ThemeCheckableUtils() - } - - @Provides - @Singleton - fun themeAvatarUtils(): ThemeAvatarUtils { - return ThemeAvatarUtils() + @Provides + fun provideMaterialSchemes(materialSchemesProvider: MaterialSchemesProvider): MaterialSchemes { + return materialSchemesProvider.getMaterialSchemesForCurrentUser() + } } } diff --git a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt index c0a3213f26..f656ef873d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -40,9 +40,7 @@ import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeSnackbarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import org.greenrobot.eventbus.EventBus import javax.inject.Inject import javax.inject.Provider @@ -67,9 +65,7 @@ class BackgroundJobFactory @Inject constructor( private val notificationManager: NotificationManager, private val eventBus: EventBus, private val deckApi: DeckApi, - private val themeColorUtils: ThemeColorUtils, - private val themeSnackbarUtils: ThemeSnackbarUtils, - private val themeButtonUtils: ThemeButtonUtils + private val viewThemeUtils: Provider ) : WorkerFactory() { @SuppressLint("NewApi") @@ -113,7 +109,7 @@ class BackgroundJobFactory @Inject constructor( context, accountManager.user, contentResolver, - themeColorUtils, + viewThemeUtils.get(), params ) } @@ -212,9 +208,7 @@ class BackgroundJobFactory @Inject constructor( accountManager, preferences, clock, - themeColorUtils, - themeSnackbarUtils, - themeButtonUtils + viewThemeUtils.get() ) } @@ -225,7 +219,7 @@ class BackgroundJobFactory @Inject constructor( notificationManager, accountManager, deckApi, - themeColorUtils + viewThemeUtils.get() ) } diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt index e479cfb3d3..427b9f605d 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/FilesExportWork.kt @@ -44,14 +44,14 @@ import com.owncloud.android.ui.dialog.SendShareDialog import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.FileExportUtils import com.owncloud.android.utils.FileStorageUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import java.security.SecureRandom class FilesExportWork( private val appContext: Context, private val user: User, private val contentResolver: ContentResolver, - private val themeColorUtils: ThemeColorUtils, + private val viewThemeUtils: ViewThemeUtils, params: WorkerParameters ) : Worker(appContext, params) { @@ -153,11 +153,12 @@ class FilesExportWork( ) .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(appContext.resources, R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(appContext)) .setSubText(user.accountName) .setContentText(message) .setAutoCancel(true) + viewThemeUtils.androidx.themeNotificationCompatBuilder(appContext, notificationBuilder) + val actionIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).apply { flags = FLAG_ACTIVITY_NEW_TASK } diff --git a/app/src/main/java/com/nextcloud/client/jobs/MediaFoldersDetectionWork.kt b/app/src/main/java/com/nextcloud/client/jobs/MediaFoldersDetectionWork.kt index dfdcf9eaa0..41bc0ac31a 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/MediaFoldersDetectionWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/MediaFoldersDetectionWork.kt @@ -55,9 +55,7 @@ import com.owncloud.android.ui.activity.ManageAccountsActivity.PENDING_FOR_REMOV import com.owncloud.android.ui.activity.SyncedFoldersActivity import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.SyncedFolderUtils -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeSnackbarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import java.util.Random @Suppress("LongParameterList") // dependencies injection @@ -69,9 +67,7 @@ class MediaFoldersDetectionWork constructor( private val userAccountManager: UserAccountManager, private val preferences: AppPreferences, private val clock: Clock, - private val themeColorUtils: ThemeColorUtils, - private val themeSnackbarUtils: ThemeSnackbarUtils, - private val themeButtonUtils: ThemeButtonUtils + private val viewThemeUtils: ViewThemeUtils ) : Worker(context, params) { companion object { @@ -97,14 +93,14 @@ class MediaFoldersDetectionWork constructor( 1, null, true, - themeSnackbarUtils + viewThemeUtils ) val videoMediaFolders = MediaProvider.getVideoFolders( contentResolver, 1, null, true, - themeSnackbarUtils + viewThemeUtils ) val imageMediaFolderPaths: MutableList = ArrayList() val videoMediaFolderPaths: MutableList = ArrayList() @@ -222,13 +218,15 @@ class MediaFoldersDetectionWork constructor( ) .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(context)) .setSubText(user.accountName) .setContentTitle(contentTitle) .setContentText(subtitle) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) .setAutoCancel(true) .setContentIntent(pendingIntent) + + viewThemeUtils.androidx.themeNotificationCompatBuilder(context, notificationBuilder) + val disableDetection = Intent(context, NotificationReceiver::class.java) disableDetection.putExtra(NOTIFICATION_ID, notificationId) disableDetection.action = DISABLE_DETECTION_CLICK diff --git a/app/src/main/java/com/nextcloud/client/jobs/NotificationWork.kt b/app/src/main/java/com/nextcloud/client/jobs/NotificationWork.kt index 352514956c..ceb62ca93e 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/NotificationWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/NotificationWork.kt @@ -54,7 +54,7 @@ import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.activity.NotificationsActivity import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.utils.PushUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import dagger.android.AndroidInjection import org.apache.commons.httpclient.HttpMethod import org.apache.commons.httpclient.HttpStatus @@ -76,7 +76,7 @@ class NotificationWork constructor( private val notificationManager: NotificationManager, private val accountManager: UserAccountManager, private val deckApi: DeckApi, - private val themeColorUtils: ThemeColorUtils + private val viewThemeUtils: ViewThemeUtils ) : Worker(context, params) { companion object { @@ -168,7 +168,6 @@ class NotificationWork constructor( val notificationBuilder = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH) .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(user.toPlatformAccount(), false, context)) .setShowWhen(true) .setSubText(user.accountName) .setContentTitle(notification.getSubject()) @@ -177,6 +176,9 @@ class NotificationWork constructor( .setAutoCancel(true) .setVisibility(NotificationCompat.VISIBILITY_PRIVATE) .setContentIntent(pendingIntent) + + viewThemeUtils.androidx.themeNotificationCompatBuilder(context, notificationBuilder) + // Remove if (notification.getActions().isEmpty()) { val disableDetection = Intent(context, NotificationReceiver::class.java) @@ -223,14 +225,17 @@ class NotificationWork constructor( NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_PUSH) .setSmallIcon(R.drawable.notification_icon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(user.toPlatformAccount(), false, context)) .setShowWhen(true) .setSubText(user.accountName) .setContentTitle(context.getString(R.string.new_notification)) .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) .setAutoCancel(true) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setContentIntent(pendingIntent).build() + .setContentIntent(pendingIntent) + .also { + viewThemeUtils.androidx.themeNotificationCompatBuilder(context, it) + } + .build() ) val notificationManager = NotificationManagerCompat.from(context) notificationManager.notify(notification.getNotificationId(), notificationBuilder.build()) diff --git a/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt b/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt index e7cd027255..183b8fe006 100644 --- a/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt +++ b/app/src/main/java/com/nextcloud/client/logger/ui/LogsActivity.kt @@ -33,7 +33,7 @@ import com.nextcloud.client.di.ViewModelFactory import com.owncloud.android.R import com.owncloud.android.databinding.LogsActivityBinding import com.owncloud.android.ui.activity.ToolbarActivity -import com.owncloud.android.utils.theme.ThemeBarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject class LogsActivity : ToolbarActivity() { @@ -42,7 +42,8 @@ class LogsActivity : ToolbarActivity() { protected lateinit var viewModelFactory: ViewModelFactory @Inject - protected lateinit var themeBarUtils: ThemeBarUtils + lateinit var viewThemeUtils: ViewThemeUtils + private lateinit var vm: LogsViewModel private lateinit var binding: LogsActivityBinding private lateinit var logsAdapter: LogsAdapter @@ -67,7 +68,7 @@ class LogsActivity : ToolbarActivity() { } findViewById(R.id.logs_loading_progress).apply { - themeBarUtils.themeProgressBar(context, this, themeColorUtils) + viewThemeUtils.platform.themeHorizontalProgressBar(this) } logsAdapter = LogsAdapter(this) @@ -81,17 +82,18 @@ class LogsActivity : ToolbarActivity() { setupToolbar() supportActionBar?.setDisplayHomeAsUpEnabled(true) - supportActionBar?.apply { themeToolbarUtils.setColoredTitle(this, getString(R.string.logs_title), baseContext) } - themeToolbarUtils.tintBackButton(supportActionBar, baseContext) + supportActionBar?.let { + viewThemeUtils.files.themeActionBar(this, it, R.string.logs_title) + } } override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.activity_logs, menu) + (menu.findItem(R.id.action_search).actionView as SearchView).apply { setOnQueryTextListener(searchBoxListener) - - themeToolbarUtils.themeSearchView(this, context) + viewThemeUtils.androidx.themeToolbarSearchView(this) } return super.onCreateOptionsMenu(menu) } diff --git a/app/src/main/java/com/nextcloud/client/media/PlayerService.kt b/app/src/main/java/com/nextcloud/client/media/PlayerService.kt index ad4096c589..5d8e7a3364 100644 --- a/app/src/main/java/com/nextcloud/client/media/PlayerService.kt +++ b/app/src/main/java/com/nextcloud/client/media/PlayerService.kt @@ -33,7 +33,7 @@ import com.nextcloud.client.network.ClientFactory import com.owncloud.android.R import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.notifications.NotificationUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import dagger.android.AndroidInjection import java.util.Locale import javax.inject.Inject @@ -90,7 +90,7 @@ class PlayerService : Service() { protected lateinit var clientFactory: ClientFactory @Inject - protected lateinit var themeColorUtils: ThemeColorUtils + lateinit var viewThemeUtils: ViewThemeUtils private lateinit var player: Player private lateinit var notificationBuilder: NotificationCompat.Builder @@ -101,7 +101,7 @@ class PlayerService : Service() { AndroidInjection.inject(this) player = Player(applicationContext, clientFactory, playerListener, audioManager) notificationBuilder = NotificationCompat.Builder(this) - notificationBuilder.color = themeColorUtils.primaryColor(this) + viewThemeUtils.androidx.themeNotificationCompatBuilder(this, notificationBuilder) val stop = Intent(this, PlayerService::class.java) stop.action = ACTION_STOP diff --git a/app/src/main/java/com/nextcloud/client/network/ClientFactoryImpl.java b/app/src/main/java/com/nextcloud/client/network/ClientFactoryImpl.java index 95ff761e28..c24c34cf89 100644 --- a/app/src/main/java/com/nextcloud/client/network/ClientFactoryImpl.java +++ b/app/src/main/java/com/nextcloud/client/network/ClientFactoryImpl.java @@ -37,11 +37,11 @@ import com.owncloud.android.lib.common.accounts.AccountUtils; import java.io.IOException; -class ClientFactoryImpl implements ClientFactory { +public class ClientFactoryImpl implements ClientFactory { private Context context; - ClientFactoryImpl(Context context) { + public ClientFactoryImpl(Context context) { this.context = context; } @@ -49,8 +49,8 @@ class ClientFactoryImpl implements ClientFactory { public OwnCloudClient create(User user) throws CreationException { try { return OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(user.toOwnCloudAccount(), context); - } catch (OperationCanceledException| - AuthenticatorException| + } catch (OperationCanceledException | + AuthenticatorException | IOException e) { throw new CreationException(e); } diff --git a/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt b/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt index 55cec1f040..9f754f5fe7 100644 --- a/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt +++ b/app/src/main/java/com/nextcloud/client/notifications/AppNotificationManagerImpl.kt @@ -16,14 +16,14 @@ import com.owncloud.android.ui.activity.FileDisplayActivity import com.owncloud.android.ui.notifications.NotificationUtils import com.owncloud.android.ui.preview.PreviewImageActivity import com.owncloud.android.ui.preview.PreviewImageFragment -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject class AppNotificationManagerImpl @Inject constructor( private val context: Context, private val resources: Resources, private val platformNotificationsManager: NotificationManager, - private val themeColorUtils: ThemeColorUtils + private val viewThemeUtils: ViewThemeUtils ) : AppNotificationManager { companion object { @@ -32,12 +32,13 @@ class AppNotificationManagerImpl @Inject constructor( } private fun builder(channelId: String): NotificationCompat.Builder { - val color = themeColorUtils.primaryColor(context, true) - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - NotificationCompat.Builder(context, channelId).setColor(color) + val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationCompat.Builder(context, channelId) } else { - NotificationCompat.Builder(context).setColor(color) + NotificationCompat.Builder(context) } + viewThemeUtils.androidx.themeNotificationCompatBuilder(context, builder) + return builder } override fun buildDownloadServiceForegroundNotification(): Notification { diff --git a/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java b/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java index 779556038b..759b0b815f 100644 --- a/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java +++ b/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java @@ -32,9 +32,7 @@ import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.LinearLayout; -import android.widget.TextView; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.appinfo.AppInfo; @@ -43,11 +41,11 @@ import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.BuildConfig; import com.owncloud.android.R; import com.owncloud.android.authentication.AuthenticatorActivity; +import com.owncloud.android.databinding.FirstRunActivityBinding; import com.owncloud.android.features.FeatureItem; import com.owncloud.android.ui.activity.BaseActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.adapter.FeaturesViewAdapter; -import com.owncloud.android.ui.whatsnew.ProgressIndicator; import com.owncloud.android.utils.DisplayUtils; import javax.inject.Inject; @@ -63,29 +61,30 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh public static final String EXTRA_EXIT = "EXIT"; public static final int FIRST_RUN_RESULT_CODE = 199; - private ProgressIndicator progressIndicator; - @Inject UserAccountManager userAccountManager; @Inject AppPreferences preferences; @Inject AppInfo appInfo; @Inject OnboardingService onboarding; + private FirstRunActivityBinding binding; + @Override protected void onCreate(Bundle savedInstanceState) { enableAccountHandling = false; super.onCreate(savedInstanceState); - setContentView(R.layout.first_run_activity); + this.binding = FirstRunActivityBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation); setSlideshowSize(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); - Button loginButton = findViewById(R.id.login); - loginButton.setBackgroundColor(getResources().getColor(R.color.login_btn_tint)); - loginButton.setTextColor(getResources().getColor(R.color.primary)); - loginButton.setOnClickListener(v -> { + binding.login.setBackgroundColor(getResources().getColor(R.color.login_btn_tint)); + binding.login.setTextColor(getResources().getColor(R.color.primary)); + + binding.login.setOnClickListener(v -> { if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) { Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class); authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, false); @@ -95,11 +94,11 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh } }); - Button providerButton = findViewById(R.id.signup); - providerButton.setBackgroundColor(getResources().getColor(R.color.primary)); - providerButton.setTextColor(getResources().getColor(R.color.login_text_color)); - providerButton.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); - providerButton.setOnClickListener(v -> { + + binding.signup.setBackgroundColor(getResources().getColor(R.color.primary)); + binding.signup.setTextColor(getResources().getColor(R.color.login_text_color)); + binding.signup.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); + binding.signup.setOnClickListener(v -> { Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class); authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, true); @@ -111,16 +110,13 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh } }); - TextView hostOwnServerTextView = findViewById(R.id.host_own_server); - hostOwnServerTextView.setTextColor(getResources().getColor(R.color.login_text_color)); - hostOwnServerTextView.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); + binding.hostOwnServer.setTextColor(getResources().getColor(R.color.login_text_color)); + binding.hostOwnServer.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); - if(!isProviderOrOwnInstallationVisible) { - hostOwnServerTextView.setOnClickListener(v -> onHostYourOwnServerClick()); + if (!isProviderOrOwnInstallationVisible) { + binding.hostOwnServer.setOnClickListener(v -> onHostYourOwnServerClick()); } - progressIndicator = findViewById(R.id.progressIndicator); - ViewPager viewPager = findViewById(R.id.contentPanel); // Sometimes, accounts are not deleted when you uninstall the application so we'll do it now if (onboarding.isFirstRun()) { @@ -128,29 +124,26 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh } FeaturesViewAdapter featuresViewAdapter = new FeaturesViewAdapter(getSupportFragmentManager(), getFirstRun()); - progressIndicator.setNumberOfSteps(featuresViewAdapter.getCount()); - viewPager.setAdapter(featuresViewAdapter); + binding.progressIndicator.setNumberOfSteps(featuresViewAdapter.getCount()); + binding.contentPanel.setAdapter(featuresViewAdapter); - viewPager.addOnPageChangeListener(this); + binding.contentPanel.addOnPageChangeListener(this); } private void setSlideshowSize(boolean isLandscape) { boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation); - LinearLayout buttonLayout = findViewById(R.id.buttonLayout); + LinearLayout.LayoutParams layoutParams; - buttonLayout.setOrientation(isLandscape ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); + binding.buttonLayout.setOrientation(isLandscape ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); - LinearLayout bottomLayout = findViewById(R.id.bottomLayout); if (isProviderOrOwnInstallationVisible) { - layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); + layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } else { - layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - DisplayUtils.convertDpToPixel(isLandscape ? 100f : 150f, this)); + layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.convertDpToPixel(isLandscape ? 100f : 150f, this)); } - bottomLayout.setLayoutParams(layoutParams); + binding.bottomLayout.setLayoutParams(layoutParams); } @Override @@ -196,7 +189,7 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh @Override public void onPageSelected(int position) { - progressIndicator.animateToStep(position + 1); + binding.progressIndicator.animateToStep(position + 1); } @Override @@ -235,7 +228,6 @@ public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageCh } - public static FeatureItem[] getFirstRun() { return new FeatureItem[]{ new FeatureItem(R.drawable.logo, R.string.first_run_1_text, R.string.empty, true, false), diff --git a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java index 08a17d1e4b..e5721b2be6 100644 --- a/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java +++ b/app/src/main/java/com/nextcloud/client/onboarding/WhatsNewActivity.java @@ -37,7 +37,7 @@ import com.owncloud.android.R; import com.owncloud.android.ui.adapter.FeaturesViewAdapter; import com.owncloud.android.ui.adapter.FeaturesWebViewAdapter; import com.owncloud.android.ui.whatsnew.ProgressIndicator; -import com.owncloud.android.utils.theme.ThemeButtonUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -56,7 +56,7 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa @Inject AppPreferences preferences; @Inject AppInfo appInfo; @Inject OnboardingService onboarding; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; @Override protected void onCreate(Bundle savedInstanceState) { @@ -86,7 +86,7 @@ public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPa mPager.addOnPageChangeListener(this); mForwardFinishButton = findViewById(R.id.forward); - themeButtonUtils.colorImageButton(mForwardFinishButton, fontColor); + viewThemeUtils.platform.colorImageButton(mForwardFinishButton, fontColor); mForwardFinishButton.setOnClickListener(view -> { if (mProgress.hasNextStep()) { diff --git a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java index 6754c379c7..28fb304101 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -25,8 +25,8 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; +import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.account.UserAccountManagerImpl; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -45,15 +45,14 @@ import static com.owncloud.android.ui.fragment.OCFileListFragment.FOLDER_LAYOUT_ /** * Implementation of application-wide preferences using {@link SharedPreferences}. - * - * Users should not use this class directly. Please use {@link AppPreferences} interface - * instead. + *

+ * Users should not use this class directly. Please use {@link AppPreferences} interface instead. */ public final class AppPreferencesImpl implements AppPreferences { /** - * Constant to access value of last path selected by the user to upload a file shared from other app. - * Value handled by the app without direct access in the UI. + * Constant to access value of last path selected by the user to upload a file shared from other app. Value handled + * by the app without direct access in the UI. */ public static final String AUTO_PREF__LAST_SEEN_VERSION_CODE = "lastSeenVersionCode"; public static final String STORAGE_PATH = "storage_path"; @@ -101,7 +100,7 @@ public final class AppPreferencesImpl implements AppPreferences { private final Context context; private final SharedPreferences preferences; - private final CurrentAccountProvider currentAccountProvider; + private final UserAccountManager userAccountManager; private final ListenerRegistry listeners; /** @@ -123,7 +122,7 @@ public final class AppPreferencesImpl implements AppPreferences { } } - void remove(@Nullable final Listener listener) { + void remove(@Nullable final Listener listener) { if (listener != null) { listeners.remove(listener); } @@ -133,7 +132,7 @@ public final class AppPreferencesImpl implements AppPreferences { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (PREF__DARK_THEME.equals(key)) { DarkMode mode = preferences.getDarkThemeMode(); - for(Listener l : listeners) { + for (Listener l : listeners) { l.onDarkThemeModeChanged(mode); } } @@ -141,9 +140,9 @@ public final class AppPreferencesImpl implements AppPreferences { } /** - * This is a temporary workaround to access app preferences in places that cannot use - * dependency injection yet. Use injected component via {@link AppPreferences} interface. - * + * This is a temporary workaround to access app preferences in places that cannot use dependency injection yet. Use + * injected component via {@link AppPreferences} interface. + *

* WARNING: this creates new instance! it does not return app-wide singleton * * @param context Context used to create shared preferences @@ -151,15 +150,15 @@ public final class AppPreferencesImpl implements AppPreferences { */ @Deprecated public static AppPreferences fromContext(Context context) { - final CurrentAccountProvider currentAccountProvider = UserAccountManagerImpl.fromContext(context); + final UserAccountManager userAccountManager = UserAccountManagerImpl.fromContext(context); final SharedPreferences prefs = android.preference.PreferenceManager.getDefaultSharedPreferences(context); - return new AppPreferencesImpl(context, prefs, currentAccountProvider); + return new AppPreferencesImpl(context, prefs, userAccountManager); } - AppPreferencesImpl(Context appContext, SharedPreferences preferences, CurrentAccountProvider currentAccountProvider) { + AppPreferencesImpl(Context appContext, SharedPreferences preferences, UserAccountManager userAccountManager) { this.context = appContext; this.preferences = preferences; - this.currentAccountProvider = currentAccountProvider; + this.userAccountManager = userAccountManager; this.listeners = new ListenerRegistry(this); this.preferences.registerOnSharedPreferenceChangeListener(listeners); } @@ -277,7 +276,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public String[] getPassCode() { - return new String[] { + return new String[]{ preferences.getString(PassCodeActivity.PREFERENCE_PASSCODE_D1, null), preferences.getString(PassCodeActivity.PREFERENCE_PASSCODE_D2, null), preferences.getString(PassCodeActivity.PREFERENCE_PASSCODE_D3, null), @@ -293,7 +292,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public String getFolderLayout(OCFile folder) { return getFolderPreference(context, - currentAccountProvider.getUser(), + userAccountManager.getUser(), PREF__FOLDER_LAYOUT, folder, FOLDER_LAYOUT_LIST); @@ -302,7 +301,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public void setFolderLayout(@Nullable OCFile folder, String layoutName) { setFolderPreference(context, - currentAccountProvider.getUser(), + userAccountManager.getUser(), PREF__FOLDER_LAYOUT, folder, layoutName); @@ -311,7 +310,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public FileSortOrder getSortOrderByFolder(OCFile folder) { return FileSortOrder.sortOrders.get(getFolderPreference(context, - currentAccountProvider.getUser(), + userAccountManager.getUser(), PREF__FOLDER_SORT_ORDER, folder, FileSortOrder.sort_a_to_z.name)); @@ -320,7 +319,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public void setSortOrder(@Nullable OCFile folder, FileSortOrder sortOrder) { setFolderPreference(context, - currentAccountProvider.getUser(), + userAccountManager.getUser(), PREF__FOLDER_SORT_ORDER, folder, sortOrder.name); @@ -333,7 +332,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public FileSortOrder getSortOrderByType(FileSortOrder.Type type, FileSortOrder defaultOrder) { - User user = currentAccountProvider.getUser(); + User user = userAccountManager.getUser(); if (user.isAnonymous()) { return defaultOrder; } @@ -347,7 +346,7 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public void setSortOrder(FileSortOrder.Type type, FileSortOrder sortOrder) { - User user = currentAccountProvider.getUser(); + User user = userAccountManager.getUser(); ArbitraryDataProvider dataProvider = new ArbitraryDataProvider(context.getContentResolver()); dataProvider.storeOrUpdateKeyValue(user.getAccountName(), PREF__FOLDER_SORT_ORDER + "_" + type, sortOrder.name); } @@ -506,19 +505,19 @@ public final class AppPreferencesImpl implements AppPreferences { @Override public void removeLegacyPreferences() { preferences.edit() - .remove("instant_uploading") - .remove("instant_video_uploading") - .remove("instant_upload_path") - .remove("instant_upload_path_use_subfolders") - .remove("instant_upload_on_wifi") - .remove("instant_upload_on_charging") - .remove("instant_video_upload_path") - .remove("instant_video_upload_path_use_subfolders") - .remove("instant_video_upload_on_wifi") - .remove("instant_video_uploading") - .remove("instant_video_upload_on_charging") - .remove("prefs_instant_behaviour") - .apply(); + .remove("instant_uploading") + .remove("instant_video_uploading") + .remove("instant_upload_path") + .remove("instant_upload_path_use_subfolders") + .remove("instant_upload_on_wifi") + .remove("instant_upload_on_charging") + .remove("instant_video_upload_path") + .remove("instant_video_upload_path_use_subfolders") + .remove("instant_video_upload_on_wifi") + .remove("instant_video_uploading") + .remove("instant_video_upload_on_charging") + .remove("prefs_instant_behaviour") + .apply(); } @Override @@ -588,13 +587,12 @@ public final class AppPreferencesImpl implements AppPreferences { } /** - * Get preference value for a folder. - * If folder is not set itself, it finds an ancestor that is set. + * Get preference value for a folder. If folder is not set itself, it finds an ancestor that is set. * - * @param context Context object. + * @param context Context object. * @param preferenceName Name of the preference to lookup. - * @param folder Folder. - * @param defaultValue Fallback value in case no ancestor is set. + * @param folder Folder. + * @param defaultValue Fallback value in case no ancestor is set. * @return Preference value */ private static String getFolderPreference(final Context context, @@ -621,10 +619,10 @@ public final class AppPreferencesImpl implements AppPreferences { /** * Set preference value for a folder. * - * @param context Context object. + * @param context Context object. * @param preferenceName Name of the preference to set. - * @param folder Folder. - * @param value Preference value to set. + * @param folder Folder. + * @param value Preference value to set. */ private static void setFolderPreference(final Context context, final User user, @@ -637,7 +635,7 @@ public final class AppPreferencesImpl implements AppPreferences { private static String getKeyFromFolder(String preferenceName, @Nullable OCFile folder) { final String folderIdString = String.valueOf(folder != null ? folder.getFileId() : - FileDataStorageManager.ROOT_PARENT_ID); + FileDataStorageManager.ROOT_PARENT_ID); return preferenceName + "_" + folderIdString; } diff --git a/app/src/main/java/com/nextcloud/client/preferences/PreferencesModule.java b/app/src/main/java/com/nextcloud/client/preferences/PreferencesModule.java index 6d3338fb37..d0b1d37103 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/PreferencesModule.java +++ b/app/src/main/java/com/nextcloud/client/preferences/PreferencesModule.java @@ -3,7 +3,7 @@ package com.nextcloud.client.preferences; import android.content.Context; import android.content.SharedPreferences; -import com.nextcloud.client.account.CurrentAccountProvider; +import com.nextcloud.client.account.UserAccountManager; import javax.inject.Singleton; @@ -23,7 +23,7 @@ public class PreferencesModule { @Singleton public AppPreferences appPreferences(Context context, SharedPreferences sharedPreferences, - CurrentAccountProvider currentAccountProvider) { - return new AppPreferencesImpl(context, sharedPreferences, currentAccountProvider); + UserAccountManager userAccountManager) { + return new AppPreferencesImpl(context, sharedPreferences, userAccountManager); } } diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationActivity.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationActivity.kt new file mode 100644 index 0000000000..6a056f5831 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationActivity.kt @@ -0,0 +1,236 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.nextcloud.client.widget + +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID +import android.content.Intent +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.content.res.AppCompatResources +import androidx.recyclerview.widget.LinearLayoutManager +import com.nextcloud.android.lib.resources.dashboard.DashBoardButtonType +import com.nextcloud.android.lib.resources.dashboard.DashboardListWidgetsRemoteOperation +import com.nextcloud.android.lib.resources.dashboard.DashboardWidget +import com.nextcloud.client.account.User +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.di.Injectable +import com.nextcloud.client.network.ClientFactory +import com.nextcloud.client.network.ClientFactory.CreationException +import com.owncloud.android.R +import com.owncloud.android.databinding.DashboardWidgetConfigurationLayoutBinding +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.ui.adapter.DashboardWidgetListAdapter +import com.owncloud.android.ui.dialog.AccountChooserInterface +import com.owncloud.android.ui.dialog.MultipleAccountsDialog +import com.owncloud.android.utils.theme.ViewThemeUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class DashboardWidgetConfigurationActivity : + AppCompatActivity(), + DashboardWidgetConfigurationInterface, + Injectable, + AccountChooserInterface { + private lateinit var mAdapter: DashboardWidgetListAdapter + private lateinit var binding: DashboardWidgetConfigurationLayoutBinding + private lateinit var currentUser: User + + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + + @Inject + lateinit var accountManager: UserAccountManager + + @Inject + lateinit var clientFactory: ClientFactory + + @Inject + lateinit var widgetRepository: WidgetRepository + + @Inject + lateinit var widgetUpdater: DashboardWidgetUpdater + + var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + + public override fun onCreate(bundle: Bundle?) { + super.onCreate(bundle) + + // Set the result to CANCELED. This will cause the widget host to cancel + // out of the widget placement if the user presses the back button. + setResult(RESULT_CANCELED) + + binding = DashboardWidgetConfigurationLayoutBinding.inflate(layoutInflater) + setContentView(binding.root) + + viewThemeUtils.platform.colorDrawable(binding.icon.drawable, getColor(R.color.dark)) + + val layoutManager = LinearLayoutManager(this) + // TODO follow our new architecture + mAdapter = DashboardWidgetListAdapter(accountManager, clientFactory, this, this) + binding.list.apply { + setHasFooter(false) + setAdapter(mAdapter) + setLayoutManager(layoutManager) + setEmptyView(binding.emptyView.emptyListView) + } + + currentUser = accountManager.user + if (accountManager.allUsers.size > 1) { + binding.chooseWidget.visibility = View.GONE + + binding.accountName.apply { + setCompoundDrawablesWithIntrinsicBounds( + null, + null, + viewThemeUtils.platform.colorDrawable( + AppCompatResources.getDrawable( + context, + R.drawable.ic_baseline_arrow_drop_down_24 + )!!, + getColor(R.color.black) + ), + null + ) + visibility = View.VISIBLE + text = currentUser.accountName + setOnClickListener { + val dialog = MultipleAccountsDialog() + dialog.highlightCurrentlyActiveAccount = false + dialog.show(supportFragmentManager, null) + } + } + } + loadWidgets(currentUser) + + binding.close.setOnClickListener { finish() } + + // Find the widget id from the intent. + appWidgetId = intent?.extras?.getInt( + AppWidgetManager.EXTRA_APPWIDGET_ID, + AppWidgetManager.INVALID_APPWIDGET_ID + ) ?: AppWidgetManager.INVALID_APPWIDGET_ID + + // If this activity was started with an intent without an app widget ID, finish with an error. + if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) { + finish() + return + } + } + + private fun loadWidgets(user: User) { + CoroutineScope(Dispatchers.IO).launch { + withContext(Dispatchers.Main) { + binding.emptyView.root.visibility = View.GONE + if (accountManager.allUsers.size > 1) { + binding.accountName.text = user.accountName + } + } + + try { + val client = clientFactory.createNextcloudClient(user) + val result = DashboardListWidgetsRemoteOperation().execute(client) + + withContext(Dispatchers.Main) { + if (result.code == RemoteOperationResult.ResultCode.FILE_NOT_FOUND) { + withContext(Dispatchers.Main) { + mAdapter.setWidgetList(null) + binding.emptyView.root.visibility = View.VISIBLE + binding.emptyView.emptyListViewHeadline.setText(R.string.widgets_not_available_title) + + binding.emptyView.emptyListIcon.apply { + setImageResource(R.drawable.ic_list_empty_error) + visibility = View.VISIBLE + } + binding.emptyView.emptyListViewText.apply { + setText( + String.format( + getString(R.string.widgets_not_available), + getString(R.string.app_name) + ) + ) + visibility = View.VISIBLE + } + } + } else { + mAdapter.setWidgetList(result.resultData) + } + } + } catch (e: CreationException) { + Log_OC.e(this, "Error loading widgets for user $user", e) + + withContext(Dispatchers.Main) { + mAdapter.setWidgetList(null) + binding.emptyView.root.visibility = View.VISIBLE + + binding.emptyView.emptyListIcon.apply { + setImageResource(R.drawable.ic_list_empty_error) + visibility = View.VISIBLE + } + binding.emptyView.emptyListViewText.apply { + setText(R.string.common_error) + visibility = View.VISIBLE + } + binding.emptyView.emptyListViewAction.apply { + visibility = View.VISIBLE + setText(R.string.reload) + setOnClickListener { + loadWidgets(user) + } + } + } + } + } + } + + override fun onItemClicked(dashboardWidget: DashboardWidget) { + widgetRepository.saveWidget(appWidgetId, dashboardWidget, currentUser) + + // update widget + val appWidgetManager = AppWidgetManager.getInstance(this) + + widgetUpdater.updateAppWidget( + appWidgetManager, + appWidgetId, + dashboardWidget.title, + dashboardWidget.iconUrl, + dashboardWidget.buttons?.find { it.type == DashBoardButtonType.NEW } + ) + + val resultValue = Intent().apply { + putExtra(EXTRA_APPWIDGET_ID, appWidgetId) + } + + setResult(RESULT_OK, resultValue) + finish() + } + + override fun onAccountChosen(user: User) { + currentUser = user + loadWidgets(user) + } +} diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationInterface.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationInterface.kt new file mode 100644 index 0000000000..1901349f26 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetConfigurationInterface.kt @@ -0,0 +1,29 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import com.nextcloud.android.lib.resources.dashboard.DashboardWidget + +interface DashboardWidgetConfigurationInterface { + fun onItemClicked(dashboardWidget: DashboardWidget) +} diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetProvider.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetProvider.kt new file mode 100644 index 0000000000..220298dd3e --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetProvider.kt @@ -0,0 +1,80 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.Context +import android.content.Intent +import dagger.android.AndroidInjection +import javax.inject.Inject + +/** + * Manages widgets + */ +class DashboardWidgetProvider : AppWidgetProvider() { + @Inject + lateinit var widgetRepository: WidgetRepository + + @Inject + lateinit var widgetUpdater: DashboardWidgetUpdater + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + AndroidInjection.inject(this, context) + + for (appWidgetId in appWidgetIds) { + val widgetConfiguration = widgetRepository.getWidget(appWidgetId) + + widgetUpdater.updateAppWidget( + appWidgetManager, + appWidgetId, + widgetConfiguration.title, + widgetConfiguration.iconUrl, + widgetConfiguration.addButton + ) + } + } + + override fun onReceive(context: Context?, intent: Intent?) { + super.onReceive(context, intent) + AndroidInjection.inject(this, context) + + if (intent?.action == OPEN_INTENT) { + val clickIntent = Intent(Intent.ACTION_VIEW, intent.data) + clickIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context?.startActivity(clickIntent) + } + } + + override fun onDeleted(context: Context?, appWidgetIds: IntArray) { + AndroidInjection.inject(this, context) + + for (appWidgetId in appWidgetIds) { + widgetRepository.deleteWidget(appWidgetId) + } + } + + companion object { + const val OPEN_INTENT = "open" + } +} diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt new file mode 100644 index 0000000000..aed8a70fff --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt @@ -0,0 +1,243 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.view.View +import android.widget.RemoteViews +import android.widget.RemoteViewsService +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.StreamEncoder +import com.bumptech.glide.load.resource.file.FileToStreamDecoder +import com.bumptech.glide.request.FutureTarget +import com.nextcloud.android.lib.resources.dashboard.DashboardGetWidgetItemsRemoteOperation +import com.nextcloud.android.lib.resources.dashboard.DashboardWidgetItem +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.network.ClientFactory +import com.owncloud.android.R +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.utils.BitmapUtils +import com.owncloud.android.utils.DisplayUtils.SVG_SIZE +import com.owncloud.android.utils.glide.CustomGlideStreamLoader +import com.owncloud.android.utils.glide.CustomGlideUriLoader +import com.owncloud.android.utils.svg.SVGorImage +import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder +import com.owncloud.android.utils.svg.SvgOrImageDecoder +import dagger.android.AndroidInjection +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import java.io.InputStream +import javax.inject.Inject + +class DashboardWidgetService : RemoteViewsService() { + @Inject + lateinit var userAccountManager: UserAccountManager + + @Inject + lateinit var clientFactory: ClientFactory + + @Inject + lateinit var widgetRepository: WidgetRepository + + override fun onCreate() { + super.onCreate() + AndroidInjection.inject(this) + } + + override fun onGetViewFactory(intent: Intent): RemoteViewsFactory { + return StackRemoteViewsFactory( + this.applicationContext, + userAccountManager, + clientFactory, + intent, + widgetRepository + ) + } +} + +class StackRemoteViewsFactory( + private val context: Context, + val userAccountManager: UserAccountManager, + val clientFactory: ClientFactory, + val intent: Intent, + val widgetRepository: WidgetRepository +) : RemoteViewsService.RemoteViewsFactory { + + private lateinit var widgetConfiguration: WidgetConfiguration + private var widgetItems: List = emptyList() + private var hasLoadMore = false + + override fun onCreate() { + Log_OC.d(this, "onCreate") + val appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) + + widgetConfiguration = widgetRepository.getWidget(appWidgetId) + + if (!widgetConfiguration.user.isPresent) { + // TODO show error + Log_OC.e(this, "No user found!") + } + + onDataSetChanged() + } + + override fun onDataSetChanged() { + CoroutineScope(Dispatchers.IO).launch { + try { + val client = clientFactory.createNextcloudClient(widgetConfiguration.user.get()) + val result = + DashboardGetWidgetItemsRemoteOperation(widgetConfiguration.widgetId, LIMIT_SIZE).execute(client) + widgetItems = result.resultData[widgetConfiguration.widgetId] ?: emptyList() + + hasLoadMore = widgetConfiguration.moreButton != null && + widgetItems.size == LIMIT_SIZE + } catch (e: ClientFactory.CreationException) { + Log_OC.e(this, "Error updating widget", e) + } + } + + Log_OC.d("WidgetService", "onDataSetChanged") + } + + override fun onDestroy() { + Log_OC.d("WidgetService", "onDestroy") + + widgetItems = emptyList() + } + + override fun getCount(): Int { + return if (hasLoadMore && widgetItems.isNotEmpty()) { + widgetItems.size + 1 + } else { + widgetItems.size + } + } + + override fun getViewAt(position: Int): RemoteViews { + return if (position == widgetItems.size) { + createLoadMoreView() + } else { + createItemView(position) + } + } + + private fun createLoadMoreView(): RemoteViews { + return RemoteViews(context.packageName, R.layout.widget_item_load_more).apply { + val clickIntent = Intent(Intent.ACTION_VIEW, Uri.parse(widgetConfiguration.moreButton?.link)) + setTextViewText(R.id.load_more, widgetConfiguration.moreButton?.text) + setOnClickFillInIntent(R.id.load_more_container, clickIntent) + } + } + + // we will switch soon to coil and then streamline all of this + // Kotlin cannot catch multiple exception types at same time + @Suppress("NestedBlockDepth", "TooGenericExceptionCaught") + private fun createItemView(position: Int): RemoteViews { + return RemoteViews(context.packageName, R.layout.widget_item).apply { + val widgetItem = widgetItems[position] + + // icon bitmap/svg + if (widgetItem.iconUrl.isNotEmpty()) { + val glide: FutureTarget + if (Uri.parse(widgetItem.iconUrl).encodedPath!!.endsWith(".svg")) { + glide = Glide.with(context) + .using( + CustomGlideUriLoader(userAccountManager.user, clientFactory), + InputStream::class.java + ) + .from(Uri::class.java) + .`as`(SVGorImage::class.java) + .transcode(SvgOrImageBitmapTranscoder(SVG_SIZE, SVG_SIZE), Bitmap::class.java) + .sourceEncoder(StreamEncoder()) + .cacheDecoder(FileToStreamDecoder(SvgOrImageDecoder())) + .decoder(SvgOrImageDecoder()) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .load(Uri.parse(widgetItem.iconUrl)) + .into(SVG_SIZE, SVG_SIZE) + } else { + glide = Glide.with(context) + .using(CustomGlideStreamLoader(widgetConfiguration.user.get(), clientFactory)) + .load(widgetItem.iconUrl) + .asBitmap() + .into(SVG_SIZE, SVG_SIZE) + } + + try { + if (widgetConfiguration.roundIcon) { + setImageViewBitmap(R.id.icon, BitmapUtils.roundBitmap(glide.get())) + } else { + setImageViewBitmap(R.id.icon, glide.get()) + } + } catch (e: Exception) { + Log_OC.d(this, "Error setting icon", e) + setImageViewResource(R.id.icon, R.drawable.ic_dashboard) + } + } + + // text + setTextViewText(R.id.title, widgetItem.title) + + if (widgetItem.subtitle.isNotEmpty()) { + setViewVisibility(R.id.subtitle, View.VISIBLE) + setTextViewText(R.id.subtitle, widgetItem.subtitle) + } else { + setViewVisibility(R.id.subtitle, View.GONE) + } + + if (widgetItem.link.isNotEmpty()) { + val clickIntent = Intent(Intent.ACTION_VIEW, Uri.parse(widgetItem.link)) + setOnClickFillInIntent(R.id.text_container, clickIntent) + } + } + } + + override fun getLoadingView(): RemoteViews? { + return null + } + + override fun getViewTypeCount(): Int { + return if (hasLoadMore) { + 2 + } else { + 1 + } + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun hasStableIds(): Boolean { + return true + } + + companion object { + const val LIMIT_SIZE = 14 + } +} diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetUpdater.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetUpdater.kt new file mode 100644 index 0000000000..d6db1eed18 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetUpdater.kt @@ -0,0 +1,166 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import android.annotation.SuppressLint +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.net.Uri +import android.view.View +import android.widget.RemoteViews +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.StreamEncoder +import com.bumptech.glide.load.resource.file.FileToStreamDecoder +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.AppWidgetTarget +import com.nextcloud.android.lib.resources.dashboard.DashboardButton +import com.nextcloud.client.account.CurrentAccountProvider +import com.nextcloud.client.network.ClientFactory +import com.owncloud.android.R +import com.owncloud.android.utils.BitmapUtils +import com.owncloud.android.utils.DisplayUtils.SVG_SIZE +import com.owncloud.android.utils.glide.CustomGlideUriLoader +import com.owncloud.android.utils.svg.SVGorImage +import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder +import com.owncloud.android.utils.svg.SvgOrImageDecoder +import java.io.InputStream +import javax.inject.Inject + +class DashboardWidgetUpdater @Inject constructor( + private val context: Context, + private val clientFactory: ClientFactory, + private val accountProvider: CurrentAccountProvider +) { + + fun updateAppWidget( + appWidgetManager: AppWidgetManager, + appWidgetId: Int, + title: String, + iconUrl: String, + addButton: DashboardButton? + ) { + val intent = Intent(context, DashboardWidgetService::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId) + data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME)) + } + + val views = RemoteViews(context.packageName, R.layout.dashboard_widget).apply { + setRemoteAdapter(R.id.list, intent) + setEmptyView(R.id.list, R.id.empty_view) + setTextViewText(R.id.title, title) + + setAddButton(addButton, appWidgetId, this) + setPendingReload(this, appWidgetId) + setPendingClick(this) + loadIcon(appWidgetId, iconUrl, this) + } + + appWidgetManager.updateAppWidget(appWidgetId, views) + appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list) + } + + private fun setPendingReload(remoteViews: RemoteViews, appWidgetId: Int) { + val intentUpdate = Intent(context, DashboardWidgetProvider::class.java) + intentUpdate.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE + + val idArray = intArrayOf(appWidgetId) + intentUpdate.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, idArray) + + remoteViews.setOnClickPendingIntent( + R.id.reload, + PendingIntent.getBroadcast( + context, + appWidgetId, + intentUpdate, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + } + + // clickPI needs to me mutable, as it is re-used. PendingIntent.FLAG_IMMUTABLE requires S (API 31) + @SuppressLint("UnspecifiedImmutableFlag") + private fun setPendingClick(remoteViews: RemoteViews) { + val clickPI = PendingIntent.getActivity( + context, + 0, + Intent(), + PendingIntent.FLAG_UPDATE_CURRENT + ) + + remoteViews.setPendingIntentTemplate(R.id.list, clickPI) + } + + private fun setAddButton(addButton: DashboardButton?, appWidgetId: Int, remoteViews: RemoteViews) { + // create add button + if (addButton == null) { + remoteViews.setViewVisibility(R.id.create, View.GONE) + } else { + remoteViews.setViewVisibility(R.id.create, View.VISIBLE) + remoteViews.setContentDescription(R.id.create, addButton.text) + + val clickIntent = Intent(context, DashboardWidgetProvider::class.java) + clickIntent.action = DashboardWidgetProvider.OPEN_INTENT + clickIntent.data = Uri.parse(addButton.link) + + remoteViews.setOnClickPendingIntent( + R.id.create, + PendingIntent.getBroadcast( + context, + appWidgetId, + clickIntent, + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + } + } + + private fun loadIcon(appWidgetId: Int, iconUrl: String, remoteViews: RemoteViews) { + val iconTarget = object : AppWidgetTarget(context, remoteViews, R.id.icon, appWidgetId) { + override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation?) { + if (resource != null) { + val tintedBitmap = BitmapUtils.tintImage(resource, R.color.black) + super.onResourceReady(tintedBitmap, glideAnimation) + } + } + } + + Glide.with(context) + .using( + CustomGlideUriLoader(accountProvider.user, clientFactory), + InputStream::class.java + ) + .from(Uri::class.java) + .`as`(SVGorImage::class.java) + .transcode(SvgOrImageBitmapTranscoder(SVG_SIZE, SVG_SIZE), Bitmap::class.java) + .sourceEncoder(StreamEncoder()) + .cacheDecoder(FileToStreamDecoder(SvgOrImageDecoder())) + .decoder(SvgOrImageDecoder()) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .load(Uri.parse(iconUrl)) + .into(iconTarget) + } +} diff --git a/app/src/main/java/com/nextcloud/client/widget/WidgetConfiguration.kt b/app/src/main/java/com/nextcloud/client/widget/WidgetConfiguration.kt new file mode 100644 index 0000000000..01b5147c63 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/WidgetConfiguration.kt @@ -0,0 +1,37 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import com.nextcloud.android.lib.resources.dashboard.DashboardButton +import com.nextcloud.client.account.User +import com.nextcloud.java.util.Optional + +data class WidgetConfiguration( + val widgetId: String, + val title: String, + val iconUrl: String, + val roundIcon: Boolean, + val user: Optional, + val addButton: DashboardButton?, + val moreButton: DashboardButton? +) diff --git a/app/src/main/java/com/nextcloud/client/widget/WidgetRepository.kt b/app/src/main/java/com/nextcloud/client/widget/WidgetRepository.kt new file mode 100644 index 0000000000..2f52e158b8 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/widget/WidgetRepository.kt @@ -0,0 +1,150 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.client.widget + +import android.content.SharedPreferences +import com.nextcloud.android.lib.resources.dashboard.DashBoardButtonType +import com.nextcloud.android.lib.resources.dashboard.DashboardButton +import com.nextcloud.android.lib.resources.dashboard.DashboardWidget +import com.nextcloud.client.account.User +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.java.util.Optional +import javax.inject.Inject + +class WidgetRepository @Inject constructor( + private val userAccountManager: UserAccountManager, + val preferences: SharedPreferences +) { + fun saveWidget(widgetId: Int, widget: DashboardWidget, user: User) { + val editor: SharedPreferences.Editor = preferences + .edit() + .putString(PREF__WIDGET_ID + widgetId, widget.id) + .putString(PREF__WIDGET_TITLE + widgetId, widget.title) + .putString(PREF__WIDGET_ICON + widgetId, widget.iconUrl) + .putBoolean(PREF__WIDGET_ROUND_ICON + widgetId, widget.roundIcons) + .putString(PREF__WIDGET_USER + widgetId, user.accountName) + val buttonList = widget.buttons + if (buttonList != null && buttonList.isNotEmpty()) { + for (button in buttonList) { + if (button.type == DashBoardButtonType.NEW) { + editor + .putString(PREF__WIDGET_ADD_BUTTON_TYPE + widgetId, button.type.toString()) + .putString(PREF__WIDGET_ADD_BUTTON_URL + widgetId, button.link) + .putString(PREF__WIDGET_ADD_BUTTON_TEXT + widgetId, button.text) + } + if (button.type == DashBoardButtonType.MORE) { + editor + .putString(PREF__WIDGET_MORE_BUTTON_TYPE + widgetId, button.type.toString()) + .putString(PREF__WIDGET_MORE_BUTTON_URL + widgetId, button.link) + .putString(PREF__WIDGET_MORE_BUTTON_TEXT + widgetId, button.text) + } + } + } + editor.apply() + } + + fun deleteWidget(widgetId: Int) { + preferences + .edit() + .remove(PREF__WIDGET_ID + widgetId) + .remove(PREF__WIDGET_TITLE + widgetId) + .remove(PREF__WIDGET_ICON + widgetId) + .remove(PREF__WIDGET_ROUND_ICON + widgetId) + .remove(PREF__WIDGET_USER + widgetId) + .remove(PREF__WIDGET_ADD_BUTTON_TEXT + widgetId) + .remove(PREF__WIDGET_ADD_BUTTON_URL + widgetId) + .remove(PREF__WIDGET_ADD_BUTTON_TYPE + widgetId) + .remove(PREF__WIDGET_MORE_BUTTON_TEXT + widgetId) + .remove(PREF__WIDGET_MORE_BUTTON_URL + widgetId) + .remove(PREF__WIDGET_MORE_BUTTON_TYPE + widgetId) + .apply() + } + + fun getWidget(widgetId: Int): WidgetConfiguration { + val userOptional: Optional = + userAccountManager.getUser(preferences.getString(PREF__WIDGET_USER + widgetId, "")) + + val addButton = createAddButton(widgetId) + val moreButton = createMoreButton(widgetId) + + return WidgetConfiguration( + preferences.getString(PREF__WIDGET_ID + widgetId, "") ?: "", + preferences.getString(PREF__WIDGET_TITLE + widgetId, "") ?: "", + preferences.getString(PREF__WIDGET_ICON + widgetId, "") ?: "", + preferences.getBoolean(PREF__WIDGET_ROUND_ICON + widgetId, false), + userOptional, + addButton, + moreButton + ) + } + + private fun createAddButton(widgetId: Int): DashboardButton? { + var addButton: DashboardButton? = null + if (preferences.contains(PREF__WIDGET_ADD_BUTTON_TYPE + widgetId)) { + addButton = DashboardButton( + DashBoardButtonType.valueOf( + preferences.getString( + PREF__WIDGET_ADD_BUTTON_TYPE + widgetId, + "" + ) ?: "" + ), + preferences.getString(PREF__WIDGET_ADD_BUTTON_TEXT + widgetId, "") ?: "", + preferences.getString(PREF__WIDGET_ADD_BUTTON_URL + widgetId, "") ?: "" + ) + } + + return addButton + } + + private fun createMoreButton(widgetId: Int): DashboardButton? { + var moreButton: DashboardButton? = null + if (preferences.contains(PREF__WIDGET_MORE_BUTTON_TYPE + widgetId)) { + moreButton = DashboardButton( + DashBoardButtonType.valueOf( + preferences.getString( + PREF__WIDGET_MORE_BUTTON_TYPE + widgetId, + "" + ) ?: "" + ), + preferences.getString(PREF__WIDGET_MORE_BUTTON_TEXT + widgetId, "") ?: "", + preferences.getString(PREF__WIDGET_MORE_BUTTON_URL + widgetId, "") ?: "" + ) + } + + return moreButton + } + + companion object { + const val PREF__WIDGET_TITLE = "widget_title_" + private const val PREF__WIDGET_ID = "widget_id_" + private const val PREF__WIDGET_ICON = "widget_icon_" + private const val PREF__WIDGET_ROUND_ICON = "widget_round_icon_" + private const val PREF__WIDGET_USER = "widget_user_" + private const val PREF__WIDGET_ADD_BUTTON_TEXT = "widget_add_button_text_" + private const val PREF__WIDGET_ADD_BUTTON_URL = "widget_add_button_url_" + private const val PREF__WIDGET_ADD_BUTTON_TYPE = "widget_add_button_type_" + private const val PREF__WIDGET_MORE_BUTTON_TEXT = "widget_more_button_text_" + private const val PREF__WIDGET_MORE_BUTTON_URL = "widget_more_button_url_" + private const val PREF__WIDGET_MORE_BUTTON_TYPE = "widget_more_button_type_" + } +} diff --git a/app/src/main/java/com/nextcloud/java/util/Optional.java b/app/src/main/java/com/nextcloud/java/util/Optional.java index b2039d3c6e..4a747dca0d 100644 --- a/app/src/main/java/com/nextcloud/java/util/Optional.java +++ b/app/src/main/java/com/nextcloud/java/util/Optional.java @@ -31,7 +31,6 @@ import java.util.NoSuchElementException; import androidx.core.util.Consumer; import androidx.core.util.ObjectsCompat; import androidx.core.util.Supplier; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import kotlin.jvm.functions.Function1; /** @@ -83,11 +82,9 @@ public final class Optional { * @param Type of the non-existent value * @return an empty {@code Optional} */ + @SuppressWarnings("unchecked") public static Optional empty() { - @SuppressWarnings("unchecked") - @SuppressFBWarnings("USBR_UNNECESSARY_STORE_BEFORE_RETURN") - Optional t = (Optional) EMPTY; - return t; + return (Optional) EMPTY; } /** diff --git a/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt b/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt index 77f91dc9ea..0a19aa8c90 100644 --- a/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt @@ -29,7 +29,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView -import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.client.account.User @@ -48,8 +47,7 @@ import com.owncloud.android.ui.adapter.UserListItem import com.owncloud.android.ui.asynctasks.RetrieveStatusAsyncTask import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject private const val ARG_CURRENT_USER_PARAM = "currentUser" @@ -73,10 +71,7 @@ class ChooseAccountDialogFragment : lateinit var clientFactory: ClientFactory @Inject - lateinit var themeColorUtils: ThemeColorUtils - - @Inject - lateinit var themeDrawableUtils: ThemeDrawableUtils + lateinit var viewThemeUtils: ViewThemeUtils override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -90,9 +85,12 @@ class ChooseAccountDialogFragment : _binding = DialogChooseAccountBinding.inflate(layoutInflater) dialogView = binding.root - return MaterialAlertDialogBuilder(requireContext()) + val builder = MaterialAlertDialogBuilder(requireContext()) .setView(binding.root) - .create() + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) + + return builder.create() } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -117,10 +115,7 @@ class ChooseAccountDialogFragment : binding.currentAccount.account.text = user.accountName // Defining user right indicator - val icon = themeDrawableUtils.tintDrawable( - ContextCompat.getDrawable(requireContext(), R.drawable.ic_check_circle), - themeColorUtils.primaryColor(requireContext(), true) - ) + val icon = viewThemeUtils.platform.tintPrimaryDrawable(requireContext(), R.drawable.ic_check_circle) binding.currentAccount.accountMenu.setImageDrawable(icon) // Creating adapter for accounts list @@ -131,8 +126,8 @@ class ChooseAccountDialogFragment : this, false, false, - themeColorUtils, - themeDrawableUtils + true, + viewThemeUtils ) binding.accountsList.adapter = adapter @@ -164,6 +159,20 @@ class ChooseAccountDialogFragment : RetrieveStatusAsyncTask(user, this, clientFactory).execute() } + + themeViews() + } + + private fun themeViews() { + viewThemeUtils.platform.themeDialogDivider(binding.separatorLine) + viewThemeUtils.platform.themeDialog(binding.root) + + viewThemeUtils.material.colorMaterialTextButton(binding.setStatus) + viewThemeUtils.dialog.colorDialogMenuText(binding.setStatus) + viewThemeUtils.material.colorMaterialTextButton(binding.addAccount) + viewThemeUtils.dialog.colorDialogMenuText(binding.addAccount) + viewThemeUtils.material.colorMaterialTextButton(binding.manageAccounts) + viewThemeUtils.dialog.colorDialogMenuText(binding.manageAccounts) } private fun getAccountListItems(): List { diff --git a/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt b/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt index 8caa2d0da0..42fd49aab7 100644 --- a/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt @@ -24,6 +24,7 @@ import android.annotation.SuppressLint import android.app.Dialog import android.content.Context import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -31,10 +32,13 @@ import android.view.inputmethod.InputMethodManager import android.widget.AdapterView import android.widget.AdapterView.OnItemSelectedListener import android.widget.ArrayAdapter +import android.widget.ImageView +import android.widget.TextView import androidx.annotation.VisibleForTesting -import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.card.MaterialCardView +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.nextcloud.client.account.User @@ -53,9 +57,7 @@ import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.adapter.PredefinedStatusClickListener import com.owncloud.android.ui.adapter.PredefinedStatusListAdapter import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeTextInputUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import com.vanniktech.emoji.EmojiManager import com.vanniktech.emoji.EmojiPopup import com.vanniktech.emoji.google.GoogleEmojiProvider @@ -110,13 +112,7 @@ class SetStatusDialogFragment : lateinit var clientFactory: ClientFactory @Inject - lateinit var themeColorUtils: ThemeColorUtils - - @Inject - lateinit var themeButtonUtils: ThemeButtonUtils - - @Inject - lateinit var themeTextInputUtils: ThemeTextInputUtils + lateinit var viewThemeUtils: ViewThemeUtils override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -139,9 +135,11 @@ class SetStatusDialogFragment : override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = DialogSetStatusBinding.inflate(layoutInflater) - return AlertDialog.Builder(requireContext()) - .setView(binding.root) - .create() + val builder = MaterialAlertDialogBuilder(requireContext()).setView(binding.root) + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) + + return builder.create() } @SuppressLint("DefaultLocale") @@ -165,6 +163,11 @@ class SetStatusDialogFragment : binding.awayStatus.setOnClickListener { setStatus(StatusType.AWAY) } binding.invisibleStatus.setOnClickListener { setStatus(StatusType.INVISIBLE) } + viewThemeUtils.files.themeStatusCardView(binding.onlineStatus) + viewThemeUtils.files.themeStatusCardView(binding.dndStatus) + viewThemeUtils.files.themeStatusCardView(binding.awayStatus) + viewThemeUtils.files.themeStatusCardView(binding.invisibleStatus) + binding.clearStatus.setOnClickListener { clearStatus() } binding.setStatus.setOnClickListener { setStatusMessage() } binding.emoji.setOnClickListener { popup.show() } @@ -204,14 +207,11 @@ class SetStatusDialogFragment : } } - binding.clearStatus.setTextColor(themeColorUtils.primaryColor(context, true)) - themeButtonUtils.colorPrimaryButton(binding.setStatus, context, themeColorUtils) - themeTextInputUtils.colorTextInput( - binding.customStatusInputContainer, - binding.customStatusInput, - themeColorUtils.primaryColor(activity), - themeColorUtils.primaryAccentColor(activity) - ) + viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.clearStatus) + viewThemeUtils.material.colorMaterialButtonPrimaryTonal(binding.setStatus) + viewThemeUtils.material.colorTextInputLayout(binding.customStatusInputContainer) + + viewThemeUtils.platform.themeDialog(binding.root) } private fun updateCurrentStatusViews(it: Status) { @@ -318,34 +318,37 @@ class SetStatusDialogFragment : } private fun visualizeStatus(statusType: StatusType) { - when (statusType) { - StatusType.ONLINE -> { - clearTopStatus() - binding.onlineStatus.setBackgroundColor(themeColorUtils.primaryColor(context)) + clearTopStatus() + val views: Triple = when (statusType) { + StatusType.ONLINE -> Triple(binding.onlineStatus, binding.onlineHeadline, binding.onlineIcon) + StatusType.AWAY -> Triple(binding.awayStatus, binding.awayHeadline, binding.awayIcon) + StatusType.DND -> Triple(binding.dndStatus, binding.dndHeadline, binding.dndIcon) + StatusType.INVISIBLE -> Triple(binding.invisibleStatus, binding.invisibleHeadline, binding.invisibleIcon) + else -> { + Log.d(TAG, "unknown status") + return } - StatusType.AWAY -> { - clearTopStatus() - binding.awayStatus.setBackgroundColor(themeColorUtils.primaryColor(context)) - } - StatusType.DND -> { - clearTopStatus() - binding.dndStatus.setBackgroundColor(themeColorUtils.primaryColor(context)) - } - StatusType.INVISIBLE -> { - clearTopStatus() - binding.invisibleStatus.setBackgroundColor(themeColorUtils.primaryColor(context)) - } - else -> clearTopStatus() } + views.first.isChecked = true + viewThemeUtils.platform.colorOnSecondaryContainerTextViewElement(views.second) } private fun clearTopStatus() { context?.let { - val grey = it.resources.getColor(R.color.grey_200) - binding.onlineStatus.setBackgroundColor(grey) - binding.awayStatus.setBackgroundColor(grey) - binding.dndStatus.setBackgroundColor(grey) - binding.invisibleStatus.setBackgroundColor(grey) + binding.onlineHeadline.setTextColor(resources.getColor(R.color.high_emphasis_text)) + binding.awayHeadline.setTextColor(resources.getColor(R.color.high_emphasis_text)) + binding.dndHeadline.setTextColor(resources.getColor(R.color.high_emphasis_text)) + binding.invisibleHeadline.setTextColor(resources.getColor(R.color.high_emphasis_text)) + + binding.onlineIcon.imageTintList = null + binding.awayIcon.imageTintList = null + binding.dndIcon.imageTintList = null + binding.invisibleIcon.imageTintList = null + + binding.onlineStatus.isChecked = false + binding.awayStatus.isChecked = false + binding.dndStatus.isChecked = false + binding.invisibleStatus.isChecked = false } } @@ -384,6 +387,8 @@ class SetStatusDialogFragment : * Fragment creator */ companion object { + private val TAG = SetStatusDialogFragment::class.simpleName + @JvmStatic fun newInstance(user: User, status: Status?): SetStatusDialogFragment { val args = Bundle() @@ -391,7 +396,6 @@ class SetStatusDialogFragment : args.putParcelable(ARG_CURRENT_STATUS_PARAM, status) val dialogFragment = SetStatusDialogFragment() dialogFragment.arguments = args - dialogFragment.setStyle(STYLE_NORMAL, R.style.Theme_ownCloud_Dialog) return dialogFragment } } diff --git a/app/src/main/java/com/nextcloud/utils/view/FastScroll.kt b/app/src/main/java/com/nextcloud/utils/view/FastScrollUtils.kt similarity index 63% rename from app/src/main/java/com/nextcloud/utils/view/FastScroll.kt rename to app/src/main/java/com/nextcloud/utils/view/FastScrollUtils.kt index 1244de43e0..a92d461eca 100644 --- a/app/src/main/java/com/nextcloud/utils/view/FastScroll.kt +++ b/app/src/main/java/com/nextcloud/utils/view/FastScrollUtils.kt @@ -27,37 +27,26 @@ package com.nextcloud.utils.view -import android.content.Context -import android.graphics.drawable.Drawable import android.view.ViewGroup -import androidx.annotation.ColorInt -import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.RecyclerView import com.google.android.material.appbar.AppBarLayout -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import me.zhanghai.android.fastscroll.FastScroller import me.zhanghai.android.fastscroll.FastScrollerBuilder -import me.zhanghai.android.fastscroll.PopupStyles +import javax.inject.Inject -object FastScroll { - - @JvmStatic +class FastScrollUtils @Inject constructor(private val viewThemeUtils: ViewThemeUtils) { @JvmOverloads fun applyFastScroll( - context: Context, - themeColorUtils: ThemeColorUtils, - themeDrawableUtils: ThemeDrawableUtils, recyclerView: RecyclerView, viewHelper: FastScroller.ViewHelper? = null ) { - val primaryColor = themeColorUtils.primaryColor(context) - val builder = FastScrollerBuilder(recyclerView) - .useMd2Style() - .setThumbDrawable(getThumbDrawable(context, themeDrawableUtils, primaryColor)) - .setPopupStyle { - PopupStyles.MD2.accept(it) - it.background = FastScrollPopupBackground(context, primaryColor) + val builder = + FastScrollerBuilder(recyclerView).let { + viewThemeUtils.files.themeFastScrollerBuilder( + recyclerView.context, + it + ) } if (viewHelper != null) { builder.setViewHelper(viewHelper) @@ -65,22 +54,6 @@ object FastScroll { builder.build() } - private fun getThumbDrawable( - context: Context, - themeDrawableUtils: ThemeDrawableUtils, - @ColorInt color: Int - ): Drawable { - val thumbDrawable = - ResourcesCompat.getDrawable( - context.resources, - me.zhanghai.android.fastscroll.R.drawable.afs_md2_thumb, - null - ) - themeDrawableUtils.tintDrawable(thumbDrawable, color) - return thumbDrawable!! - } - - @JvmStatic fun fixAppBarForFastScroll(appBarLayout: AppBarLayout, content: ViewGroup) { val contentLayoutInitialPaddingBottom = content.paddingBottom appBarLayout.addOnOffsetChangedListener( diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index bdf9edff69..83e277768d 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -81,7 +81,7 @@ import com.owncloud.android.utils.FilesSyncHelper; import com.owncloud.android.utils.PermissionUtil; import com.owncloud.android.utils.ReceiversHelper; import com.owncloud.android.utils.SecurityUtils; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.conscrypt.Conscrypt; import org.greenrobot.eventbus.EventBus; @@ -97,6 +97,7 @@ import java.util.Locale; import java.util.Map; import javax.inject.Inject; +import javax.inject.Provider; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; @@ -177,7 +178,10 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { @Inject PassCodeManager passCodeManager; - @Inject ThemeSnackbarUtils themeSnackbarUtils; + // workaround because injection is initialized on onAttachBaseContext + // and getApplicationContext is null at that point, which crashes when getting current user + @Inject Provider viewThemeUtilsProvider; + private ViewThemeUtils viewThemeUtils; @SuppressWarnings("unused") private boolean mBound; @@ -274,6 +278,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { public void onCreate() { enableStrictMode(); + viewThemeUtils = viewThemeUtilsProvider.get(); + setAppTheme(preferences.getDarkThemeMode()); super.onCreate(); @@ -320,7 +326,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { powerManagementService, backgroundJobManager, clock, - themeSnackbarUtils); + viewThemeUtils); initContactsBackup(accountManager, backgroundJobManager); notificationChannels(); @@ -500,7 +506,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { final PowerManagementService powerManagementService, final BackgroundJobManager backgroundJobManager, final Clock clock, - final ThemeSnackbarUtils themeSnackbarUtils + final ViewThemeUtils viewThemeUtils ) { updateToAutoUpload(); cleanOldEntries(clock); @@ -508,7 +514,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { if (getAppContext() != null) { if (PermissionUtil.checkExternalStoragePermission(getAppContext())) { - splitOutAutoUploadEntries(clock, themeSnackbarUtils); + splitOutAutoUploadEntries(clock, viewThemeUtils); } else { preferences.setAutoUploadSplitEntriesEnabled(true); } @@ -731,7 +737,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { } private static void splitOutAutoUploadEntries(Clock clock, - ThemeSnackbarUtils themeSnackbarUtils) { + final ViewThemeUtils viewThemeUtils) { Context context = getAppContext(); AppPreferences preferences = AppPreferencesImpl.fromContext(context); if (!preferences.isAutoUploadSplitEntriesEnabled()) { @@ -746,12 +752,12 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { 1, null, true, - themeSnackbarUtils); + viewThemeUtils); final List videoMediaFolders = MediaProvider.getVideoFolders(contentResolver, 1, null, true, - themeSnackbarUtils); + viewThemeUtils); ArrayList idsToDelete = new ArrayList<>(); List syncedFolders = syncedFolderProvider.getSyncedFolders(); diff --git a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index fdaf368100..dc225655a6 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -75,6 +75,7 @@ import android.widget.Toast; import com.blikoon.qrcodescanner.QrCodeActivity; import com.google.android.material.snackbar.Snackbar; +import com.nextcloud.android.common.ui.color.ColorUtil; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.device.DeviceInfo; @@ -118,8 +119,8 @@ import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertL import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.PermissionUtil; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; +import com.owncloud.android.utils.theme.CapabilityUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.InputStream; import java.net.URLDecoder; @@ -233,8 +234,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Inject OnboardingService onboarding; @Inject DeviceInfo deviceInfo; @Inject PassCodeManager passCodeManager; - @Inject ThemeToolbarUtils themeToolbarUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; + @Inject ViewThemeUtils viewThemeUtils; + @Inject ColorUtil colorUtil; private boolean onlyAdd = false; @SuppressLint("ResourceAsColor") @ColorInt @@ -439,7 +440,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity accountSetupWebviewBinding.loginWebviewProgressBar.setVisibility(View.GONE); accountSetupWebviewBinding.loginWebview.setVisibility(View.VISIBLE); - themeToolbarUtils.colorStatusBar(AuthenticatorActivity.this, primaryColor); + viewThemeUtils.platform.colorStatusBar(AuthenticatorActivity.this, primaryColor); getWindow().setNavigationBarColor(primaryColor); } @@ -529,8 +530,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (deviceInfo.hasCamera(this)) { accountSetupBinding.scanQr.setOnClickListener(v -> onScan()); - themeDrawableUtils.tintDrawable(accountSetupBinding.scanQr.getDrawable(), - getResources().getColor(R.color.login_text_color)); + viewThemeUtils.platform.colorDrawable(accountSetupBinding.scanQr.getDrawable(), + getResources().getColor(R.color.login_text_color)); } else { accountSetupBinding.scanQr.setVisibility(View.GONE); } @@ -1131,6 +1132,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity if (success) { accountManager.setCurrentOwnCloudAccount(mAccount.name); + setupColorCapability(); if (onlyAdd) { finish(); } else { @@ -1190,6 +1192,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity } } + /** + * Caches a fake OCCapability with only the server color, so that it is immediately available for drawing the next + * screens + */ + private void setupColorCapability() { + final OCCapability colorCapability = new OCCapability(); + colorCapability.setServerColor(colorUtil.colorToHexString(primaryColor)); + colorCapability.setAccountName(mAccount.name); + CapabilityUtils.updateCapability(colorCapability); + } + /** * Updates the authentication token. *

diff --git a/app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.java b/app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.java index 050a4884d1..ecfd878d4e 100644 --- a/app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.java @@ -7,13 +7,8 @@ import android.widget.Toast; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeColorUtils; - -import javax.inject.Inject; public class DeepLinkLoginActivity extends AuthenticatorActivity implements Injectable { - @Inject - public ThemeColorUtils themeColorUtils; @Override protected void onCreate(Bundle savedInstanceState) { @@ -35,7 +30,6 @@ public class DeepLinkLoginActivity extends AuthenticatorActivity implements Inje LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, data.toString()); TextView loginText = findViewById(R.id.loginInfo); - loginText.setTextColor(themeColorUtils.fontColor(this)); loginText.setText(String.format("Login with %1$s to %2$s", loginUrlInfo.username, loginUrlInfo.serverAddress)); } catch (IllegalArgumentException e) { diff --git a/app/src/main/java/com/owncloud/android/datamodel/MediaProvider.java b/app/src/main/java/com/owncloud/android/datamodel/MediaProvider.java index ce59d72fca..6746273de4 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/MediaProvider.java +++ b/app/src/main/java/com/owncloud/android/datamodel/MediaProvider.java @@ -29,7 +29,7 @@ import android.provider.MediaStore; import com.owncloud.android.MainApp; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.utils.PermissionUtil; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.ArrayList; @@ -74,9 +74,9 @@ public final class MediaProvider { int itemLimit, @Nullable final AppCompatActivity activity, boolean getWithoutActivity, - ThemeSnackbarUtils themeSnackbarUtils) { + final ViewThemeUtils viewThemeUtils) { // check permissions - checkPermissions(activity, themeSnackbarUtils); + checkPermissions(activity, viewThemeUtils); // query media/image folders Cursor cursorFolders = null; @@ -174,10 +174,10 @@ public final class MediaProvider { } private static void checkPermissions(@Nullable AppCompatActivity activity, - ThemeSnackbarUtils themeSnackbarUtils) { + final ViewThemeUtils viewThemeUtils) { if (activity != null && !PermissionUtil.checkExternalStoragePermission(activity.getApplicationContext())) { - PermissionUtil.requestExternalStoragePermission(activity, themeSnackbarUtils, true); + PermissionUtil.requestExternalStoragePermission(activity, viewThemeUtils, true); } } @@ -185,9 +185,9 @@ public final class MediaProvider { int itemLimit, @Nullable final AppCompatActivity activity, boolean getWithoutActivity, - ThemeSnackbarUtils themeSnackbarUtils) { + final ViewThemeUtils viewThemeUtils) { // check permissions - checkPermissions(activity, themeSnackbarUtils); + checkPermissions(activity, viewThemeUtils); // query media/image folders Cursor cursorFolders = null; diff --git a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index b415af22ad..79562821ee 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -65,8 +65,7 @@ import com.owncloud.android.utils.BitmapUtils; import com.owncloud.android.utils.DisplayUtils.AvatarGenerationListener; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; @@ -757,18 +756,15 @@ public final class ThumbnailsCacheManager { private File mFile; private String mImageKey; private final Context mContext; - private final ThemeColorUtils themeColorUtils; - private final ThemeDrawableUtils themeDrawableUtils; + private final ViewThemeUtils viewThemeUtils; public MediaThumbnailGenerationTask(ImageView imageView, Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { // Use a WeakReference to ensure the ImageView can be garbage collected mImageViewReference = new WeakReference<>(imageView); mContext = context; - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -816,8 +812,7 @@ public final class ThumbnailsCacheManager { if (mFile != null) { if (mFile.isDirectory()) { imageView.setImageDrawable(MimeTypeUtil.getDefaultFolderIcon(mContext, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } else { if (MimeTypeUtil.isVideo(mFile)) { imageView.setImageBitmap(ThumbnailsCacheManager.mDefaultVideo); @@ -825,8 +820,7 @@ public final class ThumbnailsCacheManager { imageView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(null, mFile.getName(), mContext, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } } } diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java index 58de082eea..06fa844e19 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java @@ -36,9 +36,7 @@ import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.MainApp; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -60,7 +58,7 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { @Inject PowerManagementService powerManagementService; @Inject BackgroundJobManager backgroundJobManager; @Inject Clock clock; - @Inject ThemeSnackbarUtils themeSnackbarUtils; + @Inject ViewThemeUtils viewThemeUtils; /** * Receives broadcast intent reporting that the system was just boot up. * @@ -80,7 +78,7 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { powerManagementService, backgroundJobManager, clock, - themeSnackbarUtils); + viewThemeUtils); MainApp.initContactsBackup(accountManager, backgroundJobManager); } else { Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction()); diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index d4ea859c58..cbe4d37aea 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -68,7 +68,7 @@ import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.security.SecureRandom; @@ -127,7 +127,7 @@ public class FileDownloader extends Service @Inject UserAccountManager accountManager; @Inject UploadsStorageManager uploadsStorageManager; @Inject LocalBroadcastManager localBroadcastManager; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; public static String getDownloadAddedMessage() { return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE; @@ -152,12 +152,12 @@ public class FileDownloader extends Service mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileDownloaderBinder(); - NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setContentTitle( + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils).setContentTitle( getApplicationContext().getResources().getString(R.string.app_name)) .setContentText(getApplicationContext().getResources().getString(R.string.foreground_service_download)) .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(getApplicationContext(), true)); + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_DOWNLOAD); @@ -544,7 +544,7 @@ public class FileDownloader extends Service private void notifyDownloadStart(DownloadFileOperation download) { /// create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, themeColorUtils); + mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils); mNotificationBuilder .setSmallIcon(R.drawable.notification_icon) .setTicker(getString(R.string.downloader_download_in_progress_ticker)) diff --git a/app/src/main/java/com/owncloud/android/files/services/FileUploader.java b/app/src/main/java/com/owncloud/android/files/services/FileUploader.java index 41c93cf780..84b587686a 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileUploader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileUploader.java @@ -78,7 +78,7 @@ import com.owncloud.android.ui.activity.ConflictsResolveActivity; import com.owncloud.android.ui.activity.UploadListActivity; import com.owncloud.android.ui.notifications.NotificationUtils; import com.owncloud.android.utils.ErrorMessageAdapter; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.security.SecureRandom; @@ -201,7 +201,7 @@ public class FileUploader extends Service @Inject ConnectivityService connectivityService; @Inject PowerManagementService powerManagementService; @Inject LocalBroadcastManager localBroadcastManager; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; private IndexedForest mPendingUploads = new IndexedForest<>(); @@ -237,12 +237,11 @@ public class FileUploader extends Service mServiceHandler = new ServiceHandler(mServiceLooper, this); mBinder = new FileUploaderBinder(); - NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setContentTitle( - getApplicationContext().getResources().getString(R.string.app_name)) + NotificationCompat.Builder builder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils).setContentTitle( + getApplicationContext().getResources().getString(R.string.app_name)) .setContentText(getApplicationContext().getResources().getString(R.string.foreground_service_upload)) .setSmallIcon(R.drawable.notification_icon) - .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)) - .setColor(themeColorUtils.primaryColor(getApplicationContext(), true)); + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.notification_icon)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD); @@ -689,7 +688,7 @@ public class FileUploader extends Service private void notifyUploadStart(UploadFileOperation upload) { // / create status notification with a progress bar mLastPercent = 0; - mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, themeColorUtils); + mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils); mNotificationBuilder .setOngoing(true) .setSmallIcon(R.drawable.notification_icon) diff --git a/app/src/main/java/com/owncloud/android/media/MediaControlView.java b/app/src/main/java/com/owncloud/android/media/MediaControlView.java index d9c378d073..d3d01a3ed7 100644 --- a/app/src/main/java/com/owncloud/android/media/MediaControlView.java +++ b/app/src/main/java/com/owncloud/android/media/MediaControlView.java @@ -41,8 +41,7 @@ import android.widget.TextView; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.utils.theme.ThemeBarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.Formatter; import java.util.Locale; @@ -72,9 +71,7 @@ public class MediaControlView extends FrameLayout implements OnClickListener, On private ImageButton rewindButton; @Inject - ThemeColorUtils themeColorUtils; - @Inject - ThemeBarUtils themeBarUtils; + ViewThemeUtils viewThemeUtils; public MediaControlView(Context context, @@ -137,10 +134,10 @@ public class MediaControlView extends FrameLayout implements OnClickListener, On if (progressBar != null) { if (progressBar instanceof SeekBar) { SeekBar seeker = (SeekBar) progressBar; - themeBarUtils.colorHorizontalSeekBar(seeker, getContext(), themeColorUtils); + viewThemeUtils.platform.themeHorizontalSeekBar(seeker); seeker.setOnSeekBarChangeListener(this); } else { - themeBarUtils.colorHorizontalProgressBar(progressBar, themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.platform.themeHorizontalProgressBar(progressBar); } progressBar.setMax(1000); } diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index 09017fa330..83ab79867a 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -195,7 +195,7 @@ public class CreateFolderOperation extends SyncOperation implements OnRemoteOper return result; } catch (Exception e) { if (!EncryptionUtils.unlockFolder(parent, client, token).isSuccess()) { - throw new RuntimeException("Could not clean up after failing folder creation!"); + throw new RuntimeException("Could not clean up after failing folder creation!", e); } // remove folder diff --git a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java index bace44ab43..75e52cda75 100644 --- a/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -1081,7 +1081,7 @@ public class FileContentProvider extends ContentProvider { @VisibleForTesting public static void verifyColumns(@Nullable ContentValues contentValues) { - if (contentValues == null || contentValues.keySet().size() == 0) { + if (contentValues == null || contentValues.keySet().isEmpty()) { return; } diff --git a/app/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java b/app/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java index f995ee5d54..69917018f6 100644 --- a/app/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/app/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -48,7 +48,7 @@ import com.owncloud.android.operations.UpdateOCVersionOperation; import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity; import com.owncloud.android.ui.notifications.NotificationUtils; import com.owncloud.android.utils.DataHolderUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.apache.jackrabbit.webdav.DavException; @@ -122,7 +122,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { */ private SyncResult mSyncResult; - private final ThemeColorUtils themeColorUtils; + private final ViewThemeUtils viewThemeUtils; /** * Creates a {@link FileSyncAdapter} @@ -132,9 +132,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { public FileSyncAdapter(Context context, boolean autoInitialize, UserAccountManager userAccountManager, - ThemeColorUtils themeColorUtils) { + final ViewThemeUtils viewThemeUtils) { super(context, autoInitialize, userAccountManager); - this.themeColorUtils = themeColorUtils; + this.viewThemeUtils = viewThemeUtils; } /** @@ -146,9 +146,9 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { boolean autoInitialize, boolean allowParallelSyncs, UserAccountManager userAccountManager, - ThemeColorUtils themeColorUtils) { + final ViewThemeUtils viewThemeUtils) { super(context, autoInitialize, allowParallelSyncs, userAccountManager); - this.themeColorUtils = themeColorUtils; + this.viewThemeUtils = viewThemeUtils; } @@ -524,7 +524,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { private NotificationCompat.Builder createNotificationBuilder() { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getContext()); notificationBuilder.setSmallIcon(R.drawable.notification_icon).setAutoCancel(true); - notificationBuilder.setColor(themeColorUtils.primaryColor(getContext(), true)); + viewThemeUtils.androidx.themeNotificationCompatBuilder(getContext(), notificationBuilder); return notificationBuilder; } diff --git a/app/src/main/java/com/owncloud/android/syncadapter/FileSyncService.java b/app/src/main/java/com/owncloud/android/syncadapter/FileSyncService.java index e47d9d2387..c718320888 100644 --- a/app/src/main/java/com/owncloud/android/syncadapter/FileSyncService.java +++ b/app/src/main/java/com/owncloud/android/syncadapter/FileSyncService.java @@ -25,7 +25,7 @@ import android.content.Intent; import android.os.IBinder; import com.nextcloud.client.account.UserAccountManager; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -44,7 +44,7 @@ public class FileSyncService extends Service { private static final Object syncAdapterLock = new Object(); @Inject UserAccountManager userAccountManager; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; /* * {@inheritDoc} @@ -54,7 +54,7 @@ public class FileSyncService extends Service { AndroidInjection.inject(this); synchronized (syncAdapterLock) { if (syncAdapter == null) { - syncAdapter = new FileSyncAdapter(getApplicationContext(), true, userAccountManager, themeColorUtils); + syncAdapter = new FileSyncAdapter(getApplicationContext(), true, userAccountManager, viewThemeUtils); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.java b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.java index fd1a0a742e..788e409564 100644 --- a/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.java +++ b/app/src/main/java/com/owncloud/android/ui/AvatarGroupLayout.java @@ -38,9 +38,7 @@ import com.owncloud.android.R; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.shares.ShareeUser; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeAvatarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; @@ -86,9 +84,7 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av public void setAvatars(@NonNull User user, @NonNull List sharees, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils, - ThemeAvatarUtils themeAvatarUtils) { + final ViewThemeUtils viewThemeUtils) { @NonNull Context context = getContext(); removeAllViews(); RelativeLayout.LayoutParams avatarLayoutParams; @@ -114,7 +110,7 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av if (avatarCount == 0 && sharees.size() > MAX_AVATAR_COUNT) { avatar.setImageResource(R.drawable.ic_people); - themeDrawableUtils.setIconColor(avatar.getDrawable()); + viewThemeUtils.platform.tintTextDrawable(context, avatar.getDrawable()); } else { sharee = sharees.get(avatarCount); switch (sharee.getShareType()) { @@ -122,7 +118,7 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av case EMAIL: case ROOM: case CIRCLE: - themeAvatarUtils.createAvatar(sharee.getShareType(), avatar, context, themeColorUtils); + viewThemeUtils.files.createAvatar(sharee.getShareType(), avatar, context); break; case FEDERATED: showFederatedShareAvatar(context, @@ -130,7 +126,7 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av avatarRadius, resources, avatar, - themeDrawableUtils); + viewThemeUtils); break; default: avatar.setTag(sharee); @@ -159,7 +155,7 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av float avatarRadius, Resources resources, ImageView avatar, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { // maybe federated share String[] split = user.split("@"); String userId = split[0]; @@ -173,10 +169,10 @@ public class AvatarGroupLayout extends RelativeLayout implements DisplayUtils.Av placeholder = TextDrawable.createAvatarByUserId(userId, avatarRadius); } catch (Exception e) { Log_OC.e(TAG, "Error calculating RGB value for active account icon.", e); - placeholder = themeDrawableUtils.tintDrawable(ResourcesCompat.getDrawable(resources, - R.drawable.account_circle_white, - null), - R.color.black); + placeholder = viewThemeUtils.platform.colorDrawable(ResourcesCompat.getDrawable(resources, + R.drawable.account_circle_white, + null), + ContextCompat.getColor(context, R.color.black)); } avatar.setTag(null); diff --git a/app/src/main/java/com/owncloud/android/ui/EmptyRecyclerView.java b/app/src/main/java/com/owncloud/android/ui/EmptyRecyclerView.java index f77c9da404..4b90cae5aa 100644 --- a/app/src/main/java/com/owncloud/android/ui/EmptyRecyclerView.java +++ b/app/src/main/java/com/owncloud/android/ui/EmptyRecyclerView.java @@ -81,6 +81,24 @@ public class EmptyRecyclerView extends RecyclerView { initEmptyView(); } + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + super.onItemRangeChanged(positionStart, itemCount); + initEmptyView(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) { + super.onItemRangeChanged(positionStart, itemCount, payload); + initEmptyView(); + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + super.onItemRangeMoved(fromPosition, toPosition, itemCount); + initEmptyView(); + } + @Override public void onItemRangeInserted(int positionStart, int itemCount) { super.onItemRangeInserted(positionStart, itemCount); diff --git a/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java b/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java index 181d1bd087..8707cef2d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java +++ b/app/src/main/java/com/owncloud/android/ui/ThemeableSwitchPreference.java @@ -21,8 +21,6 @@ package com.owncloud.android.ui; import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; import android.preference.SwitchPreference; import android.util.AttributeSet; import android.view.View; @@ -30,21 +28,17 @@ import android.view.ViewGroup; import android.widget.Switch; import com.owncloud.android.MainApp; -import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; -import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.graphics.drawable.DrawableCompat; - /** * Themeable switch preference TODO Migrate to androidx */ public class ThemeableSwitchPreference extends SwitchPreference { @Inject - ThemeColorUtils themeColorUtils; + ViewThemeUtils viewThemeUtils; public ThemeableSwitchPreference(Context context) { super(context); @@ -71,37 +65,13 @@ public class ThemeableSwitchPreference extends SwitchPreference { } private void findSwitch(ViewGroup viewGroup) { - ColorStateList thumbColorStateList = null; - ColorStateList trackColorStateList = null; - for (int i = 0; i < viewGroup.getChildCount(); i++) { View child = viewGroup.getChildAt(i); if (child instanceof Switch) { Switch switchView = (Switch) child; - if(thumbColorStateList == null && trackColorStateList == null) { - int thumbColor = themeColorUtils.primaryAccentColor(getContext()); - if (themeColorUtils.darkTheme(getContext()) && - AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { - thumbColor = Color.WHITE; - } - int trackColor = Color.argb(77, Color.red(thumbColor), Color.green(thumbColor), Color.blue(thumbColor)); - int trackColorUnchecked = getContext().getResources().getColor(R.color.switch_track_color_unchecked); - thumbColorStateList = new ColorStateList( - new int[][]{new int[]{android.R.attr.state_checked}, new int[]{}}, - new int[]{thumbColor, getContext().getResources().getColor(R.color.switch_thumb_color_unchecked)}); - trackColorStateList = new ColorStateList( - new int[][]{new int[]{android.R.attr.state_checked}, - new int[]{}}, - new int[]{trackColor, trackColorUnchecked}); - } - - // setting the thumb color - DrawableCompat.setTintList(switchView.getThumbDrawable(), thumbColorStateList); - - // setting the track color - DrawableCompat.setTintList(switchView.getTrackDrawable(), trackColorStateList); + viewThemeUtils.platform.colorSwitch(switchView); break; } else if (child instanceof ViewGroup) { diff --git a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java index 8138de7d7b..c449c50855 100644 --- a/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activities/ActivitiesActivity.java @@ -41,6 +41,7 @@ import com.owncloud.android.ui.interfaces.ActivityListInterface; import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; @@ -70,6 +71,7 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn @Inject ActivitiesRepository activitiesRepository; @Inject FilesRepository filesRepository; @Inject ClientFactory clientFactory; + @Inject ViewThemeUtils viewThemeUtils; @Override protected void onCreate(Bundle savedInstanceState) { @@ -84,7 +86,7 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn // setup toolbar setupToolbar(); - themeLayoutUtils.colorSwipeRefreshLayout(this, binding.swipeContainingList); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList); // setup drawer setupDrawer(R.id.nav_activity); @@ -114,8 +116,7 @@ public class ActivitiesActivity extends DrawerActivity implements ActivityListIn this, clientFactory, false, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); binding.list.setAdapter(adapter); LinearLayoutManager layoutManager = new LinearLayoutManager(this); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/CommunityActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/CommunityActivity.java index 1851a190d1..05662f63b7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/CommunityActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/CommunityActivity.java @@ -64,7 +64,9 @@ public class CommunityActivity extends DrawerActivity { contributeForumView.setMovementMethod(LinkMovementMethod.getInstance()); contributeForumView.setText(Html.fromHtml(getString(R.string.community_contribute_forum_text) + " " + getString(R.string.community_contribute_forum_text_link, - themeColorUtils.primaryColorToHexString(this), + viewThemeUtils + .files + .primaryColorToHexString(this), getString(R.string.help_link), getString(R.string.community_contribute_forum_forum)))); @@ -72,7 +74,7 @@ public class CommunityActivity extends DrawerActivity { contributeTranslationView.setMovementMethod(LinkMovementMethod.getInstance()); contributeTranslationView.setText(Html.fromHtml( getString(R.string.community_contribute_translate_link, - themeColorUtils.primaryColorToHexString(this), + viewThemeUtils.files.primaryColorToHexString(this), getString(R.string.translation_link), getString(R.string.community_contribute_translate_translate)) + " " + getString(R.string.community_contribute_translate_text))); @@ -82,11 +84,11 @@ public class CommunityActivity extends DrawerActivity { contributeGithubView.setText(Html.fromHtml( getString(R.string.community_contribute_github_text, getString(R.string.community_contribute_github_text_link, - themeColorUtils.primaryColorToHexString(this), + viewThemeUtils.files.primaryColorToHexString(this), getString(R.string.contributing_link))))); MaterialButton reportButton = binding.communityTestingReport; - themeButtonUtils.colorPrimaryButton(reportButton, this, themeColorUtils); + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(reportButton); reportButton.setOnClickListener(v -> DisplayUtils.startLinkIntent(this, R.string.report_issue_empty_link)); binding.communityBetaFdroid.setOnClickListener( diff --git a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index 526ac55c05..39549d63df 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -54,7 +54,6 @@ import android.webkit.URLUtil; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ProgressBar; import android.widget.TextView; import com.bumptech.glide.GenericRequestBuilder; @@ -66,6 +65,7 @@ import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; import com.google.android.material.button.MaterialButton; import com.google.android.material.navigation.NavigationView; +import com.google.android.material.progressindicator.LinearProgressIndicator; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.network.ClientFactory; @@ -113,8 +113,6 @@ import com.owncloud.android.utils.svg.SVGorImage; import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder; import com.owncloud.android.utils.svg.SvgOrImageDecoder; import com.owncloud.android.utils.theme.CapabilityUtils; -import com.owncloud.android.utils.theme.ThemeBarUtils; -import com.owncloud.android.utils.theme.ThemeMenuUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -149,6 +147,7 @@ public abstract class DrawerActivity extends ToolbarActivity private static final int MENU_ORDER_EXTERNAL_LINKS = 3; private static final int MENU_ITEM_EXTERNAL_LINK = 111; private static final int MAX_LOGO_SIZE_PX = 1000; + private static final int RELATIVE_THRESHOLD_WARNING = 80; /** * Reference to the drawer layout. @@ -188,7 +187,7 @@ public abstract class DrawerActivity extends ToolbarActivity /** * progress bar of the quota view. */ - private ProgressBar mQuotaProgressBar; + private LinearProgressIndicator mQuotaProgressBar; /** * text view of the quota view. @@ -210,12 +209,6 @@ public abstract class DrawerActivity extends ToolbarActivity @Inject ClientFactory clientFactory; - @Inject - ThemeMenuUtils themeMenuUtils; - - @Inject - ThemeBarUtils themeBarUtils; - /** * Initializes the drawer, its content and highlights the menu item with the given id. This method needs to be * called after the content view has been set. @@ -287,9 +280,8 @@ public abstract class DrawerActivity extends ToolbarActivity Drawable backArrow = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_arrow_back, null); - mDrawerToggle.setHomeAsUpIndicator( - themeDrawableUtils.tintDrawable(backArrow, themeColorUtils.appBarPrimaryFontColor(this))); - mDrawerToggle.getDrawerArrowDrawable().setColor(themeColorUtils.appBarPrimaryFontColor(this)); + + viewThemeUtils.platform.tintToolbarArrowDrawable(this, mDrawerToggle, backArrow); } /** @@ -297,10 +289,10 @@ public abstract class DrawerActivity extends ToolbarActivity */ private void setupQuotaElement() { mQuotaView = (LinearLayout) findQuotaViewById(R.id.drawer_quota); - mQuotaProgressBar = (ProgressBar) findQuotaViewById(R.id.drawer_quota_ProgressBar); + mQuotaProgressBar = (LinearProgressIndicator) findQuotaViewById(R.id.drawer_quota_ProgressBar); mQuotaTextPercentage = (TextView) findQuotaViewById(R.id.drawer_quota_percentage); mQuotaTextLink = (TextView) findQuotaViewById(R.id.drawer_quota_link); - themeBarUtils.colorProgressBar(mQuotaProgressBar, themeColorUtils.primaryColor(this)); + viewThemeUtils.material.colorProgressBar(mQuotaProgressBar); } public void updateHeader() { @@ -309,11 +301,11 @@ public abstract class DrawerActivity extends ToolbarActivity OCCapability capability = getCapabilities(); String logo = capability.getServerLogo(); - int primaryColor = themeColorUtils.primaryColor(getAccount(), false, this); + int primaryColor = themeColorUtils.unchangedPrimaryColor(getAccount(), this); // set background to primary color LinearLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view); - drawerHeader.setBackgroundColor(themeColorUtils.unchangedPrimaryColor(getAccount(), this)); + drawerHeader.setBackgroundColor(primaryColor); if (!TextUtils.isEmpty(logo) && URLUtil.isValidUrl(logo)) { // background image @@ -379,13 +371,6 @@ public abstract class DrawerActivity extends ToolbarActivity } - /** - * setup drawer header, basically the logo color - */ - private void setupDrawerHeader(FrameLayout drawerHeader) { - drawerHeader.setBackgroundColor(themeColorUtils.primaryColor(getAccount(), true, this)); - } - /** * setup drawer content, basically setting the item selected listener. * @@ -702,9 +687,12 @@ public abstract class DrawerActivity extends ToolbarActivity mQuotaProgressBar.setProgress(relative); - themeBarUtils.colorProgressBar(mQuotaProgressBar, DisplayUtils.getRelativeInfoColor(this, - relative, - themeColorUtils)); + if (relative < RELATIVE_THRESHOLD_WARNING) { + viewThemeUtils.material.colorProgressBar(mQuotaProgressBar); + } else { + viewThemeUtils.material.colorProgressBar(mQuotaProgressBar, + getResources().getColor(R.color.infolevel_warning)); + } updateQuotaLink(); showQuota(true); @@ -769,9 +757,7 @@ public abstract class DrawerActivity extends ToolbarActivity this, firstQuota.getIconUrl(), target, - R.drawable.ic_link, - size, - size); + R.drawable.ic_link); } else { mQuotaTextLink.setVisibility(View.GONE); @@ -789,26 +775,9 @@ public abstract class DrawerActivity extends ToolbarActivity */ protected void setDrawerMenuItemChecked(int menuItemId) { if (mNavigationView != null && mNavigationView.getMenu().findItem(menuItemId) != null) { + viewThemeUtils.platform.colorNavigationView(mNavigationView); mCheckedMenuItem = menuItemId; - MenuItem currentItem = mNavigationView.getMenu().findItem(menuItemId); - int drawerColor = getResources().getColor(R.color.drawer_text_color); - int activeColor = themeColorUtils.primaryColor(null, true, true, this); - - currentItem.setChecked(true); - - // For each menu item, change the color of the selected item, and of the other items - for (int i = 0; i < mNavigationView.getMenu().size(); i++) { - MenuItem menuItem = mNavigationView.getMenu().getItem(i); - if (menuItem.getIcon() != null) { - if (menuItem == currentItem) { - themeDrawableUtils.tintDrawable(currentItem.getIcon(), activeColor); - themeMenuUtils.tintMenuItemText(currentItem, activeColor); - } else { - themeDrawableUtils.tintDrawable(menuItem.getIcon(), drawerColor); - themeMenuUtils.tintMenuItemText(menuItem, drawerColor); - } - } - } + mNavigationView.getMenu().findItem(menuItemId).setChecked(true); } else { Log_OC.w(TAG, "setDrawerMenuItemChecked has been called with invalid menu-item-ID"); } @@ -884,8 +853,6 @@ public abstract class DrawerActivity extends ToolbarActivity if (mNavigationView != null && getBaseContext().getResources().getBoolean(R.bool.show_external_links)) { mNavigationView.getMenu().removeGroup(R.id.drawer_menu_external_links); - float density = getResources().getDisplayMetrics().density; - final int size = Math.round(24 * density); int greyColor = ContextCompat.getColor(this, R.color.drawer_menu_icon); for (final ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.LINK)) { @@ -911,9 +878,7 @@ public abstract class DrawerActivity extends ToolbarActivity this, link.getIconUrl(), target, - R.drawable.ic_link, - size, - size); + R.drawable.ic_link); } setDrawerMenuItemChecked(mCheckedMenuItem); @@ -925,7 +890,7 @@ public abstract class DrawerActivity extends ToolbarActivity if (menuItem != null) { if (drawable != null) { - menuItem.setIcon(themeDrawableUtils.tintDrawable(drawable, greyColor)); + menuItem.setIcon(viewThemeUtils.platform.colorDrawable(drawable, greyColor)); } else { menuItem.setIcon(R.drawable.ic_link); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java index 9321dfc40b..1c24457b82 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java @@ -78,7 +78,7 @@ public abstract class EditorWebView extends ExternalSiteWebView { R.string.timeout_richDocuments, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.common_back, v -> closeView()); - themeSnackbarUtils.colorSnackbar(getApplicationContext(), snackbar); + viewThemeUtils.material.themeSnackbar(snackbar); setLoadingSnackbar(snackbar); snackbar.show(); } @@ -159,8 +159,7 @@ public abstract class EditorWebView extends ExternalSiteWebView { file.isGroupFolder(), file.getMountType(), this, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } else { if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) { // Thumbnail in cache? @@ -182,10 +181,8 @@ public abstract class EditorWebView extends ExternalSiteWebView { } else { Drawable icon = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), - user, getApplicationContext(), - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); binding.thumbnail.setImageDrawable(icon); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java b/app/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java index 03736ce9f5..9267245d9f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java @@ -202,7 +202,7 @@ public class ExternalSiteWebView extends FileActivity { private void setupActionBar(String title) { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { - themeToolbarUtils.setColoredTitle(actionBar, title, this); + viewThemeUtils.files.themeActionBar(this, actionBar, title); if (showSidebar) { actionBar.setDisplayHomeAsUpEnabled(true); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java index b10033f48a..cddf45cd94 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java @@ -89,11 +89,12 @@ import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.FileDetailSharingFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.ui.helpers.FileOperationsHelper; +import com.owncloud.android.ui.preview.PreviewImageActivity; import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.FilesSyncHelper; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -103,6 +104,7 @@ import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; +import androidx.appcompat.app.ActionBar; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; @@ -172,9 +174,6 @@ public abstract class FileActivity extends DrawerActivity @Inject BackgroundJobManager backgroundJobManager; - @Inject - ThemeSnackbarUtils themeSnackbarUtils; - @Override public void showFiles(boolean onDeviceOnly) { // must be specialized in subclasses @@ -205,9 +204,10 @@ public abstract class FileActivity extends DrawerActivity mFileOperationsHelper.setOpIdWaitingFor( savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE) ); - themeToolbarUtils.setColoredTitle(getSupportActionBar(), - savedInstanceState.getString(KEY_ACTION_BAR_TITLE), - this); + final ActionBar actionBar = getSupportActionBar(); + if (actionBar != null && !(this instanceof PreviewImageActivity)) { + viewThemeUtils.files.themeActionBar(this, actionBar, savedInstanceState.getString(KEY_ACTION_BAR_TITLE)); + } } else { User user = getIntent().getParcelableExtra(FileActivity.EXTRA_USER); mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE); @@ -700,12 +700,12 @@ public abstract class FileActivity extends DrawerActivity public static void copyAndShareFileLink(FileActivity activity, OCFile file, String link, - ThemeSnackbarUtils themeSnackbarUtils) { + final ViewThemeUtils viewThemeUtils) { ClipboardUtil.copyToClipboard(activity, link, false); Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), R.string.clipboard_text_copied, Snackbar.LENGTH_LONG) .setAction(R.string.share, v -> showShareLinkDialog(activity, file, link)); - themeSnackbarUtils.colorSnackbar(activity, snackbar); + viewThemeUtils.material.themeSnackbar(snackbar); snackbar.show(); } @@ -774,7 +774,7 @@ public abstract class FileActivity extends DrawerActivity snackbar = Snackbar.make(sharingFragment.getView(), result.getMessage(), Snackbar.LENGTH_LONG); } - themeSnackbarUtils.colorSnackbar(this, snackbar); + viewThemeUtils.material.themeSnackbar(snackbar); snackbar.show(); } } @@ -800,7 +800,7 @@ public abstract class FileActivity extends DrawerActivity } } - copyAndShareFileLink(this, file, link, themeSnackbarUtils); + copyAndShareFileLink(this, file, link, viewThemeUtils); if (sharingFragment != null) { sharingFragment.onUpdateShareInformation(result, file); @@ -834,7 +834,7 @@ public abstract class FileActivity extends DrawerActivity operation, getResources()), Snackbar.LENGTH_LONG); - themeSnackbarUtils.colorSnackbar(this, snackbar); + viewThemeUtils.material.themeSnackbar(snackbar); snackbar.show(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 5dcca733aa..de8c6ef6ef 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -65,7 +65,7 @@ import com.nextcloud.client.network.ConnectivityService; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.java.util.Optional; -import com.nextcloud.utils.view.FastScroll; +import com.nextcloud.utils.view.FastScrollUtils; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.FilesBinding; @@ -231,6 +231,9 @@ public class FileDisplayActivity extends FileActivity @Inject ConnectivityService connectivityService; + @Inject + FastScrollUtils fastScrollUtils; + public static Intent openFileIntent(Context context, User user, OCFile file) { final Intent intent = new Intent(context, PreviewImageActivity.class); intent.putExtra(FileActivity.EXTRA_FILE, file); @@ -272,7 +275,7 @@ public class FileDisplayActivity extends FileActivity mSwitchAccountButton.setOnClickListener(v -> showManageAccountsDialog()); - FastScroll.fixAppBarForFastScroll(binding.appbar.appbar, binding.rootLayout); + fastScrollUtils.fixAppBarForFastScroll(binding.appbar.appbar, binding.rootLayout); // Init Fragment without UI to retain AsyncTask across configuration changes @@ -314,8 +317,7 @@ public class FileDisplayActivity extends FileActivity .create(); alertDialog.show(); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); } catch (WindowManager.BadTokenException e) { Log_OC.e(TAG, "Error showing wrong storage info, so skipping it: " + e.getMessage()); } @@ -333,7 +335,7 @@ public class FileDisplayActivity extends FileActivity if (dialog != null && dialog.isShowing()) { dialog.dismiss(); getSupportFragmentManager().beginTransaction().remove(fragment).commitNowAllowingStateLoss(); - PermissionUtil.requestExternalStoragePermission(this, themeSnackbarUtils); + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils); } } } @@ -343,7 +345,7 @@ public class FileDisplayActivity extends FileActivity super.onPostCreate(savedInstanceState); - PermissionUtil.requestExternalStoragePermission(this, themeSnackbarUtils); + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils); if (getIntent().getParcelableExtra(OCFileListFragment.SEARCH_EVENT) != null) { switchToSearchFragment(savedInstanceState); @@ -686,7 +688,7 @@ public class FileDisplayActivity extends FileActivity searchView.setIconified(false); }); - themeToolbarUtils.themeSearchView(searchView, this); + viewThemeUtils.androidx.themeToolbarSearchView(searchView); // populate list of menu items to show/hide when drawer is opened/closed mDrawerMenuItemstoShowHideList = new ArrayList<>(1); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt index 088121c731..56f2e9458e 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/FolderPickerActivity.kt @@ -342,8 +342,8 @@ open class FolderPickerActivity : val atRoot = currentDir == null || currentDir.parentId == 0L actionBar.setDisplayHomeAsUpEnabled(!atRoot) actionBar.setHomeButtonEnabled(!atRoot) - themeToolbarUtils.tintBackButton(actionBar, this) - themeToolbarUtils.setColoredTitle(supportActionBar, if (atRoot) caption else currentDir!!.fileName, this) + val title = if (atRoot) caption ?: "" else currentDir!!.fileName + viewThemeUtils.files.themeActionBar(this, actionBar, title) } } @@ -354,14 +354,14 @@ open class FolderPickerActivity : mCancelBtn = findViewById(R.id.folder_picker_btn_cancel) mChooseBtn = findViewById(R.id.folder_picker_btn_choose) if (mChooseBtn != null) { - themeButtonUtils.colorPrimaryButton(mChooseBtn, this, themeColorUtils) + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(mChooseBtn!!) mChooseBtn!!.setOnClickListener(this) } if (mCancelBtn != null) { if (this is FilePickerActivity) { - themeButtonUtils.colorPrimaryButton(mCancelBtn, this, themeColorUtils) + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(mCancelBtn!!) } else { - mCancelBtn!!.setTextColor(themeColorUtils.primaryColor(this, true)) + viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(mCancelBtn!!) } mCancelBtn!!.setOnClickListener(this) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 63b110baa5..f4679bec50 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -131,12 +131,9 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowHomeEnabled(true); + viewThemeUtils.files.themeActionBar(this, actionBar, R.string.prefs_manage_accounts); } - // set title Action bar - updateActionBarTitleAndHomeButtonByString(getResources().getString(R.string.prefs_manage_accounts)); - themeToolbarUtils.tintBackButton(actionBar, this); - List users = accountManager.getAllUsers(); originalUsers = toAccountNames(users); @@ -155,8 +152,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap this, multipleAccountsSupported, true, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); recyclerView.setAdapter(userListAdapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); @@ -310,8 +307,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap this, multipleAccountsSupported, false, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); recyclerView.setAdapter(userListAdapter); runOnUiThread(() -> userListAdapter.notifyDataSetChanged()); } catch (OperationCanceledException e) { @@ -364,8 +361,8 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap this, multipleAccountsSupported, false, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); recyclerView.setAdapter(userListAdapter); } else { onBackPressed(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java index 1c626494dd..97c0d8dc78 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/NotificationsActivity.java @@ -85,7 +85,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio // use account from intent (opened via android notification can have a different account than current one) if (getIntent() != null && getIntent().getExtras() != null) { String accountName = getIntent().getExtras().getString(NotificationWork.KEY_NOTIFICATION_ACCOUNT); - if(accountName != null && optionalUser.isPresent()) { + if (accountName != null && optionalUser.isPresent()) { User user = optionalUser.get(); if (user.getAccountName().equalsIgnoreCase(accountName)) { accountManager.setCurrentOwnCloudAccount(accountName); @@ -100,8 +100,8 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio updateActionBarTitleAndHomeButtonByString(getString(R.string.drawer_item_notifications)); - themeLayoutUtils.colorSwipeRefreshLayout(this, binding.swipeContainingList); - themeLayoutUtils.colorSwipeRefreshLayout(this, binding.swipeContainingEmpty); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingEmpty); // setup drawer setupDrawer(R.id.nav_notifications); @@ -109,8 +109,8 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio if (!optionalUser.isPresent()) { // show error runOnUiThread(() -> setEmptyContent( - getString(R.string.notifications_no_results_headline), - getString(R.string.account_not_found)) + getString(R.string.notifications_no_results_headline), + getString(R.string.account_not_found)) ); return; } @@ -149,7 +149,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio final ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContentResolver()); final String accountName = optionalUser.isPresent() ? optionalUser.get().getAccountName() : ""; final boolean usesOldLogin = arbitraryDataProvider.getBooleanValue(accountName, - UserAccountManager.ACCOUNT_USES_STANDARD_PASSWORD); + UserAccountManager.ACCOUNT_USES_STANDARD_PASSWORD); if (usesOldLogin) { snackbar = Snackbar.make(binding.emptyList.emptyListView, @@ -258,7 +258,7 @@ public class NotificationsActivity extends DrawerActivity implements Notificatio private void initializeAdapter() { initializeClient(); if (adapter == null) { - adapter = new NotificationListAdapter(client, this, themeColorUtils, themeButtonUtils); + adapter = new NotificationListAdapter(client, this, viewThemeUtils); binding.list.setAdapter(adapter); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java index 555a5061da..3fe049ef39 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/PassCodeActivity.java @@ -42,9 +42,7 @@ import com.owncloud.android.R; import com.owncloud.android.authentication.PassCodeManager; import com.owncloud.android.databinding.PasscodelockBinding; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.Arrays; @@ -63,7 +61,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { public final static String ACTION_REQUEST_WITH_RESULT = "ACTION_REQUEST_WITH_RESULT"; public final static String ACTION_CHECK_WITH_RESULT = "ACTION_CHECK_WITH_RESULT"; public final static String ACTION_CHECK = "ACTION_CHECK"; - public final static String KEY_PASSCODE = "KEY_PASSCODE"; + public final static String KEY_PASSCODE = "KEY_PASSCODE"; public final static String KEY_CHECK_RESULT = "KEY_CHECK_RESULT"; public final static String PREFERENCE_PASSCODE_D = "PrefPinCode"; @@ -74,9 +72,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { @Inject AppPreferences preferences; @Inject PassCodeManager passCodeManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; private PasscodelockBinding binding; private final EditText[] passCodeEditTexts = new EditText[4]; private String[] passCodeDigits = {"", "", "", ""}; @@ -85,37 +81,30 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** * Initializes the activity. + *

+ * An intent with a valid ACTION is expected; if none is found, an {@link IllegalArgumentException} will be thrown. * - * An intent with a valid ACTION is expected; if none is found, an - * {@link IllegalArgumentException} will be thrown. - * - * @param savedInstanceState Previously saved state - irrelevant in this case + * @param savedInstanceState Previously saved state - irrelevant in this case */ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = PasscodelockBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - int elementColor = themeColorUtils.primaryColor(this, true); - themeButtonUtils.themeBorderlessButton(themeColorUtils.primaryColor(this, true), binding.cancel); + viewThemeUtils.platform.colorTextButtons(binding.cancel); passCodeEditTexts[0] = binding.txt0; - themeTextInputUtils.colorEditText(passCodeEditTexts[0], elementColor); - themeTextInputUtils.themeEditText(this, passCodeEditTexts[0], false, themeColorUtils); + passCodeEditTexts[1] = binding.txt1; + passCodeEditTexts[2] = binding.txt2; + passCodeEditTexts[3] = binding.txt3; + + for (EditText passCodeEditText : passCodeEditTexts) { + viewThemeUtils.platform.colorEditText(passCodeEditText); + } + passCodeEditTexts[0].requestFocus(); - passCodeEditTexts[1] = binding.txt1; - themeTextInputUtils.colorEditText(passCodeEditTexts[1], elementColor); - themeTextInputUtils.themeEditText(this, passCodeEditTexts[1], false, themeColorUtils); - - passCodeEditTexts[2] = binding.txt2; - themeTextInputUtils.colorEditText(passCodeEditTexts[2], elementColor); - themeTextInputUtils.themeEditText(this, passCodeEditTexts[2], false, themeColorUtils); - - passCodeEditTexts[3] = binding.txt3; - themeTextInputUtils.colorEditText(passCodeEditTexts[3], elementColor); - themeTextInputUtils.themeEditText(this, passCodeEditTexts[3], false, themeColorUtils); Window window = getWindow(); if (window != null) { @@ -135,10 +124,10 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { confirmingPassCode = savedInstanceState.getBoolean(PassCodeActivity.KEY_CONFIRMING_PASSCODE); passCodeDigits = savedInstanceState.getStringArray(PassCodeActivity.KEY_PASSCODE_DIGITS); } - if(confirmingPassCode){ + if (confirmingPassCode) { // the app was in the passcodeconfirmation requestPassCodeConfirmation(); - }else{ + } else { // pass code preference has just been activated in SettingsActivity; // will receive and confirm pass code value binding.header.setText(R.string.pass_code_configure_your_pass_code); @@ -162,13 +151,12 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { } /** - * Enables or disables the cancel button to allow the user interrupt the ACTION - * requested to the activity. + * Enables or disables the cancel button to allow the user interrupt the ACTION requested to the activity. * - * @param enabled 'True' makes the cancel button available, 'false' hides it. + * @param enabled 'True' makes the cancel button available, 'false' hides it. */ - protected void setCancelButtonEnabled(boolean enabled){ - if(enabled){ + protected void setCancelButtonEnabled(boolean enabled) { + if (enabled) { binding.cancel.setVisibility(View.VISIBLE); binding.cancel.setOnClickListener(new OnClickListener() { @Override @@ -235,9 +223,9 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** * Processes the pass code entered by the user just after the last digit was in. - * - * Takes into account the action requested to the activity, the currently saved pass code and - * the previously typed pass code, if any. + *

+ * Takes into account the action requested to the activity, the currently saved pass code and the previously typed + * pass code, if any. */ private void processFullPassCode() { if (ACTION_CHECK.equals(getIntent().getAction())) { @@ -249,7 +237,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { hideSoftKeyboard(); finish(); - } else { + } else { preferences.increasePinWrongAttempts(); showErrorAndRestart(R.string.pass_code_wrong, R.string.pass_code_enter_pass_code, View.INVISIBLE); @@ -278,8 +266,8 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { } else { showErrorAndRestart( - R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE - ); + R.string.pass_code_mismatch, R.string.pass_code_configure_your_pass_code, View.VISIBLE + ); } } } @@ -292,7 +280,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { inputMethodManager.hideSoftInputFromWindow( focusedView.getWindowToken(), 0 - ); + ); } } @@ -309,10 +297,9 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** - * Ask to the user for retyping the pass code just entered before saving it as the current pass - * code. + * Ask to the user for retyping the pass code just entered before saving it as the current pass code. */ - protected void requestPassCodeConfirmation(){ + protected void requestPassCodeConfirmation() { clearBoxes(); binding.header.setText(R.string.pass_code_reenter_your_pass_code); binding.explanation.setVisibility(View.INVISIBLE); @@ -322,7 +309,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** * Compares pass code entered by the user with the value currently saved in the app. * - * @return 'True' if entered pass code equals to the saved one. + * @return 'True' if entered pass code equals to the saved one. */ protected boolean checkPassCode() { @@ -337,12 +324,11 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { } /** - * Compares pass code retyped by the user in the input fields with the value entered just - * before. + * Compares pass code retyped by the user in the input fields with the value entered just before. * - * @return 'True' if retyped pass code equals to the entered before. + * @return 'True' if retyped pass code equals to the entered before. */ - protected boolean confirmPassCode(){ + protected boolean confirmPassCode() { confirmingPassCode = false; boolean result = true; @@ -355,7 +341,7 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** * Sets the input fields to empty strings and puts the focus on the first one. */ - protected void clearBoxes(){ + protected void clearBoxes() { for (EditText mPassCodeEditText : passCodeEditTexts) { mPassCodeEditText.setText(""); } @@ -363,12 +349,12 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { } /** - * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while - * preventing than ACTION_CHECK may be worked around. + * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while preventing than + * ACTION_CHECK may be worked around. * - * @param keyCode Key code of the key that triggered the down event. - * @param event Event triggered. - * @return 'True' when the key event was processed by this method. + * @param keyCode Key code of the key that triggered the down event. + * @param event Event triggered. + * @return 'True' when the key event was processed by this method. */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -448,18 +434,16 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { /** * Constructor * - * @param index Position in the pass code of the input field that will be bound to - * this watcher. - * @param lastOne 'True' means that watcher corresponds to the last position of the - * pass code. + * @param index Position in the pass code of the input field that will be bound to this watcher. + * @param lastOne 'True' means that watcher corresponds to the last position of the pass code. */ PassCodeDigitTextWatcher(int index, boolean lastOne) { mIndex = index; - mLastOne = lastOne; + mLastOne = lastOne; if (mIndex < 0) { throw new IllegalArgumentException( - "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + - " constructor" + "Invalid index in " + PassCodeDigitTextWatcher.class.getSimpleName() + + " constructor" ); } } @@ -469,13 +453,11 @@ public class PassCodeActivity extends AppCompatActivity implements Injectable { } /** - * Performs several actions when the user types a digit in an input field: - * - saves the input digit to the state of the activity; this will allow retyping the - * pass code to confirm it. - * - moves the focus automatically to the next field - * - for the last field, triggers the processing of the full pass code + * Performs several actions when the user types a digit in an input field: - saves the input digit to the state + * of the activity; this will allow retyping the pass code to confirm it. - moves the focus automatically to the + * next field - for the last field, triggers the processing of the full pass code * - * @param s Changed text + * @param s Changed text */ @Override public void afterTextChanged(Editable s) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 7cf07a8137..a24572d606 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -52,7 +52,6 @@ import android.view.WindowManager.LayoutParams; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; -import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.Spinner; @@ -62,6 +61,7 @@ import android.widget.Toast; import com.google.android.material.button.MaterialButton; import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; +import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.MainApp; @@ -80,6 +80,7 @@ import com.owncloud.android.operations.UploadFileOperation; import com.owncloud.android.syncadapter.FileSyncAdapter; import com.owncloud.android.ui.adapter.UploaderAdapter; import com.owncloud.android.ui.asynctasks.CopyAndUploadContentUrisTask; +import com.owncloud.android.ui.dialog.AccountChooserInterface; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; import com.owncloud.android.ui.dialog.MultipleAccountsDialog; @@ -91,8 +92,7 @@ import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ErrorMessageAdapter; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.MimeType; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.io.FileWriter; @@ -120,7 +120,6 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.widget.SearchView; import androidx.core.view.MenuItemCompat; -import androidx.core.widget.NestedScrollView; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -131,8 +130,8 @@ import static com.owncloud.android.utils.DisplayUtils.openSortingOrderDialogFrag * This can be used to upload things to an ownCloud instance. */ public class ReceiveExternalFilesActivity extends FileActivity - implements OnItemClickListener, View.OnClickListener, CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener, - SortingOrderDialogFragment.OnSortingOrderListener, Injectable { + implements OnItemClickListener, View.OnClickListener, CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener, + SortingOrderDialogFragment.OnSortingOrderListener, Injectable, AccountChooserInterface { private static final String TAG = ReceiveExternalFilesActivity.class.getSimpleName(); @@ -201,11 +200,11 @@ public class ReceiveExternalFilesActivity extends FileActivity // Init Fragment without UI to retain AsyncTask across configuration changes FragmentManager fm = getSupportFragmentManager(); TaskRetainerFragment taskRetainerFragment = - (TaskRetainerFragment) fm.findFragmentByTag(TaskRetainerFragment.FTAG_TASK_RETAINER_FRAGMENT); + (TaskRetainerFragment) fm.findFragmentByTag(TaskRetainerFragment.FTAG_TASK_RETAINER_FRAGMENT); if (taskRetainerFragment == null) { taskRetainerFragment = new TaskRetainerFragment(); fm.beginTransaction() - .add(taskRetainerFragment, TaskRetainerFragment.FTAG_TASK_RETAINER_FRAGMENT).commit(); + .add(taskRetainerFragment, TaskRetainerFragment.FTAG_TASK_RETAINER_FRAGMENT).commit(); } // else, Fragment already created and retained across configuration change } @@ -220,9 +219,9 @@ public class ReceiveExternalFilesActivity extends FileActivity if (!somethingToUpload()) { showErrorDialog( - R.string.uploader_error_message_no_file_to_upload, - R.string.uploader_error_title_no_file_to_upload - ); + R.string.uploader_error_message_no_file_to_upload, + R.string.uploader_error_title_no_file_to_upload + ); } super.setAccount(account, savedAccount); @@ -237,8 +236,9 @@ public class ReceiveExternalFilesActivity extends FileActivity return this; } - public void changeAccount(Account account) { - setAccount(account, false); + @Override + public void onAccountChosen(@NonNull User user) { + setAccount(user.toPlatformAccount(), false); initTargetFolder(); populateDirectoryList(); } @@ -295,7 +295,7 @@ public class ReceiveExternalFilesActivity extends FileActivity builder.setIcon(R.drawable.ic_warning); builder.setTitle(R.string.uploader_wrn_no_account_title); builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), - getString(R.string.app_name))); + getString(R.string.app_name))); builder.setCancelable(false); builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, (dialog, which) -> { // using string value since in API7 this @@ -308,7 +308,7 @@ public class ReceiveExternalFilesActivity extends FileActivity startActivityForResult(intent, REQUEST_CODE__SETUP_ACCOUNT); }); builder.setNeutralButton(R.string.uploader_wrn_no_account_quit_btn_text, - (dialog, which) -> getActivity().finish()); + (dialog, which) -> getActivity().finish()); return builder.create(); } } @@ -329,8 +329,7 @@ public class ReceiveExternalFilesActivity extends FileActivity private Spinner mSpinner; @Inject AppPreferences preferences; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; public static DialogInputUploadFilename newInstance(String subjectText, String extraText) { DialogInputUploadFilename dialog = new DialogInputUploadFilename(); @@ -368,7 +367,7 @@ public class ReceiveExternalFilesActivity extends FileActivity View view = layout.inflate(R.layout.upload_file_dialog, null); ArrayAdapter adapter - = new ArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_item); + = new ArrayAdapter<>(requireContext(), android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); int selectPos = 0; @@ -385,17 +384,17 @@ public class ReceiveExternalFilesActivity extends FileActivity mText.add(internetShortcutUrlText(extraText)); mFilenameBase.add(filename); mFilenameSuffix.add(URL_FILE_SUFFIX); - adapter.add(String.format(str,URL_FILE_SUFFIX)); + adapter.add(String.format(str, URL_FILE_SUFFIX)); mText.add(internetShortcutWeblocText(extraText)); mFilenameBase.add(filename); mFilenameSuffix.add(WEBLOC_FILE_SUFFIX); - adapter.add(String.format(str,WEBLOC_FILE_SUFFIX)); + adapter.add(String.format(str, WEBLOC_FILE_SUFFIX)); mText.add(internetShortcutDesktopText(extraText, filename)); mFilenameBase.add(filename); mFilenameSuffix.add(DESKTOP_FILE_SUFFIX); - adapter.add(String.format(str,DESKTOP_FILE_SUFFIX)); + adapter.add(String.format(str, DESKTOP_FILE_SUFFIX)); selectPos = preferences.getUploadUrlFileExtensionUrlSelectedPos(); mFileCategory = CATEGORY_URL; @@ -405,12 +404,12 @@ public class ReceiveExternalFilesActivity extends FileActivity mText.add(internetShortcutUrlText(texts[2])); mFilenameBase.add(texts[0]); mFilenameSuffix.add(URL_FILE_SUFFIX); - adapter.add(String.format(str,URL_FILE_SUFFIX)); + adapter.add(String.format(str, URL_FILE_SUFFIX)); mText.add(internetShortcutWeblocText(texts[2])); mFilenameBase.add(texts[0]); mFilenameSuffix.add(WEBLOC_FILE_SUFFIX); - adapter.add(String.format(str,WEBLOC_FILE_SUFFIX)); + adapter.add(String.format(str, WEBLOC_FILE_SUFFIX)); mText.add(internetShortcutDesktopText(texts[2], texts[0])); mFilenameBase.add(texts[0]); @@ -425,10 +424,7 @@ public class ReceiveExternalFilesActivity extends FileActivity final TextInputLayout userInputContainer = view.findViewById(R.id.user_input_container); setFilename(userInput, selectPos); userInput.requestFocus(); - themeTextInputUtils.colorTextInput(userInputContainer, - userInput, - themeColorUtils.primaryColor(getContext()), - themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.material.colorTextInputLayout(userInputContainer); final Spinner spinner = view.findViewById(R.id.file_type); setupSpinner(adapter, selectPos, userInput, spinner); @@ -523,8 +519,7 @@ public class ReceiveExternalFilesActivity extends FileActivity } } - private void setFilename(EditText inputText, int selectPos) - { + private void setFilename(EditText inputText, int selectPos) { String filename = mFilenameBase.get(selectPos) + mFilenameSuffix.get(selectPos); inputText.setText(filename); int selectionStart = 0; @@ -532,8 +527,8 @@ public class ReceiveExternalFilesActivity extends FileActivity int selectionEnd = extensionStart >= 0 ? extensionStart : filename.length(); if (selectionEnd >= 0) { inputText.setSelection( - Math.min(selectionStart, selectionEnd), - Math.max(selectionStart, selectionEnd)); + Math.min(selectionStart, selectionEnd), + Math.max(selectionStart, selectionEnd)); } } @@ -577,18 +572,18 @@ public class ReceiveExternalFilesActivity extends FileActivity private String internetShortcutUrlText(String url) { return "[InternetShortcut]\r\n" + - "URL=" + url + "\r\n"; + "URL=" + url + "\r\n"; } private String internetShortcutWeblocText(String url) { return "\n" + - "\n" + - "\n" + - "\n" + - "URL\n" + - "" + url + "\n" + - "\n" + - "\n"; + "\n" + + "\n" + + "\n" + + "URL\n" + + "" + url + "\n" + + "\n" + + "\n"; } private String internetShortcutDesktopText(String url, String filename) { @@ -652,7 +647,7 @@ public class ReceiveExternalFilesActivity extends FileActivity if (files.size() < position) { throw new IndexOutOfBoundsException("Incorrect item selected"); } - if (files.get(position).isFolder()){ + if (files.get(position).isFolder()) { OCFile folderToEnter = files.get(position); startSyncFolderOperation(folderToEnter); mParents.push(folderToEnter.getFileName()); @@ -711,8 +706,8 @@ public class ReceiveExternalFilesActivity extends FileActivity private void setupActionBarSubtitle() { ActionBar actionBar = getSupportActionBar(); - if (isHaveMultipleAccount()) { - themeToolbarUtils.setColoredSubtitle(actionBar, getAccount().name, this); + if (isHaveMultipleAccount() && actionBar != null) { + viewThemeUtils.files.themeActionBar(this, actionBar, getAccount().name); } else if (actionBar != null) { actionBar.setSubtitle(null); } @@ -732,9 +727,9 @@ public class ReceiveExternalFilesActivity extends FileActivity if (actionBar != null) { if (TextUtils.isEmpty(current_dir)) { - themeToolbarUtils.setColoredTitle(actionBar, R.string.uploader_top_message, this); + viewThemeUtils.files.themeActionBar(this, actionBar, R.string.uploader_top_message); } else { - themeToolbarUtils.setColoredTitle(actionBar, current_dir, this); + viewThemeUtils.files.themeActionBar(this, actionBar, current_dir); } actionBar.setDisplayHomeAsUpEnabled(notRoot); @@ -751,7 +746,7 @@ public class ReceiveExternalFilesActivity extends FileActivity if (files.isEmpty()) { setMessageForEmptyList(R.string.file_list_empty_headline, R.string.empty, - R.drawable.uploads); + R.drawable.uploads); } else { mEmptyListContainer.setVisibility(View.GONE); @@ -771,30 +766,20 @@ public class ReceiveExternalFilesActivity extends FileActivity new int[]{R.id.filename}, getStorageManager(), getUser().get(), - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); binding.list.setAdapter(sa); } MaterialButton btnChooseFolder = binding.uploaderChooseFolder; - themeButtonUtils.colorPrimaryButton(btnChooseFolder, this, themeColorUtils); + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(btnChooseFolder); btnChooseFolder.setOnClickListener(this); - if (mFile.canWrite()) { - btnChooseFolder.setEnabled(true); - themeButtonUtils.colorPrimaryButton(btnChooseFolder, this, themeColorUtils); - } else { - btnChooseFolder.setEnabled(false); - btnChooseFolder.setBackgroundColor(Color.GRAY); - } + btnChooseFolder.setEnabled(mFile.canWrite()); - themeToolbarUtils.colorStatusBar(this); + viewThemeUtils.platform.themeStatusBar(this); - themeToolbarUtils.tintBackButton(actionBar, this); - - Button btnNewFolder = binding.uploaderCancel; - btnNewFolder.setTextColor(themeColorUtils.primaryColor(this, true)); - btnNewFolder.setOnClickListener(this); + viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.uploaderCancel); + binding.uploaderCancel.setOnClickListener(this); binding.list.setOnItemClickListener(this); @@ -818,8 +803,7 @@ public class ReceiveExternalFilesActivity extends FileActivity if (mEmptyListContainer != null && mEmptyListMessage != null) { mEmptyListHeadline.setText(headline); mEmptyListMessage.setText(message); - mEmptyListIcon.setImageDrawable( - themeDrawableUtils.tintDrawable(icon, themeColorUtils.primaryColor(this, true))); + mEmptyListIcon.setImageDrawable(viewThemeUtils.platform.tintPrimaryDrawable(this, icon)); mEmptyListIcon.setVisibility(View.VISIBLE); mEmptyListMessage.setVisibility(View.VISIBLE); } @@ -838,13 +822,13 @@ public class ReceiveExternalFilesActivity extends FileActivity // perform folder synchronization RemoteOperation syncFolderOp = new RefreshFolderOperation(folder, - currentSyncTime, - false, - false, - getStorageManager(), - getUser().orElseThrow(RuntimeException::new), - getApplicationContext() - ); + currentSyncTime, + false, + false, + getStorageManager(), + getUser().orElseThrow(RuntimeException::new), + getApplicationContext() + ); syncFolderOp.execute(getAccount(), this, null, null); } @@ -896,23 +880,23 @@ public class ReceiveExternalFilesActivity extends FileActivity private boolean somethingToUpload() { return (mStreamsToUpload != null && mStreamsToUpload.size() > 0 && mStreamsToUpload.get(0) != null || - mUploadFromTmpFile); + mUploadFromTmpFile); } public void uploadFile(String tmpName, String filename) { FileUploader.uploadNewFile( - getBaseContext(), - getUser().orElseThrow(RuntimeException::new), - tmpName, - mFile.getRemotePath() + filename, - FileUploader.LOCAL_BEHAVIOUR_COPY, - null, - true, - UploadFileOperation.CREATED_BY_USER, - false, - false, - NameCollisionPolicy.ASK_USER - ); + getBaseContext(), + getUser().orElseThrow(RuntimeException::new), + tmpName, + mFile.getRemotePath() + filename, + FileUploader.LOCAL_BEHAVIOUR_COPY, + null, + true, + UploadFileOperation.CREATED_BY_USER, + false, + false, + NameCollisionPolicy.ASK_USER + ); finish(); } @@ -950,9 +934,9 @@ public class ReceiveExternalFilesActivity extends FileActivity } showErrorDialog( - messageResId, - messageResTitle - ); + messageResId, + messageResTitle + ); } } @@ -968,8 +952,7 @@ public class ReceiveExternalFilesActivity extends FileActivity } /** - * Updates the view associated to the activity after the finish of an operation - * trying create a new folder + * Updates the view associated to the activity after the finish of an operation trying create a new folder * * @param operation Creation operation performed. * @param result Result of the creation. @@ -984,8 +967,8 @@ public class ReceiveExternalFilesActivity extends FileActivity } else { try { DisplayUtils.showSnackMessage( - this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()) - ); + this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()) + ); } catch (NotFoundException e) { Log_OC.e(TAG, "Error while trying to show fail message ", e); @@ -1044,7 +1027,7 @@ public class ReceiveExternalFilesActivity extends FileActivity newFolderMenuItem.setEnabled(mFile.canWrite()); // hacky as no default way is provided - themeToolbarUtils.themeSearchView(searchView, this); + viewThemeUtils.androidx.themeToolbarSearchView(searchView); return true; } @@ -1070,7 +1053,7 @@ public class ReceiveExternalFilesActivity extends FileActivity return retval; } - private OCFile getCurrentFolder(){ + private OCFile getCurrentFolder() { OCFile file = mFile; if (file != null) { if (file.isFolder()) { @@ -1101,9 +1084,9 @@ public class ReceiveExternalFilesActivity extends FileActivity String accountName = intent.getStringExtra(FileSyncAdapter.EXTRA_ACCOUNT_NAME); String syncFolderRemotePath = intent.getStringExtra(FileSyncAdapter.EXTRA_FOLDER_PATH); RemoteOperationResult syncResult = (RemoteOperationResult) - DataHolderUtil.getInstance().retrieve(intent.getStringExtra(FileSyncAdapter.EXTRA_RESULT)); + DataHolderUtil.getInstance().retrieve(intent.getStringExtra(FileSyncAdapter.EXTRA_RESULT)); boolean sameAccount = getAccount() != null && accountName.equals(getAccount().name) - && getStorageManager() != null; + && getStorageManager() != null; if (sameAccount) { @@ -1119,10 +1102,10 @@ public class ReceiveExternalFilesActivity extends FileActivity if (currentDir == null) { // current folder was removed from the server DisplayUtils.showSnackMessage( - getActivity(), - R.string.sync_current_folder_was_removed, - getCurrentFolder().getFileName() - ); + getActivity(), + R.string.sync_current_folder_was_removed, + getCurrentFolder().getFileName() + ); browseToRoot(); } else { @@ -1138,11 +1121,11 @@ public class ReceiveExternalFilesActivity extends FileActivity } mSyncInProgress = !FileSyncAdapter.EVENT_FULL_SYNC_END.equals(event) && - !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event); + !RefreshFolderOperation.EVENT_SINGLE_FOLDER_SHARES_SYNCED.equals(event); if (RefreshFolderOperation.EVENT_SINGLE_FOLDER_CONTENTS_SYNCED.equals(event) - /// TODO refactor and make common - && syncResult != null && !syncResult.isSuccess()) { + /// TODO refactor and make common + && syncResult != null && !syncResult.isSuccess()) { if (syncResult.getCode() == ResultCode.UNAUTHORIZED || (syncResult.isException() && syncResult.getException() @@ -1179,9 +1162,9 @@ public class ReceiveExternalFilesActivity extends FileActivity /** * Show an error dialog, forcing the user to click a single button to exit the activity * - * @param messageResId Resource id of the message to show in the dialog. - * @param messageResTitle Resource id of the title to show in the dialog. 0 to show default alert message. - * -1 to show no title. + * @param messageResId Resource id of the message to show in the dialog. + * @param messageResTitle Resource id of the title to show in the dialog. 0 to show default alert message. -1 to + * show no title. */ private void showErrorDialog(int messageResId, int messageResTitle) { @@ -1192,7 +1175,7 @@ public class ReceiveExternalFilesActivity extends FileActivity R.string.common_back, -1, -1 - ); + ); errorDialog.setCancelable(false); errorDialog.setOnConfirmationListener( new ConfirmationDialogFragment.ConfirmationDialogFragmentListener() { @@ -1211,7 +1194,7 @@ public class ReceiveExternalFilesActivity extends FileActivity // not used at the moment } } - ); + ); errorDialog.show(getSupportFragmentManager(), FTAG_ERROR_FRAGMENT); } } 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 3855578349..f9ddae3036 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 @@ -31,11 +31,11 @@ import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; -import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceActivity; import android.preference.PreferenceCategory; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; @@ -75,11 +75,7 @@ import com.owncloud.android.utils.DeviceCredentialUtils; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.EncryptionUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; -import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -92,19 +88,21 @@ import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDelegate; +import androidx.core.content.ContextCompat; +import androidx.core.content.res.ResourcesCompat; /** * An Activity that allows the user to change the application's settings. - * + *

* It proxies the necessary calls via {@link androidx.appcompat.app.AppCompatDelegate} to be used with AppCompat. */ -public class SettingsActivity extends ThemedPreferenceActivity +public class SettingsActivity extends PreferenceActivity implements StorageMigration.StorageMigrationProgressListener, LoadingVersionNumberTask.VersionDevInterface, Injectable { private static final String TAG = SettingsActivity.class.getSimpleName(); - public static final String PREFERENCE_LOCK= "lock"; + public static final String PREFERENCE_LOCK = "lock"; public static final String LOCK_NONE = "none"; public static final String LOCK_PASSCODE = "passcode"; @@ -140,21 +138,14 @@ public class SettingsActivity extends ThemedPreferenceActivity @Inject AppPreferences preferences; @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; - @Inject ThemeUtils themeUtils; - @Inject ThemeTextUtils themeTextUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; + @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (themeUtils.themingEnabled(this)) { - setTheme(R.style.FallbackThemingTheme); - } - getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); @@ -164,7 +155,6 @@ public class SettingsActivity extends ThemedPreferenceActivity // Register context menu for list of preferences. registerForContextMenu(getListView()); - int accentColor = themeColorUtils.primaryAccentColor(this); String appVersion = getAppVersion(); PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("preference_screen"); @@ -174,31 +164,33 @@ public class SettingsActivity extends ThemedPreferenceActivity setupBaseUri(); // General - setupGeneralCategory(accentColor); + setupGeneralCategory(); // Synced folders - setupAutoUploadCategory(accentColor, preferenceScreen); + setupAutoUploadCategory(preferenceScreen); // Details - setupDetailsCategory(accentColor, preferenceScreen); + setupDetailsCategory(preferenceScreen); // More - setupMoreCategory(accentColor); + setupMoreCategory(); // About - setupAboutCategory(accentColor, appVersion); + setupAboutCategory(appVersion); // Dev - setupDevCategory(accentColor, preferenceScreen); + setupDevCategory(preferenceScreen); + + // workaround for mismatched color when app dark mode and system dark mode don't agree + setListBackground(); } - private void setupDevCategory(int accentColor, PreferenceScreen preferenceScreen) { + private void setupDevCategory(PreferenceScreen preferenceScreen) { // Dev category PreferenceCategory preferenceCategoryDev = (PreferenceCategory) findPreference("dev_category"); if (getResources().getBoolean(R.bool.is_beta)) { - preferenceCategoryDev.setTitle(themeTextUtils.getColoredTitle(getString(R.string.prefs_category_dev), - accentColor)); + viewThemeUtils.files.themePreferenceCategory(preferenceCategoryDev); /* Link to dev apks */ Preference pDevLink = findPreference("dev_link"); @@ -235,10 +227,9 @@ public class SettingsActivity extends ThemedPreferenceActivity } } - private void setupAboutCategory(int accentColor, String appVersion) { - PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("about"); - preferenceCategoryAbout.setTitle(themeTextUtils.getColoredTitle(getString(R.string.prefs_category_about), - accentColor)); + private void setupAboutCategory(String appVersion) { + final PreferenceCategory preferenceCategoryAbout = (PreferenceCategory) findPreference("about"); + viewThemeUtils.files.themePreferenceCategory(preferenceCategoryAbout); /* About App */ Preference pAboutApp = findPreference("about_app"); @@ -288,7 +279,7 @@ public class SettingsActivity extends ThemedPreferenceActivity } else { intent = new Intent(getApplicationContext(), ExternalSiteWebView.class); intent.putExtra(ExternalSiteWebView.EXTRA_TITLE, - getResources().getString(R.string.privacy)); + getResources().getString(R.string.privacy)); intent.putExtra(ExternalSiteWebView.EXTRA_URL, privacyUrl.toString()); intent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false); intent.putExtra(ExternalSiteWebView.EXTRA_MENU_ITEM_ID, -1); @@ -321,10 +312,9 @@ public class SettingsActivity extends ThemedPreferenceActivity } } - private void setupMoreCategory(int accentColor) { - PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more"); - preferenceCategoryMore.setTitle(themeTextUtils.getColoredTitle(getString(R.string.prefs_category_more), - accentColor)); + private void setupMoreCategory() { + final PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more"); + viewThemeUtils.files.themePreferenceCategory(preferenceCategoryMore); setupAutoUploadPreference(preferenceCategoryMore); @@ -386,7 +376,6 @@ public class SettingsActivity extends ThemedPreferenceActivity } - private void setupRecommendPreference(PreferenceCategory preferenceCategoryMore) { boolean recommendEnabled = getResources().getBoolean(R.bool.recommend_enabled); Preference pRecommend = findPreference("recommend"); @@ -402,11 +391,11 @@ public class SettingsActivity extends ThemedPreferenceActivity String downloadUrlGooglePlayStore = getString(R.string.url_app_download); String downloadUrlFDroid = getString(R.string.fdroid_link); String downloadUrls = String.format(getString(R.string.recommend_urls), - downloadUrlGooglePlayStore, downloadUrlFDroid); + downloadUrlGooglePlayStore, downloadUrlFDroid); String recommendSubject = String.format(getString(R.string.recommend_subject), appName); String recommendText = String.format(getString(R.string.recommend_text), - appName, downloadUrls); + appName, downloadUrls); intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject); intent.putExtra(Intent.EXTRA_TEXT, recommendText); @@ -501,9 +490,9 @@ public class SettingsActivity extends ThemedPreferenceActivity } catch (Throwable t) { Log_OC.e(TAG, "Base Uri for account could not be resolved to call DAVdroid!", t); DisplayUtils.showSnackMessage( - activity, - R.string.prefs_calendar_contacts_address_resolve_error - ); + activity, + R.string.prefs_calendar_contacts_address_resolve_error + ); } return true; }); @@ -513,10 +502,9 @@ public class SettingsActivity extends ThemedPreferenceActivity } } - private void setupDetailsCategory(int accentColor, PreferenceScreen preferenceScreen) { + private void setupDetailsCategory(PreferenceScreen preferenceScreen) { PreferenceCategory preferenceCategoryDetails = (PreferenceCategory) findPreference("details"); - preferenceCategoryDetails.setTitle(themeTextUtils.getColoredTitle(getString(R.string.prefs_category_details), - accentColor)); + viewThemeUtils.files.themePreferenceCategory(preferenceCategoryDetails); boolean fPassCodeEnabled = getResources().getBoolean(R.bool.passcode_enabled); boolean fDeviceCredentialsEnabled = getResources().getBoolean(R.bool.device_credentials_enabled); @@ -609,11 +597,10 @@ public class SettingsActivity extends ThemedPreferenceActivity } } - private void setupAutoUploadCategory(int accentColor, PreferenceScreen preferenceScreen) { - PreferenceCategory preferenceCategorySyncedFolders = + private void setupAutoUploadCategory(PreferenceScreen preferenceScreen) { + final PreferenceCategory preferenceCategorySyncedFolders = (PreferenceCategory) findPreference("synced_folders_category"); - preferenceCategorySyncedFolders.setTitle(themeTextUtils.getColoredTitle(getString(R.string.drawer_synced_folders), - accentColor)); + viewThemeUtils.files.themePreferenceCategory(preferenceCategorySyncedFolders); if (!getResources().getBoolean(R.bool.syncedFolder_light)) { preferenceScreen.removePreference(preferenceCategorySyncedFolders); @@ -653,7 +640,7 @@ public class SettingsActivity extends ThemedPreferenceActivity Intent i = new Intent(getApplicationContext(), PassCodeActivity.class); i.setAction(PassCodeActivity.ACTION_REQUEST_WITH_RESULT); startActivityForResult(i, ACTION_REQUEST_PASSCODE); - } else if (LOCK_DEVICE_CREDENTIALS.equals(lock)){ + } else if (LOCK_DEVICE_CREDENTIALS.equals(lock)) { if (!DeviceCredentialUtils.areCredentialsAvailable(getApplicationContext())) { DisplayUtils.showSnackMessage(this, R.string.prefs_lock_device_credentials_not_setup); } else { @@ -680,10 +667,9 @@ public class SettingsActivity extends ThemedPreferenceActivity } } - private void setupGeneralCategory(int accentColor) { - PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general"); - preferenceCategoryGeneral.setTitle(themeTextUtils.getColoredTitle(getString(R.string.prefs_category_general), - accentColor)); + private void setupGeneralCategory() { + final PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general"); + viewThemeUtils.files.themePreferenceCategory(preferenceCategoryGeneral); prefStoragePath = (ListPreference) findPreference(AppPreferencesImpl.STORAGE_PATH); if (prefStoragePath != null) { @@ -737,11 +723,16 @@ public class SettingsActivity extends ThemedPreferenceActivity DarkMode mode = DarkMode.valueOf((String) newValue); preferences.setDarkThemeMode(mode); MainApp.setAppTheme(mode); + setListBackground(); return true; }); } + private void setListBackground() { + getListView().setBackgroundColor(ContextCompat.getColor(this, R.color.bg_default)); + } + private String getAppVersion() { String temp; try { @@ -764,12 +755,17 @@ public class SettingsActivity extends ThemedPreferenceActivity ActionBar actionBar = getDelegate().getSupportActionBar(); if (actionBar != null) { - themeToolbarUtils.setColoredTitle(actionBar, getString(R.string.actionbar_settings), this); - themeToolbarUtils.colorStatusBar(this); - actionBar.setBackgroundDrawable(new ColorDrawable(themeColorUtils.primaryAppbarColor(this))); - + viewThemeUtils.platform.themeStatusBar(this); actionBar.setDisplayHomeAsUpEnabled(true); - themeToolbarUtils.tintBackButton(actionBar, this); + actionBar.setDisplayShowTitleEnabled(true); + if (this.getResources() != null) { + viewThemeUtils.androidx.themeActionBar(this, + actionBar, + getString(R.string.actionbar_settings), + ResourcesCompat.getDrawable(this.getResources(), + R.drawable.ic_arrow_back, + null)); + } } } @@ -798,7 +794,7 @@ public class SettingsActivity extends ThemedPreferenceActivity } else { // no f-droid market app or Play store installed --> launch browser for f-droid url Intent downloadIntent = new Intent(Intent.ACTION_VIEW, - Uri.parse("https://f-droid.org/repository/browse/?fdid=at.bitfire.davdroid")); + Uri.parse("https://f-droid.org/repository/browse/?fdid=at.bitfire.davdroid")); DisplayUtils.startIntentIfAppAvailable(downloadIntent, this, R.string.no_browser_available); DisplayUtils.showSnackMessage(this, R.string.prefs_calendar_contacts_no_store_error); @@ -819,7 +815,6 @@ public class SettingsActivity extends ThemedPreferenceActivity } - @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); @@ -834,7 +829,7 @@ public class SettingsActivity extends ThemedPreferenceActivity String passcode = data.getStringExtra(PassCodeActivity.KEY_PASSCODE); if (passcode != null && passcode.length() == 4) { SharedPreferences.Editor appPrefs = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); + .getDefaultSharedPreferences(getApplicationContext()).edit(); for (int i = 1; i <= 4; ++i) { appPrefs.putString(PassCodeActivity.PREFERENCE_PASSCODE_D + i, passcode.substring(i - 1, i)); @@ -887,8 +882,7 @@ public class SettingsActivity extends ThemedPreferenceActivity .create(); alertDialog.show(); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java index 120c91bc84..bcdf08985a 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ShareActivity.java @@ -23,7 +23,6 @@ package com.owncloud.android.ui.activity; import android.app.Activity; import android.graphics.Bitmap; -import android.graphics.PorterDuff; import android.os.Bundle; import com.nextcloud.client.account.User; @@ -79,15 +78,12 @@ public class ShareActivity extends FileActivity { file.isGroupFolder(), file.getMountType(), this, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } else { binding.shareFileIcon.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), - optionalUser.get(), this, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); if (MimeTypeUtil.isImage(file)) { String remoteId = String.valueOf(file.getRemoteId()); Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(remoteId); @@ -100,8 +96,7 @@ public class ShareActivity extends FileActivity { // Name binding.shareFileName.setText(getResources().getString(R.string.share_file, file.getFileName())); - binding.shareHeaderDivider.getBackground().setColorFilter(themeColorUtils.primaryAccentColor(this), - PorterDuff.Mode.SRC_ATOP); + viewThemeUtils.platform.colorViewBackground(binding.shareHeaderDivider); // Size binding.shareFileSize.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index 02fcad2c12..061cbad6e7 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -66,8 +66,7 @@ import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment.OnSy import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable import com.owncloud.android.utils.PermissionUtil import com.owncloud.android.utils.SyncedFolderUtils -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeSnackbarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -159,10 +158,7 @@ class SyncedFoldersActivity : lateinit var backgroundJobManager: BackgroundJobManager @Inject - lateinit var themeButtonUtils: ThemeButtonUtils - - @Inject - lateinit var themeSnackBarUtils: ThemeSnackbarUtils + lateinit var viewThemeUtils: ViewThemeUtils private lateinit var binding: SyncedFoldersLayoutBinding private lateinit var adapter: SyncedFolderAdapter @@ -243,7 +239,7 @@ class SyncedFoldersActivity : .setTitle(R.string.autoupload_disable_power_save_check) .setMessage(getString(R.string.power_save_check_dialog_message)) .show() - themeButtonUtils.themeBorderlessButton(themeColorUtils, alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)) + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)) } /** @@ -252,10 +248,17 @@ class SyncedFoldersActivity : private fun setupContent() { val gridWidth = resources.getInteger(R.integer.media_grid_width) val lightVersion = resources.getBoolean(R.bool.syncedFolder_light) - adapter = SyncedFolderAdapter(this, clock, gridWidth, this, lightVersion, themeColorUtils, themeDrawableUtils) + adapter = SyncedFolderAdapter( + this, + clock, + gridWidth, + this, + lightVersion, + viewThemeUtils + ) syncedFolderProvider = SyncedFolderProvider(contentResolver, preferences, clock) binding.emptyList.emptyListIcon.setImageResource(R.drawable.nav_synced_folders) - themeButtonUtils.colorPrimaryButton(binding.emptyList.emptyListViewAction, this, themeColorUtils) + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.emptyList.emptyListViewAction) val lm = GridLayoutManager(this, gridWidth) adapter.setLayoutManager(lm) val spacing = resources.getDimensionPixelSize(R.dimen.media_grid_spacing) @@ -291,7 +294,7 @@ class SyncedFoldersActivity : perFolderMediaItemLimit, this@SyncedFoldersActivity, false, - themeSnackbarUtils + viewThemeUtils ) mediaFolders.addAll( MediaProvider.getVideoFolders( @@ -299,7 +302,7 @@ class SyncedFoldersActivity : perFolderMediaItemLimit, this@SyncedFoldersActivity, false, - themeSnackbarUtils + viewThemeUtils ) ) val syncedFolderArrayList = syncedFolderProvider.syncedFolders @@ -548,7 +551,7 @@ class SyncedFoldersActivity : ) onSyncFolderSettingsClick(0, emptyCustomFolder) } else { - PermissionUtil.requestExternalStoragePermission(this, themeSnackBarUtils, true) + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true) } result = super.onOptionsItemSelected(item) } @@ -775,7 +778,7 @@ class SyncedFoldersActivity : load(getItemsDisplayedPerFolder(), true) } else { // permission denied --> request again - PermissionUtil.requestExternalStoragePermission(this, themeSnackbarUtils, true) + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true) } } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) @@ -802,8 +805,7 @@ class SyncedFoldersActivity : .setIcon(R.drawable.ic_battery_alert) if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { val alertDialog = alertDialogBuilder.show() - themeButtonUtils.themeBorderlessButton( - themeColorUtils, + viewThemeUtils.platform.colorTextButtons( alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) ) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt b/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt index f0dfe7811f..07e33b3e26 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/TextEditorWebView.kt @@ -26,6 +26,7 @@ import android.net.Uri import android.widget.Toast import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature +import com.nextcloud.android.common.ui.util.PlatformThemeUtil import com.nextcloud.client.appinfo.AppInfo import com.nextcloud.client.device.DeviceInfo import com.owncloud.android.R @@ -67,7 +68,7 @@ class TextEditorWebView : EditorWebView() { WebSettingsCompat.DARK_STRATEGY_WEB_THEME_DARKENING_ONLY ) } - if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) && themeUtils.isDarkModeActive(this)) { + if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK) && PlatformThemeUtil.isDarkMode(this)) { WebSettingsCompat.setForceDark(getWebView().settings, WebSettingsCompat.FORCE_DARK_ON) } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ThemedPreferenceActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ThemedPreferenceActivity.java deleted file mode 100644 index 2cf02cd145..0000000000 --- a/app/src/main/java/com/owncloud/android/ui/activity/ThemedPreferenceActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Daniel Bailey - * Copyright (C) 2019 Daniel Bailey - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * 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 AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this program. If not, see . - */ - -package com.owncloud.android.ui.activity; - -import android.os.Bundle; -import android.preference.PreferenceActivity; - -import com.nextcloud.client.preferences.AppPreferences; -import com.nextcloud.client.preferences.DarkMode; - -import javax.inject.Inject; - -import androidx.annotation.Nullable; - -public class ThemedPreferenceActivity extends PreferenceActivity { - - /** - * Tracks whether the activity should be recreate()'d after a theme change - */ - private boolean themeChangePending; - private boolean paused; - - @Inject AppPreferences preferences; - - private AppPreferences.Listener onThemeChangedListener = new AppPreferences.Listener() { - @Override - public void onDarkThemeModeChanged(DarkMode mode) { - preferences.setDarkThemeMode(mode); - - if (paused) { - themeChangePending = true; - return; - } - recreate(); - } - }; - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - preferences.addListener(onThemeChangedListener); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - preferences.removeListener(onThemeChangedListener); - } - - @Override - protected void onPause() { - super.onPause(); - paused = true; - } - - @Override - protected void onResume() { - super.onResume(); - paused = false; - - if (themeChangePending) { - recreate(); - } - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java index edb745d7ec..a6512ca79c 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ToolbarActivity.java @@ -37,6 +37,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.MaterialToolbar; import com.google.android.material.button.MaterialButton; import com.google.android.material.card.MaterialCardView; import com.google.android.material.textview.MaterialTextView; @@ -44,12 +45,9 @@ import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.utils.theme.ThemeButtonUtils; import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; -import com.owncloud.android.utils.theme.ThemeLayoutUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -58,8 +56,6 @@ import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.AppCompatSpinner; -import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; /** * Base class providing toolbar registration functionality, see {@link #setupToolbar(boolean, boolean)}. @@ -71,7 +67,7 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable private AppBarLayout mAppBar; private RelativeLayout mDefaultToolbar; - private Toolbar mToolbar; + private MaterialToolbar mToolbar; private MaterialCardView mHomeSearchToolbar; private ImageView mPreviewImage; private FrameLayout mPreviewImageContainer; @@ -81,22 +77,16 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable private boolean isHomeSearchToolbarShow = false; @Inject public ThemeColorUtils themeColorUtils; - @Inject public ThemeLayoutUtils themeLayoutUtils; - @Inject public ThemeToolbarUtils themeToolbarUtils; @Inject public ThemeUtils themeUtils; - @Inject public ThemeDrawableUtils themeDrawableUtils; - @Inject public ThemeButtonUtils themeButtonUtils; + @Inject public ViewThemeUtils viewThemeUtils; /** * Toolbar setup that must be called in implementer's {@link #onCreate} after {@link #setContentView} if they want * to use the toolbar. */ private void setupToolbar(boolean isHomeSearchToolbarShow, boolean showSortListButtonGroup) { - int fontColor = themeColorUtils.appBarPrimaryFontColor(this); - mToolbar = findViewById(R.id.toolbar); setSupportActionBar(mToolbar); - themeToolbarUtils.colorStatusBar(this); mAppBar = findViewById(R.id.appbar); mDefaultToolbar = findViewById(R.id.default_toolbar); @@ -120,13 +110,10 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable mToolbarSpinner = findViewById(R.id.toolbar_spinner); - if (mToolbar.getOverflowIcon() != null) { - themeDrawableUtils.tintDrawable(mToolbar.getOverflowIcon(), fontColor); - } - - if (mToolbar.getNavigationIcon() != null) { - themeDrawableUtils.tintDrawable(mToolbar.getNavigationIcon(), fontColor); - } + viewThemeUtils.material.themeToolbar(mToolbar); + viewThemeUtils.material.colorToolbarOverflowIcon(mToolbar); + viewThemeUtils.platform.themeStatusBar(this); + viewThemeUtils.material.colorMaterialTextButton(mSwitchAccountButton); } public void setupToolbar() { @@ -171,18 +158,21 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable @SuppressLint("PrivateResource") private void showHomeSearchToolbar(boolean isShow) { + viewThemeUtils.material.themeToolbar(mToolbar); if (isShow) { + viewThemeUtils.platform.resetStatusBar(this); mAppBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(mAppBar.getContext(), R.animator.appbar_elevation_off)); mDefaultToolbar.setVisibility(View.GONE); mHomeSearchToolbar.setVisibility(View.VISIBLE); - themeToolbarUtils.colorStatusBar(this, ContextCompat.getColor(this, R.color.bg_default)); + viewThemeUtils.material.themeCardView(mHomeSearchToolbar); + viewThemeUtils.material.themeSearchBarText(mSearchText); } else { mAppBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(mAppBar.getContext(), R.animator.appbar_elevation_on)); + viewThemeUtils.platform.themeStatusBar(this); mDefaultToolbar.setVisibility(View.VISIBLE); mHomeSearchToolbar.setVisibility(View.GONE); - themeToolbarUtils.colorStatusBar(this); } } @@ -198,10 +188,10 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable // set & color the chosen title ActionBar actionBar = getSupportActionBar(); - themeToolbarUtils.setColoredTitle(actionBar, titleToSet, this); // set home button properties if (actionBar != null) { + actionBar.setTitle(titleToSet); actionBar.setDisplayShowTitleEnabled(true); } } @@ -209,10 +199,12 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable /** * checks if the given file is the root folder. * + * * @param file file to be checked if it is the root folder * @return true if it is null or the root folder, else returns false */ public boolean isRoot(OCFile file) { + return file == null || (file.isFolder() && file.getParentId() == FileDataStorageManager.ROOT_PARENT_ID); } @@ -291,7 +283,10 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable public void updateToolbarSubtitle(@NonNull String subtitle) { ActionBar actionBar = getSupportActionBar(); - themeToolbarUtils.setColoredSubtitle(actionBar, subtitle, this); + if (actionBar != null) { + actionBar.setSubtitle(subtitle); + viewThemeUtils.androidx.themeActionBarSubtitle(this, actionBar); + } } public void clearToolbarSubtitle() { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 2f6eadb712..4d7dd31c6b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -41,6 +41,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.R; +import com.owncloud.android.databinding.UploadFilesLayoutBinding; import com.owncloud.android.files.services.FileUploader; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.adapter.StoragePathAdapter; @@ -55,7 +56,6 @@ import com.owncloud.android.ui.fragment.LocalFileListFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.PermissionUtil; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; import java.io.File; import java.util.ArrayList; @@ -98,7 +98,6 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList private static final String WAIT_DIALOG_TAG = "WAIT"; @Inject AppPreferences preferences; - @Inject ThemeSnackbarUtils themeSnackbarUtils; private Account mAccountOnCreation; private ArrayAdapter mDirectories; private boolean mLocalFolderPickerMode; @@ -110,8 +109,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList private LocalStoragePathPickerDialogFragment dialog; private Menu mOptionsMenu; private SearchView mSearchView; - private Spinner mBehaviourSpinner; - private MaterialButton uploadButton; + private UploadFilesLayoutBinding binding; @VisibleForTesting @@ -174,30 +172,27 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList fillDirectoryDropdown(); // Inflate and set the layout view - setContentView(R.layout.upload_files_layout); + binding = UploadFilesLayoutBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); if (mLocalFolderPickerMode) { - findViewById(R.id.upload_options).setVisibility(View.GONE); - ((MaterialButton) findViewById(R.id.upload_files_btn_upload)).setText(R.string.uploader_btn_alternative_text); + binding.uploadOptions.setVisibility(View.GONE); + binding.uploadFilesBtnUpload.setText(R.string.uploader_btn_alternative_text); } mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentByTag("local_files_list"); // Set input controllers - MaterialButton cancelButton = findViewById(R.id.upload_files_btn_cancel); - cancelButton.setTextColor(themeColorUtils.primaryColor(this, true)); - cancelButton.setOnClickListener(this); + viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.uploadFilesBtnCancel); + binding.uploadFilesBtnCancel.setOnClickListener(this); - uploadButton = findViewById(R.id.upload_files_btn_upload); - themeButtonUtils.colorPrimaryButton(uploadButton, this, themeColorUtils); - uploadButton.setOnClickListener(this); - uploadButton.setEnabled(mLocalFolderPickerMode); + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.uploadFilesBtnUpload); + binding.uploadFilesBtnUpload.setOnClickListener(this); + binding.uploadFilesBtnUpload.setEnabled(mLocalFolderPickerMode); int localBehaviour = preferences.getUploaderBehaviour(); // file upload spinner - mBehaviourSpinner = findViewById(R.id.upload_files_spinner_behaviour); - List behaviours = new ArrayList<>(); behaviours.add(getString(R.string.uploader_upload_files_behaviour_move_to_nextcloud_folder, themeUtils.getDefaultDisplayNameForRootFolder(this))); @@ -207,13 +202,13 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList ArrayAdapter behaviourAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, behaviours); behaviourAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - mBehaviourSpinner.setAdapter(behaviourAdapter); - mBehaviourSpinner.setSelection(localBehaviour); + binding.uploadFilesSpinnerBehaviour.setAdapter(behaviourAdapter); + binding.uploadFilesSpinnerBehaviour.setSelection(localBehaviour); // setup the toolbar setupToolbar(); - findViewById(R.id.sort_list_button_group).setVisibility(View.VISIBLE); - findViewById(R.id.switch_grid_view_button).setVisibility(View.GONE); + binding.uploadFilesToolbar.sortListButtonGroup.setVisibility(View.VISIBLE); + binding.uploadFilesToolbar.switchGridViewButton.setVisibility(View.GONE); // Action bar setup ActionBar actionBar = getSupportActionBar(); @@ -223,7 +218,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList actionBar.setDisplayHomeAsUpEnabled(mCurrentDir != null); actionBar.setDisplayShowTitleEnabled(false); - themeToolbarUtils.tintBackButton(actionBar, this); + viewThemeUtils.files.themeActionBar(this, actionBar); } showToolbarSpinner(); @@ -261,7 +256,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList } private void requestPermissions() { - PermissionUtil.requestExternalStoragePermission(this, themeSnackbarUtils, true); + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true); } public void showToolbarSpinner() { @@ -294,11 +289,10 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList setSelectAllMenuItem(selectAll, mSelectAll); } - int fontColor = themeColorUtils.appBarPrimaryFontColor(this); final MenuItem item = menu.findItem(R.id.action_search); mSearchView = (SearchView) MenuItemCompat.getActionView(item); - themeToolbarUtils.themeSearchView(mSearchView, this); - themeDrawableUtils.tintDrawable(menu.findItem(R.id.action_choose_storage_path).getIcon(), fontColor); + viewThemeUtils.androidx.themeToolbarSearchView(mSearchView); + viewThemeUtils.platform.tintTextDrawable(this, menu.findItem(R.id.action_choose_storage_path).getIcon()); mSearchView.setOnSearchClickListener(v -> mToolbarSpinner.setVisibility(View.GONE)); @@ -456,7 +450,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList private void updateUploadButtonActive() { final boolean anySelected = mFileListFragment.getCheckedFilesCount() > 0; - uploadButton.setEnabled(anySelected || mLocalFolderPickerMode); + binding.uploadFilesBtnUpload.setEnabled(anySelected || mLocalFolderPickerMode); } private void setSelectAllMenuItem(MenuItem selectAll, boolean checked) { @@ -466,7 +460,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList selectAll.setIcon(R.drawable.ic_select_none); } else { selectAll.setIcon( - themeDrawableUtils.tintDrawable(R.drawable.ic_select_all, themeColorUtils.primaryColor(this))); + viewThemeUtils.platform.tintPrimaryDrawable(this, R.drawable.ic_select_all)); } updateUploadButtonActive(); } @@ -508,7 +502,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList data.putExtra(LOCAL_BASE_PATH, mCurrentDir.getAbsolutePath()); // set result code - switch (mBehaviourSpinner.getSelectedItemPosition()) { + switch (binding.uploadFilesSpinnerBehaviour.getSelectedItemPosition()) { case 0: // move to nextcloud folder setResult(RESULT_OK_AND_MOVE, data); break; @@ -527,7 +521,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList } // store behaviour - preferences.setUploaderBehaviour(mBehaviourSpinner.getSelectedItemPosition()); + preferences.setUploaderBehaviour(binding.uploadFilesSpinnerBehaviour.getSelectedItemPosition()); } finish(); @@ -576,16 +570,16 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList private void checkWritableFolder(File folder) { boolean canWriteIntoFolder = folder.canWrite(); - mBehaviourSpinner.setEnabled(canWriteIntoFolder); + binding.uploadFilesSpinnerBehaviour.setEnabled(canWriteIntoFolder); TextView textView = findViewById(R.id.upload_files_upload_files_behaviour_text); if (canWriteIntoFolder) { textView.setText(getString(R.string.uploader_upload_files_behaviour)); int localBehaviour = preferences.getUploaderBehaviour(); - mBehaviourSpinner.setSelection(localBehaviour); + binding.uploadFilesSpinnerBehaviour.setSelection(localBehaviour); } else { - mBehaviourSpinner.setSelection(1); + binding.uploadFilesSpinnerBehaviour.setSelection(1); textView.setText(new StringBuilder().append(getString(R.string.uploader_upload_files_behaviour)) .append(' ') .append(getString(R.string.uploader_upload_files_behaviour_not_writable)) @@ -647,7 +641,7 @@ public class UploadFilesActivity extends DrawerActivity implements LocalFileList finish(); } else { new CheckAvailableSpaceTask(this, mFileListFragment.getCheckedFilePaths()) - .execute(mBehaviourSpinner.getSelectedItemPosition() == 0); + .execute(binding.uploadFilesSpinnerBehaviour.getSelectedItemPosition() == 0); } } else { requestPermissions(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java index e9c4827c35..7ef10d7fa9 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadListActivity.java @@ -56,6 +56,7 @@ import com.owncloud.android.operations.CheckCurrentCredentialsOperation; import com.owncloud.android.ui.adapter.UploadListAdapter; import com.owncloud.android.ui.decoration.MediaGridItemDecoration; import com.owncloud.android.utils.FilesSyncHelper; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -99,6 +100,9 @@ public class UploadListActivity extends FileActivity { @Inject LocalBroadcastManager localBroadcastManager; + @Inject + ViewThemeUtils viewThemeUtils; + private UploadListLayoutBinding binding; public static Intent createIntent(OCFile file, User user, Integer flag, Context context) { @@ -155,9 +159,7 @@ public class UploadListActivity extends FileActivity { connectivityService, powerManagementService, clock, - themeColorUtils, - themeDrawableUtils, - themeBarUtils); + viewThemeUtils); final GridLayoutManager lm = new GridLayoutManager(this, 1); uploadListAdapter.setLayoutManager(lm); @@ -167,7 +169,7 @@ public class UploadListActivity extends FileActivity { binding.list.setLayoutManager(lm); binding.list.setAdapter(uploadListAdapter); - themeLayoutUtils.colorSwipeRefreshLayout(this, swipeListRefreshLayout); + viewThemeUtils.androidx.themeSwipeRefreshLayout(swipeListRefreshLayout); swipeListRefreshLayout.setOnRefreshListener(this::refresh); loadItems(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java index 14692a72dd..760a843d30 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UserInfoActivity.java @@ -27,7 +27,6 @@ package com.owncloud.android.ui.activity; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.Bundle; @@ -61,6 +60,7 @@ import com.owncloud.android.ui.dialog.AccountRemovalConfirmationDialog; import com.owncloud.android.ui.events.TokenPushEvent; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.PushUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -70,13 +70,11 @@ import java.util.List; import javax.inject.Inject; -import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.core.content.res.ResourcesCompat; -import androidx.core.graphics.drawable.DrawableCompat; import androidx.fragment.app.FragmentManager; import androidx.lifecycle.Lifecycle; import androidx.recyclerview.widget.RecyclerView; @@ -134,11 +132,10 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowHomeEnabled(true); - themeToolbarUtils.tintBackButton(actionBar, this); + viewThemeUtils.files.themeActionBar(this, actionBar); } - binding.userinfoList.setAdapter( - new UserInfoAdapter(null, themeColorUtils.primaryColor(getAccount(), true, this))); + binding.userinfoList.setAdapter(new UserInfoAdapter(null, viewThemeUtils)); if (userInfo != null) { populateUserInfoUi(userInfo); @@ -207,21 +204,23 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { if (backgroundImageView != null) { String background = getStorageManager().getCapability(user.getAccountName()).getServerBackground(); - int primaryColor = themeColorUtils.primaryColor(getAccount(), false, this); if (URLUtil.isValidUrl(background)) { // background image SimpleTarget target = new SimpleTarget() { @Override public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) { - Drawable[] drawables = {new ColorDrawable(primaryColor), resource}; + Drawable[] drawables = { + viewThemeUtils.platform.getPrimaryColorDrawable(backgroundImageView.getContext()), + resource}; LayerDrawable layerDrawable = new LayerDrawable(drawables); backgroundImageView.setImageDrawable(layerDrawable); } @Override public void onLoadFailed(Exception e, Drawable errorDrawable) { - Drawable[] drawables = {new ColorDrawable(primaryColor), + Drawable[] drawables = { + viewThemeUtils.platform.getPrimaryColorDrawable(backgroundImageView.getContext()), ResourcesCompat.getDrawable(getResources(), R.drawable.background, null)}; @@ -239,7 +238,8 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { .into(target); } else { // plain color - backgroundImageView.setImageDrawable(new ColorDrawable(primaryColor)); + backgroundImageView.setImageDrawable( + viewThemeUtils.platform.getPrimaryColorDrawable(backgroundImageView.getContext())); } } } @@ -255,8 +255,6 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { binding.userinfoIcon, this); - int tint = themeColorUtils.primaryColor(user.toPlatformAccount(), true, this); - if (!TextUtils.isEmpty(userInfo.getDisplayName())) { binding.userinfoFullName.setText(userInfo.getDisplayName()); } @@ -275,7 +273,7 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { binding.emptyList.emptyListView.setVisibility(View.GONE); if (binding.userinfoList.getAdapter() instanceof UserInfoAdapter) { - binding.userinfoList.setAdapter(new UserInfoAdapter(createUserInfoDetails(userInfo), tint)); + binding.userinfoList.setAdapter(new UserInfoAdapter(createUserInfoDetails(userInfo), viewThemeUtils)); } binding.loadingContent.setVisibility(View.GONE); @@ -373,7 +371,7 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { protected static class UserInfoAdapter extends RecyclerView.Adapter { protected List mDisplayList; - @ColorInt protected int mTintColor; + protected ViewThemeUtils viewThemeUtils; public static class ViewHolder extends RecyclerView.ViewHolder { protected UserInfoDetailsTableItemBinding binding; @@ -384,9 +382,9 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { } } - public UserInfoAdapter(List displayList, @ColorInt int tintColor) { + public UserInfoAdapter(List displayList, ViewThemeUtils viewThemeUtils) { mDisplayList = displayList == null ? new LinkedList<>() : displayList; - mTintColor = tintColor; + this.viewThemeUtils = viewThemeUtils; } public void setData(List displayList) { @@ -411,7 +409,7 @@ public class UserInfoActivity extends DrawerActivity implements Injectable { holder.binding.icon.setImageResource(item.icon); holder.binding.text.setText(item.text); holder.binding.icon.setContentDescription(item.iconContentDescription); - DrawableCompat.setTint(holder.binding.icon.getDrawable(), mTintColor); + viewThemeUtils.platform.colorImageView(holder.binding.icon); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ActivityAndVersionListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ActivityAndVersionListAdapter.java index 880a7f8737..12be88f1cc 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ActivityAndVersionListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ActivityAndVersionListAdapter.java @@ -33,15 +33,13 @@ import android.view.ViewGroup; import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.common.NextcloudClient; -import com.owncloud.android.R; import com.owncloud.android.databinding.VersionListItemBinding; import com.owncloud.android.lib.resources.activities.model.Activity; import com.owncloud.android.lib.resources.files.model.FileVersion; import com.owncloud.android.ui.interfaces.ActivityListInterface; import com.owncloud.android.ui.interfaces.VersionListInterface; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.Collections; import java.util.Date; @@ -61,16 +59,14 @@ public class ActivityAndVersionListAdapter extends ActivityListAdapter { ActivityListInterface activityListInterface, VersionListInterface.View versionListInterface, ClientFactory clientFactory, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils + ViewThemeUtils viewThemeUtils ) { super(context, currentAccountProvider, activityListInterface, clientFactory, true, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); this.versionListInterface = versionListInterface; } @@ -106,13 +102,7 @@ public class ActivityAndVersionListAdapter extends ActivityListAdapter { if (item instanceof Activity) { Activity activity = (Activity) item; - if (activity.getDatetime() != null) { - time = getHeaderDateString(context, activity.getDatetime().getTime()).toString(); - } else if (activity.getDate() != null) { - time = getHeaderDateString(context, activity.getDate().getTime()).toString(); - } else { - time = context.getString(R.string.date_unknown); - } + time = getHeaderDateString(context, activity.getDatetime().getTime()).toString(); } else { FileVersion version = (FileVersion) item; time = getHeaderDateString(context, version.getModifiedTimestamp()).toString(); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java index f70f901396..f14024737c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ActivityListAdapter.java @@ -72,8 +72,7 @@ import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.glide.CustomGlideStreamLoader; import com.owncloud.android.utils.svg.SvgBitmapTranscoder; import com.owncloud.android.utils.svg.SvgDecoder; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.InputStream; import java.util.ArrayList; @@ -100,8 +99,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter values; private boolean isDetailView; - private ThemeColorUtils themeColorUtils; - private ThemeDrawableUtils themeDrawableUtils; + private ViewThemeUtils viewThemeUtils; public ActivityListAdapter( Context context, @@ -109,8 +107,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter(); this.context = context; this.currentAccountProvider = currentAccountProvider; @@ -118,8 +115,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter activityItems, NextcloudClient client, boolean clear) { @@ -133,13 +129,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter 0) { + if (activity.getRichSubjectElement().getRichObjectList().size() > 0) { activityViewHolder.binding.list.setVisibility(View.VISIBLE); activityViewHolder.binding.list.removeAllViews(); @@ -287,14 +272,12 @@ public class ActivityListAdapter extends RecyclerView.Adapter. + */ + +package com.owncloud.android.ui.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.android.lib.resources.dashboard.DashboardWidget +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.network.ClientFactory +import com.nextcloud.client.widget.DashboardWidgetConfigurationInterface +import com.owncloud.android.databinding.WidgetListItemBinding + +class DashboardWidgetListAdapter( + val accountManager: UserAccountManager, + val clientFactory: ClientFactory, + val context: Context, + private val dashboardWidgetConfigurationInterface: DashboardWidgetConfigurationInterface +) : + RecyclerView.Adapter() { + private var widgets = emptyList() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return WidgetListItemViewHolder( + WidgetListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), + accountManager, + clientFactory, + context + ) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val widgetListItemViewHolder = holder as WidgetListItemViewHolder + + widgetListItemViewHolder.bind(widgets[position], dashboardWidgetConfigurationInterface) + } + + override fun getItemCount(): Int { + return widgets.size + } + + @SuppressLint("NotifyDataSetChanged") + fun setWidgetList(list: Map?) { + widgets = list?.map { (_, value) -> value }?.sortedBy { it.order } ?: emptyList() + notifyDataSetChanged() + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt index d3882307a8..6425ddc767 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryAdapter.kt @@ -49,8 +49,7 @@ import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileSortOrder import com.owncloud.android.utils.FileStorageUtils import com.owncloud.android.utils.MimeTypeUtil -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import me.zhanghai.android.fastscroll.PopupTextProvider import java.util.Calendar import java.util.Date @@ -62,8 +61,7 @@ class GalleryAdapter( ocFileListFragmentInterface: OCFileListFragmentInterface, preferences: AppPreferences, transferServiceGetter: ComponentsGetter, - themeColorUtils: ThemeColorUtils, - themeDrawableUtils: ThemeDrawableUtils + viewThemeUtils: ViewThemeUtils ) : SectionedRecyclerViewAdapter(), CommonOCFileListAdapterInterface, PopupTextProvider { var files: List = mutableListOf() private val ocFileListDelegate: OCFileListDelegate @@ -83,8 +81,7 @@ class GalleryAdapter( transferServiceGetter, showMetadata = false, showShareAvatar = false, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java index 07c24e3a09..4c03f82e3d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java @@ -35,8 +35,7 @@ import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; -import com.owncloud.android.utils.theme.ThemeAvatarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import androidx.annotation.NonNull; import androidx.core.content.res.ResourcesCompat; @@ -45,8 +44,7 @@ import androidx.recyclerview.widget.RecyclerView; class LinkShareViewHolder extends RecyclerView.ViewHolder { private FileDetailsShareLinkShareItemBinding binding; private Context context; - private ThemeColorUtils themeColorUtils; - private ThemeAvatarUtils themeAvatarUtils; + private ViewThemeUtils viewThemeUtils; public LinkShareViewHolder(@NonNull View itemView) { super(itemView); @@ -54,13 +52,11 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder { public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding, Context context, - ThemeColorUtils themeColorUtils, - ThemeAvatarUtils themeAvatarUtils) { + final ViewThemeUtils viewThemeUtils) { this(binding.getRoot()); this.binding = binding; this.context = context; - this.themeColorUtils = themeColorUtils; - this.themeAvatarUtils = themeAvatarUtils; + this.viewThemeUtils = viewThemeUtils; } public void bind(OCShare publicShare, ShareeListAdapterListener listener) { @@ -83,7 +79,7 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder { binding.name.setText(R.string.share_link); } - themeAvatarUtils.colorIconImageViewWithBackground(binding.icon, context, themeColorUtils); + viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); } String permissionName = SharingMenuHelper.getPermissionName(context, publicShare); @@ -98,6 +94,7 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder { if (!TextUtils.isEmpty(permissionName)) { binding.permissionName.setText(permissionName); binding.permissionName.setVisibility(View.VISIBLE); + viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName); } else { binding.permissionName.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index f716dd4e64..0f3d047cd8 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -40,8 +40,7 @@ import com.owncloud.android.ui.interfaces.LocalFileListFragmentInterface; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.ArrayList; @@ -73,8 +72,7 @@ public class LocalFileListAdapter extends RecyclerView.Adapter checkedFiles; - private ThemeColorUtils themeColorUtils; - private ThemeDrawableUtils themeDrawableUtils; + private ViewThemeUtils viewThemeUtils; private static final int VIEWTYPE_ITEM = 0; private static final int VIEWTYPE_FOOTER = 1; @@ -85,15 +83,13 @@ public class LocalFileListAdapter extends RecyclerView.Adapter(); - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; swapDirectory(directory); } @@ -181,9 +177,9 @@ public class LocalFileListAdapter extends RecyclerView.Adapter localFileListFragmentInterface .onItemClicked(finalFile)); @@ -231,12 +227,9 @@ public class LocalFileListAdapter extends RecyclerView.Adapter notificationsList; private final OwnCloudClient client; private final NotificationsActivity notificationsActivity; - private final ThemeColorUtils themeColorUtils; - private final ThemeButtonUtils themeButtonUtils; + private final ViewThemeUtils viewThemeUtils; public NotificationListAdapter(OwnCloudClient client, NotificationsActivity notificationsActivity, - ThemeColorUtils themeColorUtils, - ThemeButtonUtils themeButtonUtils) { + ViewThemeUtils viewThemeUtils) { this.notificationsList = new ArrayList<>(); this.client = client; this.notificationsActivity = notificationsActivity; - this.themeColorUtils = themeColorUtils; - this.themeButtonUtils = themeButtonUtils; + this.viewThemeUtils = viewThemeUtils; foregroundColorSpanBlack = new ForegroundColorSpan( notificationsActivity.getResources().getColor(R.color.text_color)); } @@ -147,12 +144,12 @@ public class NotificationListAdapter extends RecyclerView.Adapter overflowActions = new ArrayList<>(); - + if (notification.getActions().size() > 2) { - for (Action action: notification.getActions()) { + for (Action action : notification.getActions()) { if (action.primary) { - button = new MaterialButton(notificationsActivity); + final MaterialButton button = new MaterialButton(notificationsActivity); button.setAllCaps(false); button.setText(action.label); @@ -215,29 +208,27 @@ public class NotificationListAdapter extends RecyclerView.Adapter { - PopupMenu popup = new PopupMenu(notificationsActivity, finalButton); + moreButton.setOnClickListener(v -> { + PopupMenu popup = new PopupMenu(notificationsActivity, moreButton); for (Action action : overflowActions) { popup.getMenu().add(action.label).setOnMenuItemClickListener(item -> { @@ -255,24 +246,23 @@ public class NotificationListAdapter extends RecyclerView.Adapter requestBuilder = Glide.with(notificationsActivity) + private void downloadIcon(String icon, ImageView itemViewType, Context context) { + GenericRequestBuilder requestBuilder = Glide.with(notificationsActivity) .using(Glide.buildStreamModelLoader(Uri.class, notificationsActivity), InputStream.class) .from(Uri.class) .as(SVG.class) - .transcode(new SvgDrawableTranscoder(), PictureDrawable.class) + .transcode(new SvgDrawableTranscoder(context), Drawable.class) .sourceEncoder(new StreamEncoder()) .cacheDecoder(new FileToStreamDecoder<>(new SvgDecoder())) .decoder(new SvgDecoder()) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 2d6b6440ff..592aba8e61 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -31,7 +31,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.ContentValues; import android.content.res.Resources; -import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; @@ -76,9 +75,7 @@ import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.theme.CapabilityUtils; -import com.owncloud.android.utils.theme.ThemeAvatarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.io.IOException; @@ -131,9 +128,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter ocFileListFragmentInterface.onHeaderClicked()); } else { ListGridImageViewHolder gridViewHolder = (ListGridImageViewHolder) holder; @@ -416,7 +400,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter ocFileListFragmentInterface.onShareIconClick(file)); } else { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt index b15bfd251c..d783741ac1 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt @@ -34,8 +34,7 @@ import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.ui.fragment.SearchType import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils @Suppress("LongParameterList", "TooManyFunctions") class OCFileListDelegate( @@ -49,8 +48,7 @@ class OCFileListDelegate( private val transferServiceGetter: ComponentsGetter, private val showMetadata: Boolean, private var showShareAvatar: Boolean, - private var themeColorUtils: ThemeColorUtils, - private var themeDrawableUtils: ThemeDrawableUtils + private var viewThemeUtils: ViewThemeUtils ) { private val checkedFiles: MutableSet = HashSet() private var highlightedItem: OCFile? = null @@ -106,8 +104,7 @@ class OCFileListDelegate( context, gridViewHolder.shimmerThumbnail, preferences, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) // item layout + click listeners bindGridItemLayout(file, gridViewHolder) @@ -162,10 +159,7 @@ class OCFileListDelegate( .getColor(R.color.selected_item_background) ) gridViewHolder.checkbox.setImageDrawable( - themeDrawableUtils.tintDrawable( - R.drawable.ic_checkbox_marked, - themeColorUtils.primaryColor(context) - ) + viewThemeUtils.platform.tintPrimaryDrawable(context, R.drawable.ic_checkbox_marked) ) } else { gridViewHolder.itemLayout.setBackgroundColor(context.resources.getColor(R.color.bg_default)) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt index 36e54ee8ae..ea19b15476 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/QuickSharingPermissionsAdapter.kt @@ -27,15 +27,17 @@ import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding import com.owncloud.android.datamodel.QuickPermissionModel +import com.owncloud.android.utils.theme.ViewThemeUtils class QuickSharingPermissionsAdapter( private val quickPermissionList: MutableList, - private val onPermissionChangeListener: QuickSharingPermissionViewHolder.OnPermissionChangeListener + private val onPermissionChangeListener: QuickSharingPermissionViewHolder.OnPermissionChangeListener, + private val viewThemeUtils: ViewThemeUtils ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { val binding = ItemQuickSharePermissionsBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return QuickSharingPermissionViewHolder(binding, binding.root, onPermissionChangeListener) + return QuickSharingPermissionViewHolder(binding, binding.root, onPermissionChangeListener, viewThemeUtils) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { @@ -51,7 +53,8 @@ class QuickSharingPermissionsAdapter( class QuickSharingPermissionViewHolder( val binding: ItemQuickSharePermissionsBinding, itemView: View, - val onPermissionChangeListener: OnPermissionChangeListener + val onPermissionChangeListener: OnPermissionChangeListener, + private val viewThemeUtils: ViewThemeUtils ) : RecyclerView .ViewHolder(itemView) { @@ -59,6 +62,7 @@ class QuickSharingPermissionsAdapter( fun bindData(quickPermissionModel: QuickPermissionModel) { binding.tvQuickShareName.text = quickPermissionModel.permissionName if (quickPermissionModel.isSelected) { + viewThemeUtils.platform.colorImageView(binding.tvQuickShareCheckIcon) binding.tvQuickShareCheckIcon.visibility = View.VISIBLE } else { binding.tvQuickShareCheckIcon.visibility = View.INVISIBLE diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/RichDocumentsTemplateAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/RichDocumentsTemplateAdapter.java index 82413ca364..79dbf908b4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/RichDocumentsTemplateAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/RichDocumentsTemplateAdapter.java @@ -36,7 +36,7 @@ import com.owncloud.android.datamodel.Template; import com.owncloud.android.ui.dialog.ChooseRichDocumentsTemplateDialogFragment; import com.owncloud.android.utils.NextcloudServer; import com.owncloud.android.utils.glide.CustomGlideStreamLoader; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -56,8 +56,7 @@ public class RichDocumentsTemplateAdapter extends RecyclerView.Adapter shares, ShareeListAdapterListener listener, String userId, User user, - ThemeColorUtils themeColorUtils, - ThemeAvatarUtils themeAvatarUtils) { + final ViewThemeUtils viewThemeUtils) { this.fileActivity = fileActivity; this.shares = shares; this.listener = listener; this.userId = userId; this.user = user; - this.themeColorUtils = themeColorUtils; - this.themeAvatarUtils = themeAvatarUtils; + this.viewThemeUtils = viewThemeUtils; avatarRadiusDimension = fileActivity.getResources().getDimension(R.dimen.user_icon_radius); @@ -101,8 +97,7 @@ public class ShareeListAdapter extends RecyclerView.Adapter(); this.light = light; this.hideItems = true; - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; this.thumbnailThreadPool = Executors.newCachedThreadPool(); shouldShowHeadersForEmptySections(true); @@ -348,8 +344,7 @@ public class SyncedFolderAdapter extends SectionedRecyclerViewAdapter(templateList.getTemplates().values()).get(position), themeColorUtils, themeDrawableUtils); + holder.setData(new ArrayList<>(templateList.getTemplates().values()).get(position)); } public void setTemplateList(TemplateList templateList) { @@ -125,6 +116,7 @@ public class TemplateAdapter extends RecyclerView.Adapter asyncTasks = new ArrayList<>(); - private final ThemeColorUtils themeColorUtils; - private final ThemeDrawableUtils themeDrawableUtils; + private final ViewThemeUtils viewThemeUtils; public TrashbinListAdapter( TrashbinActivityInterface trashbinActivityInterface, @@ -79,8 +77,7 @@ public class TrashbinListAdapter extends RecyclerView.Adapter(); this.trashbinActivityInterface = trashbinActivityInterface; @@ -88,8 +85,7 @@ public class TrashbinListAdapter extends RecyclerView.Adapter trashbinFiles, boolean clear) { @@ -226,8 +222,7 @@ public class TrashbinListAdapter extends RecyclerView.Adapter ResourcesCompat.getDrawable(context.resources, R.drawable.ic_deck, null) else -> - MimeTypeUtil.getFileTypeIcon(mimetype, entry.title, context, themeColorUtils, themeDrawableUtils) + MimeTypeUtil.getFileTypeIcon(mimetype, entry.title, context, viewThemeUtils) } } - val color = themeColorUtils.primaryColor(context) - drawable!!.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP) - return drawable + return viewThemeUtils.platform.tintPrimaryDrawable(context, drawable)!! } private inner class RoundIfNeededListener(private val entry: SearchResultEntry) : diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt index 5f1d557144..bc5651f49a 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchListAdapter.kt @@ -40,8 +40,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.ThumbnailsCacheManager.InitDiskCacheTask import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils /** * This Adapter populates a SectionedRecyclerView with search results by unified search @@ -53,8 +52,7 @@ class UnifiedSearchListAdapter( private val user: User, private val clientFactory: ClientFactory, private val context: Context, - private val themeColorUtils: ThemeColorUtils, - private val themeDrawableUtils: ThemeDrawableUtils + private val viewThemeUtils: ViewThemeUtils ) : SectionedRecyclerViewAdapter() { companion object { private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE @@ -71,7 +69,7 @@ class UnifiedSearchListAdapter( parent, false ) - UnifiedSearchHeaderViewHolder(binding, themeColorUtils, context) + UnifiedSearchHeaderViewHolder(binding, viewThemeUtils, context) } VIEW_TYPE_FOOTER -> { val binding = UnifiedSearchFooterBinding.inflate( @@ -94,8 +92,7 @@ class UnifiedSearchListAdapter( storageManager, listInterface, context, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) } VIEW_TYPE_EMPTY -> { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index 2c76229bd8..d2702f4b3b 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -24,7 +24,6 @@ package com.owncloud.android.ui.adapter; -import android.accounts.Account; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; @@ -65,9 +64,7 @@ import com.owncloud.android.ui.activity.ConflictsResolveActivity; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeBarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.Arrays; @@ -90,9 +87,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter toggleSectionExpanded(section)); @@ -172,9 +167,7 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter> data, @@ -61,15 +59,13 @@ public class UploaderAdapter extends SimpleAdapter { int[] to, FileDataStorageManager storageManager, User user, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { super(context, data, resource, from, to); this.user = user; mStorageManager = storageManager; mContext = context; inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -109,11 +105,9 @@ public class UploaderAdapter extends SimpleAdapter { file.isSharedViaLink(), file.isEncrypted(), file.isGroupFolder(), - user, file.getMountType(), mContext, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); fileIcon.setImageDrawable(icon); } else { // get Thumbnail if file is image @@ -148,10 +142,8 @@ public class UploaderAdapter extends SimpleAdapter { } else { final Drawable icon = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), - user, mContext, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); fileIcon.setImageDrawable(icon); } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java index 4c08d891d8..4b75827d3c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java @@ -26,6 +26,7 @@ package com.owncloud.android.ui.adapter; +import android.content.Context; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.view.LayoutInflater; @@ -40,10 +41,8 @@ import com.owncloud.android.databinding.AccountActionBinding; import com.owncloud.android.databinding.AccountItemBinding; import com.owncloud.android.lib.common.OwnCloudAccount; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.ui.activity.BaseActivity; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -59,7 +58,7 @@ public class UserListAdapter extends RecyclerView.Adapter values; private Listener accountListAdapterListener; private final UserAccountManager accountManager; @@ -69,17 +68,17 @@ public class UserListAdapter extends RecyclerView.Adapter values, ClickListener clickListener, boolean showAddAccount, boolean showDotsMenu, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + boolean highlightCurrentlyActiveAccount, + final ViewThemeUtils viewThemeUtils) { this.context = context; this.accountManager = accountManager; this.values = values; @@ -90,8 +89,8 @@ public class UserListAdapter extends RecyclerView.Adapter. + */ + +package com.owncloud.android.ui.adapter + +import android.content.Context +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.request.animation.GlideAnimation +import com.bumptech.glide.request.target.SimpleTarget +import com.nextcloud.android.lib.resources.dashboard.DashboardWidget +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.network.ClientFactory +import com.nextcloud.client.widget.DashboardWidgetConfigurationInterface +import com.owncloud.android.R +import com.owncloud.android.databinding.WidgetListItemBinding +import com.owncloud.android.utils.DisplayUtils + +class WidgetListItemViewHolder( + val binding: WidgetListItemBinding, + val accountManager: UserAccountManager, + val clientFactory: ClientFactory, + val context: Context +) : + RecyclerView.ViewHolder(binding.root) { + fun bind( + dashboardWidget: DashboardWidget, + dashboardWidgetConfigurationInterface: DashboardWidgetConfigurationInterface + ) { + binding.layout.setOnClickListener { dashboardWidgetConfigurationInterface.onItemClicked(dashboardWidget) } + + val target = object : SimpleTarget() { + override fun onResourceReady(resource: Drawable?, glideAnimation: GlideAnimation?) { + binding.icon.setImageDrawable(resource) + binding.icon.setColorFilter(context.getColor(R.color.dark), PorterDuff.Mode.SRC_ATOP) + } + + override fun onLoadFailed(e: java.lang.Exception?, errorDrawable: Drawable?) { + super.onLoadFailed(e, errorDrawable) + binding.icon.setImageDrawable(errorDrawable) + binding.icon.setColorFilter(context.getColor(R.color.dark), PorterDuff.Mode.SRC_ATOP) + } + } + + DisplayUtils.downloadIcon( + accountManager, + clientFactory, + context, + dashboardWidget.iconUrl, + target, + R.drawable.ic_dashboard + ) + binding.name.text = dashboardWidget.title + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/asynctasks/RetrieveHoverCardAsyncTask.java b/app/src/main/java/com/owncloud/android/ui/asynctasks/RetrieveHoverCardAsyncTask.java index 0b9cbd5241..fa30f18941 100644 --- a/app/src/main/java/com/owncloud/android/ui/asynctasks/RetrieveHoverCardAsyncTask.java +++ b/app/src/main/java/com/owncloud/android/ui/asynctasks/RetrieveHoverCardAsyncTask.java @@ -32,8 +32,7 @@ import com.owncloud.android.R; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.ui.fragment.ProfileBottomSheetDialog; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.lang.ref.WeakReference; @@ -45,21 +44,18 @@ public class RetrieveHoverCardAsyncTask extends AsyncTask private final String userId; private final WeakReference activityWeakReference; private final ClientFactory clientFactory; - private final ThemeColorUtils themeColorUtils; - private final ThemeDrawableUtils themeDrawableUtils; + private final ViewThemeUtils viewThemeUtils; public RetrieveHoverCardAsyncTask(User user, String userId, FragmentActivity activity, ClientFactory clientFactory, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { this.user = user; this.userId = userId; this.activityWeakReference = new WeakReference<>(activity); this.clientFactory = clientFactory; - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -84,7 +80,11 @@ public class RetrieveHoverCardAsyncTask extends AsyncTask if (activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { if (hoverCard.getActions().size() > 0) { - new ProfileBottomSheetDialog(activity, user, hoverCard, themeColorUtils, themeDrawableUtils).show(); + new ProfileBottomSheetDialog(activity, + user, + hoverCard, + viewThemeUtils) + .show(); } else { DisplayUtils.showSnackMessage(activity, R.string.no_actions); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountChooserInterface.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountChooserInterface.kt new file mode 100644 index 0000000000..f38f37d7a6 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountChooserInterface.kt @@ -0,0 +1,29 @@ +/* + * + * Nextcloud Android client application + * + * @author Tobias Kaminsky + * Copyright (C) 2022 Tobias Kaminsky + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.ui.dialog + +import com.nextcloud.client.account.User + +interface AccountChooserInterface { + fun onAccountChosen(user: User) +} diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.java index be264a9a7c..f2863b1975 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalConfirmationDialog.java @@ -25,12 +25,12 @@ package com.owncloud.android.ui.dialog; import android.app.Dialog; import android.os.Bundle; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.BackgroundJobManager; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -43,8 +43,7 @@ public class AccountRemovalConfirmationDialog extends DialogFragment implements private static final String KEY_USER = "USER"; @Inject BackgroundJobManager backgroundJobManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; private User user; public static AccountRemovalConfirmationDialog newInstance(User user) { @@ -69,22 +68,24 @@ public class AccountRemovalConfirmationDialog extends DialogFragment implements AlertDialog alertDialog = (AlertDialog) getDialog(); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(requireActivity(), R.style.Theme_ownCloud_Dialog) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity()) .setTitle(R.string.delete_account) .setMessage(getResources().getString(R.string.delete_account_warning, user.getAccountName())) .setIcon(R.drawable.ic_warning) .setPositiveButton(R.string.common_ok, (dialogInterface, i) -> backgroundJobManager.startAccountRemovalJob(user.getAccountName(), false)) - .setNeutralButton(R.string.common_cancel, null) - .create(); + .setNeutralButton(R.string.common_cancel, null); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder); + + return builder.create(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java index fa5a1ec24e..8bb336bf45 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.java @@ -35,6 +35,7 @@ import android.view.Window; import android.view.WindowManager.LayoutParams; import android.widget.Button; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.collect.Sets; import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; @@ -59,9 +60,7 @@ import com.owncloud.android.ui.adapter.RichDocumentsTemplateAdapter; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.NextcloudServer; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -89,9 +88,7 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im @Inject CurrentAccountProvider currentAccount; @Inject ClientFactory clientFactory; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; @Inject FileDataStorageManager fileDataStorageManager; private RichDocumentsTemplateAdapter adapter; private OCFile parentFolder; @@ -123,9 +120,8 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im AlertDialog alertDialog = (AlertDialog) getDialog(); positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - positiveButton, - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(positiveButton, + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); positiveButton.setOnClickListener(this); positiveButton.setEnabled(false); @@ -165,10 +161,7 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im View view = binding.getRoot(); binding.filename.requestFocus(); - themeTextInputUtils.colorTextInput(binding.filenameContainer, - binding.filename, - themeColorUtils.primaryColor(getContext()), - themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.material.colorTextInputLayout(binding.filenameContainer); Type type = Type.valueOf(arguments.getString(ARG_TYPE)); new FetchTemplateTask(this, client).execute(type); @@ -180,7 +173,7 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im getContext(), currentAccount, clientFactory, - themeColorUtils); + viewThemeUtils); binding.list.setAdapter(adapter); binding.filename.addTextChangedListener(new TextWatcher() { @@ -218,11 +211,14 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im }); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(activity); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity); builder.setView(view) .setPositiveButton(R.string.create, null) .setNeutralButton(R.string.common_cancel, null) .setTitle(getTitle(type)); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(activity, builder); + Dialog dialog = builder.create(); Window window = dialog.getWindow(); @@ -323,7 +319,7 @@ public class ChooseRichDocumentsTemplateDialogFragment extends DialogFragment im Template template, String path, User user - ) { + ) { this.client = client; this.chooseTemplateDialogFragmentWeakReference = new WeakReference<>(chooseTemplateDialogFragment); this.template = template; diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt index 32a0f2e22d..9304d70bcb 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseTemplateDialogFragment.kt @@ -35,6 +35,7 @@ import android.widget.Button import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.GridLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.android.lib.resources.directediting.DirectEditingCreateFileRemoteOperation import com.nextcloud.android.lib.resources.directediting.DirectEditingObtainListOfTemplatesRemoteOperation import com.nextcloud.client.account.CurrentAccountProvider @@ -58,10 +59,7 @@ import com.owncloud.android.ui.activity.TextEditorWebView import com.owncloud.android.ui.adapter.TemplateAdapter import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.FileStorageUtils -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils -import com.owncloud.android.utils.theme.ThemeTextInputUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import java.lang.ref.WeakReference import javax.inject.Inject @@ -78,21 +76,12 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem @Inject lateinit var currentAccount: CurrentAccountProvider - @Inject - lateinit var themeColorUtils: ThemeColorUtils - - @Inject - lateinit var themeDrawableUtils: ThemeDrawableUtils - - @Inject - lateinit var themeButtonUtils: ThemeButtonUtils - - @Inject - lateinit var themeTextInputUtils: ThemeTextInputUtils - @Inject lateinit var fileDataStorageManager: FileDataStorageManager + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + private var adapter: TemplateAdapter? = null private var parentFolder: OCFile? = null private var title: String? = null @@ -111,8 +100,7 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem val alertDialog = dialog as AlertDialog val button = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) - themeButtonUtils.themeBorderlessButton( - themeColorUtils, + viewThemeUtils.platform.colorTextButtons( button, alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) ) @@ -144,11 +132,8 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem val view: View = binding.root binding.filename.requestFocus() - themeTextInputUtils.colorTextInput( - binding.filenameContainer, - binding.filename, - themeColorUtils.primaryColor(context), - themeColorUtils.primaryAccentColor(context) + viewThemeUtils.material.colorTextInputLayout( + binding.filenameContainer ) binding.filename.addTextChangedListener(object : TextWatcher { @@ -173,17 +158,19 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem context, currentAccount, clientFactory, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) binding.list.adapter = adapter // Build the dialog - val builder = AlertDialog.Builder(activity) + val builder = MaterialAlertDialogBuilder(activity) builder.setView(view) .setPositiveButton(R.string.create, null) .setNeutralButton(R.string.common_cancel, null) .setTitle(title) + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.list.context, builder) + val dialog: Dialog = builder.create() val window = dialog.window window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java index 53f8fbe751..7c0c19001d 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java @@ -20,10 +20,10 @@ import android.app.Activity; import android.app.Dialog; import android.os.Bundle; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -44,8 +44,8 @@ public class ConfirmationDialogFragment extends DialogFragment implements Inject public static final String FTAG_CONFIRMATION = "CONFIRMATION_FRAGMENT"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; + private ConfirmationDialogFragmentListener mListener; @@ -84,10 +84,11 @@ public class ConfirmationDialogFragment extends DialogFragment implements Inject AlertDialog alertDialog = (AlertDialog) getDialog(); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + if(alertDialog != null) { + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + } } public void setOnConfirmationListener(ConfirmationDialogFragmentListener listener) { @@ -120,7 +121,7 @@ public class ConfirmationDialogFragment extends DialogFragment implements Inject messageArguments = new String[]{}; } - AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.Theme_ownCloud_Dialog) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity) .setIcon(R.drawable.ic_warning) .setIconAttribute(android.R.attr.alertDialogIcon) .setMessage(String.format(getString(messageId), messageArguments)); @@ -155,6 +156,9 @@ public class ConfirmationDialogFragment extends DialogFragment implements Inject dialog.dismiss(); }); } + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(activity, builder); + return builder.create(); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java index 8ace741f72..47ca18a5be 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java @@ -29,6 +29,7 @@ import android.view.View; import android.widget.Button; import android.widget.Toast; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; @@ -39,10 +40,7 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.adapter.LocalFileListAdapter; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeCheckableUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.ArrayList; @@ -72,10 +70,7 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable private User user; private final List asyncTasks = new ArrayList<>(); private Button positiveButton; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeCheckableUtils themeCheckableUtils; + @Inject ViewThemeUtils viewThemeUtils; private static final String KEY_NEW_FILE = "file"; private static final String KEY_EXISTING_FILE = "ocfile"; @@ -123,9 +118,8 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable } positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - positiveButton, - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(positiveButton, + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); positiveButton.setEnabled(false); } @@ -161,12 +155,11 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable // Inflate the layout for the dialog binding = ConflictResolveDialogBinding.inflate(requireActivity().getLayoutInflater()); - themeCheckableUtils.tintCheckbox(themeColorUtils.primaryColor(getContext()), - binding.newCheckbox, - binding.existingCheckbox); + viewThemeUtils.platform.themeCheckbox(binding.newCheckbox); + viewThemeUtils.platform.themeCheckbox(binding.existingCheckbox); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity()); builder.setView(binding.getRoot()) .setPositiveButton(R.string.common_ok, (dialog, which) -> { if (listener != null) { @@ -201,8 +194,7 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable LocalFileListAdapter.setThumbnail(newFile, binding.newThumbnail, getContext(), - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); // set info for existing file binding.existingSize.setText(DisplayUtils.bytesToHumanReadable(existingFile.getFileLength())); @@ -220,8 +212,7 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable getContext(), null, null, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); View.OnClickListener checkBoxClickListener = v -> positiveButton.setEnabled(binding.newCheckbox.isChecked() || binding.existingCheckbox.isChecked()); @@ -238,6 +229,8 @@ public class ConflictsResolveDialog extends DialogFragment implements Injectable positiveButton.setEnabled(binding.newCheckbox.isChecked() || binding.existingCheckbox.isChecked()); }); + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.existingFileContainer.getContext(), builder); + return builder.create(); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java index 3f00e82f2c..e095cfac98 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java @@ -33,6 +33,7 @@ import android.view.WindowManager.LayoutParams; import android.widget.Button; import android.widget.TextView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.collect.Sets; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; @@ -42,9 +43,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; import java.util.Set; @@ -67,10 +66,9 @@ public class CreateFolderDialogFragment public static final String CREATE_FOLDER_FRAGMENT = "CREATE_FOLDER_FRAGMENT"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; @Inject FileDataStorageManager fileDataStorageManager; + @Inject ViewThemeUtils viewThemeUtils; + private OCFile mParentFolder; private Button positiveButton; @@ -99,9 +97,8 @@ public class CreateFolderDialogFragment if (alertDialog != null) { positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - positiveButton, - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(positiveButton, + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); } } @@ -118,10 +115,7 @@ public class CreateFolderDialogFragment // Setup layout binding.userInput.setText(""); binding.userInput.requestFocus(); - themeTextInputUtils.colorTextInput(binding.userInputContainer, - binding.userInput, - themeColorUtils.primaryColor(getActivity()), - themeColorUtils.primaryAccentColor(getActivity())); + viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer); OCFile parentFolder = requireArguments().getParcelable(ARG_PARENT_FOLDER); List folderContent = fileDataStorageManager.getFolderContent(parentFolder, false); @@ -173,11 +167,14 @@ public class CreateFolderDialogFragment }); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity()); builder.setView(view) .setPositiveButton(R.string.folder_confirm_create, this) .setNeutralButton(R.string.common_cancel, this) .setTitle(R.string.uploader_info_dirname); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.getContext(), builder); + AlertDialog d = builder.create(); Window window = d.getWindow(); @@ -192,8 +189,8 @@ public class CreateFolderDialogFragment public void onClick(DialogInterface dialog, int which) { if (which == AlertDialog.BUTTON_POSITIVE) { String newFolderName = - ((TextView)(getDialog().findViewById(R.id.user_input))) - .getText().toString().trim(); + ((TextView) (getDialog().findViewById(R.id.user_input))) + .getText().toString().trim(); if (TextUtils.isEmpty(newFolderName)) { DisplayUtils.showSnackMessage(getActivity(), R.string.filename_empty); @@ -207,6 +204,7 @@ public class CreateFolderDialogFragment } String path = mParentFolder.getDecryptedRemotePath() + newFolderName + OCFile.PATH_SEPARATOR; + ((ComponentsGetter) getActivity()).getFileOperationsHelper().createFolder(path); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.java index 4c40e0711f..f1c16c6b49 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.java @@ -32,7 +32,7 @@ import android.widget.DatePicker; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.Calendar; @@ -54,7 +54,7 @@ public class ExpirationDatePickerDialogFragment /** Parameter constant for date chosen initially */ private static final String ARG_CHOSEN_DATE_IN_MILLIS = "CHOSEN_DATE_IN_MILLIS"; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; private OnExpiryDateListener onExpiryDateListener; /** @@ -83,9 +83,10 @@ public class ExpirationDatePickerDialogFragment final Dialog currentDialog = getDialog(); if (currentDialog != null) { final DatePickerDialog dialog = (DatePickerDialog) currentDialog; - dialog.getButton(DatePickerDialog.BUTTON_NEUTRAL).setTextColor(themeColorUtils.primaryColor(getContext(), true)); - dialog.getButton(DatePickerDialog.BUTTON_NEGATIVE).setTextColor(themeColorUtils.primaryColor(getContext(), true)); - dialog.getButton(DatePickerDialog.BUTTON_POSITIVE).setTextColor(themeColorUtils.primaryColor(getContext(), true)); + + viewThemeUtils.platform.colorTextButtons(dialog.getButton(DatePickerDialog.BUTTON_NEUTRAL), + dialog.getButton(DatePickerDialog.BUTTON_NEGATIVE), + dialog.getButton(DatePickerDialog.BUTTON_POSITIVE)); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java index 67b1f4e1c7..891249e9b0 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java @@ -29,7 +29,7 @@ import android.widget.ProgressBar; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -42,7 +42,7 @@ public class IndeterminateProgressDialog extends DialogFragment implements Injec private static final String ARG_MESSAGE_ID = IndeterminateProgressDialog.class.getCanonicalName() + ".ARG_MESSAGE_ID"; private static final String ARG_CANCELABLE = IndeterminateProgressDialog.class.getCanonicalName() + ".ARG_CANCELABLE"; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; /** * Public factory method to get dialog instances. @@ -71,14 +71,9 @@ public class IndeterminateProgressDialog extends DialogFragment implements Injec /// create indeterminate progress dialog final ProgressDialog progressDialog = new ProgressDialog(getActivity(), R.style.ProgressDialogTheme); progressDialog.setIndeterminate(true); - progressDialog.setOnShowListener(new DialogInterface.OnShowListener() { - @Override - public void onShow(DialogInterface dialog) { - ProgressBar v = progressDialog.findViewById(android.R.id.progress); - v.getIndeterminateDrawable().setColorFilter(themeColorUtils.primaryAccentColor(getContext()), - android.graphics.PorterDuff.Mode.MULTIPLY); - - } + progressDialog.setOnShowListener(dialog -> { + ProgressBar v = progressDialog.findViewById(android.R.id.progress); + viewThemeUtils.platform.tintDrawable(requireContext(), v.getIndeterminateDrawable()); }); /// set message diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java index c4eeb3b308..016d8ea7f8 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.java @@ -19,7 +19,6 @@ package com.owncloud.android.ui.dialog; import android.app.Dialog; -import android.graphics.PorterDuff; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -30,7 +29,7 @@ import android.widget.TextView; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -39,7 +38,7 @@ import androidx.fragment.app.DialogFragment; public class LoadingDialog extends DialogFragment implements Injectable { - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; private String mMessage; @Override @@ -66,8 +65,7 @@ public class LoadingDialog extends DialogFragment implements Injectable { // set progress wheel color ProgressBar progressBar = v.findViewById(R.id.loadingBar); - progressBar.getIndeterminateDrawable().setColorFilter(themeColorUtils.primaryAccentColor(getContext()), - PorterDuff.Mode.SRC_IN); + viewThemeUtils.platform.tintDrawable(requireContext(), progressBar.getIndeterminateDrawable()); return v; } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.java index 132ee40617..96e39d372a 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.java @@ -27,14 +27,14 @@ import android.os.Environment; import android.view.LayoutInflater; import android.view.View; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.StoragePathDialogBinding; import com.owncloud.android.ui.adapter.StoragePathAdapter; import com.owncloud.android.ui.adapter.StoragePathItem; import com.owncloud.android.utils.FileStorageUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.ArrayList; @@ -60,8 +60,7 @@ public class LocalStoragePathPickerDialogFragment extends DialogFragment private static Set internalStoragePaths = new HashSet<>(); - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; static { internalStoragePaths.add("/storage/emulated/legacy"); @@ -82,8 +81,7 @@ public class LocalStoragePathPickerDialogFragment extends DialogFragment AlertDialog alertDialog = (AlertDialog) getDialog(); if (alertDialog != null) { - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); } } @@ -97,7 +95,7 @@ public class LocalStoragePathPickerDialogFragment extends DialogFragment public Dialog onCreateDialog(Bundle savedInstanceState) { if (!(getActivity() instanceof StoragePathAdapter.StoragePathAdapterListener)) { throw new IllegalArgumentException("Calling activity must implement " + - "StoragePathAdapter.StoragePathAdapterListener"); + "StoragePathAdapter.StoragePathAdapterListener"); } // Inflate the layout for the dialog @@ -111,11 +109,13 @@ public class LocalStoragePathPickerDialogFragment extends DialogFragment binding.storagePathRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); builder.setView(view) .setNegativeButton(R.string.common_cancel, this) .setTitle(R.string.storage_choose_location); + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); + return builder.create(); } @@ -137,7 +137,7 @@ public class LocalStoragePathPickerDialogFragment extends DialogFragment for (FileStorageUtils.StandardDirectory standardDirectory : FileStorageUtils.StandardDirectory.getStandardDirectories()) { addIfExists(storagePathItems, standardDirectory.getIcon(), getString(standardDirectory.getDisplayName()), - Environment.getExternalStoragePublicDirectory(standardDirectory.getName()).getAbsolutePath()); + Environment.getExternalStoragePublicDirectory(standardDirectory.getName()).getAbsolutePath()); } String sdCard = getString(R.string.storage_internal_storage); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java index 109b355198..e985db2a42 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.java @@ -28,22 +28,22 @@ package com.owncloud.android.ui.dialog; import android.app.Activity; import android.app.Dialog; +import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.MultipleAccountsBinding; -import com.owncloud.android.ui.activity.ReceiveExternalFilesActivity; import com.owncloud.android.ui.adapter.UserListAdapter; import com.owncloud.android.ui.adapter.UserListItem; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -51,15 +51,14 @@ import java.util.List; import javax.inject.Inject; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; import androidx.recyclerview.widget.LinearLayoutManager; public class MultipleAccountsDialog extends DialogFragment implements Injectable, UserListAdapter.ClickListener { @Inject UserAccountManager accountManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; + @Inject ViewThemeUtils viewThemeUtils; + public boolean highlightCurrentlyActiveAccount = true; @NonNull @Override @@ -73,23 +72,26 @@ public class MultipleAccountsDialog extends DialogFragment implements Injectable LayoutInflater inflater = activity.getLayoutInflater(); MultipleAccountsBinding binding = MultipleAccountsBinding.inflate(inflater, null, false); - final ReceiveExternalFilesActivity parent = (ReceiveExternalFilesActivity) getActivity(); - AlertDialog.Builder builder = new AlertDialog.Builder(parent); + final Context parent = getActivity(); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); UserListAdapter adapter = new UserListAdapter(parent, accountManager, getAccountListItems(), this, false, + highlightCurrentlyActiveAccount, false, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); binding.list.setHasFixedSize(true); binding.list.setLayoutManager(new LinearLayoutManager(activity)); binding.list.setAdapter(adapter); builder.setView(binding.getRoot()).setTitle(R.string.common_choose_account); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); + Dialog dialog = builder.create(); Window window = dialog.getWindow(); @@ -125,9 +127,9 @@ public class MultipleAccountsDialog extends DialogFragment implements Injectable @Override public void onAccountClicked(User user) { - final ReceiveExternalFilesActivity parentActivity = (ReceiveExternalFilesActivity) getActivity(); + final AccountChooserInterface parentActivity = (AccountChooserInterface) getActivity(); if (parentActivity != null) { - parentActivity.changeAccount(user.toPlatformAccount()); + parentActivity.onAccountChosen(user); } dismiss(); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java index 7e4c292956..5ae7cf2141 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/NoteDialogFragment.java @@ -29,15 +29,14 @@ import android.view.View; import android.view.Window; import android.view.WindowManager.LayoutParams; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.NoteDialogBinding; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -53,9 +52,7 @@ public class NoteDialogFragment extends DialogFragment implements DialogInterfac private static final String ARG_SHARE = "SHARE"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; private OCShare share; private NoteDialogBinding binding; @@ -86,9 +83,8 @@ public class NoteDialogFragment extends DialogFragment implements DialogInterfac AlertDialog alertDialog = (AlertDialog) getDialog(); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); } @NonNull @@ -102,17 +98,17 @@ public class NoteDialogFragment extends DialogFragment implements DialogInterfac // Setup layout binding.noteText.setText(share.getNote()); binding.noteText.requestFocus(); - themeTextInputUtils.colorTextInput(binding.noteContainer, - binding.noteText, - themeColorUtils.primaryColor(getContext()), - themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.material.colorTextInputLayout(binding.noteContainer); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.noteContainer.getContext()); builder.setView(view) .setPositiveButton(R.string.note_confirm, this) .setNeutralButton(R.string.common_cancel, this) .setTitle(R.string.send_note); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.noteContainer.getContext(), builder); + Dialog dialog = builder.create(); Window window = dialog.getWindow(); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java index 3edf9a7f0d..64b832b34d 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java @@ -28,13 +28,10 @@ import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; -import com.owncloud.android.utils.theme.ThemeColorUtils; import java.util.ArrayList; import java.util.Collection; -import javax.inject.Inject; - import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; @@ -49,8 +46,6 @@ public class RemoveFilesDialogFragment extends ConfirmationDialogFragment implem private static final int SINGLE_SELECTION = 1; private static final String ARG_TARGET_FILES = "TARGET_FILES"; - @Inject ThemeColorUtils themeColorUtils; - private Collection mTargetFiles; private ActionMode actionMode; @@ -133,13 +128,13 @@ public class RemoveFilesDialogFragment extends ConfirmationDialogFragment implem public void onStart() { super.onStart(); - int color = themeColorUtils.primaryAccentColor(getActivity()); - AlertDialog alertDialog = (AlertDialog) getDialog(); - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color); - alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(color); - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(color); + if (alertDialog != null) { + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + } } @NonNull diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java index 20d38e841f..e56d58cb5a 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java @@ -38,6 +38,7 @@ import android.view.Window; import android.view.WindowManager.LayoutParams; import android.widget.Button; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.common.collect.Sets; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; @@ -47,8 +48,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.resources.files.FileUtils; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; import java.util.Set; @@ -71,14 +71,14 @@ public class RenameFileDialogFragment private static final String ARG_TARGET_FILE = "TARGET_FILE"; private static final String ARG_PARENT_FOLDER = "PARENT_FOLDER"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; @Inject FileDataStorageManager fileDataStorageManager; private EditBoxDialogBinding binding; private OCFile mTargetFile; private Button positiveButton; + /** * Public factory method to create new RenameFileDialogFragment instances. * @@ -92,21 +92,18 @@ public class RenameFileDialogFragment args.putParcelable(ARG_PARENT_FOLDER, parentFolder); frag.setArguments(args); return frag; - } @Override public void onStart() { super.onStart(); - int color = themeColorUtils.primaryAccentColor(getContext()); - AlertDialog alertDialog = (AlertDialog) getDialog(); if (alertDialog != null) { positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - positiveButton.setTextColor(color); - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(color); + viewThemeUtils.platform.colorTextButtons(positiveButton, + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); } } @@ -123,10 +120,7 @@ public class RenameFileDialogFragment // Setup layout String currentName = mTargetFile.getFileName(); binding.userInput.setText(currentName); - themeTextInputUtils.colorTextInput(binding.userInputContainer, - binding.userInput, - themeColorUtils.primaryColor(getActivity()), - themeColorUtils.primaryAccentColor(getActivity())); + viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer); int extensionStart = mTargetFile.isFolder() ? -1 : currentName.lastIndexOf('.'); int selectionEnd = extensionStart >= 0 ? extensionStart : currentName.length(); binding.userInput.setSelection(0, selectionEnd); @@ -179,11 +173,14 @@ public class RenameFileDialogFragment }); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity()); builder.setView(view) .setPositiveButton(R.string.file_rename, this) .setNeutralButton(R.string.common_cancel, this) .setTitle(R.string.rename_dialog_title); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.getContext(), builder); + Dialog d = builder.create(); Window window = d.getWindow(); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java index 90f29a2a84..a85491ffc1 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.java @@ -23,22 +23,21 @@ package com.owncloud.android.ui.dialog; import android.app.Dialog; import android.content.DialogInterface; -import android.graphics.PorterDuff; import android.os.Bundle; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager.LayoutParams; -import android.widget.EditText; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.EditBoxDialogBinding; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.ComponentsGetter; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -47,7 +46,7 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.DialogFragment; /** - * Dialog to rename a public share + * Dialog to rename a public share. */ public class RenamePublicShareDialogFragment extends DialogFragment implements DialogInterface.OnClickListener, Injectable { @@ -56,7 +55,7 @@ public class RenamePublicShareDialogFragment public static final String RENAME_PUBLIC_SHARE_FRAGMENT = "RENAME_PUBLIC_SHARE_FRAGMENT"; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; private EditBoxDialogBinding binding; private OCShare publicShare; @@ -67,27 +66,23 @@ public class RenamePublicShareDialogFragment args.putParcelable(ARG_PUBLIC_SHARE, share); frag.setArguments(args); return frag; - } @Override public void onStart() { super.onStart(); - int color = themeColorUtils.primaryAccentColor(getContext()); - AlertDialog alertDialog = (AlertDialog) getDialog(); if (alertDialog != null) { - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(color); - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(color); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); } } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - int accentColor = themeColorUtils.primaryAccentColor(getContext()); publicShare = requireArguments().getParcelable(ARG_PUBLIC_SHARE); // Inflate the layout for the dialog @@ -96,18 +91,19 @@ public class RenamePublicShareDialogFragment View view = binding.getRoot(); // Setup layout - EditText inputText = binding.userInput; - inputText.setText(publicShare.getLabel()); - inputText.requestFocus(); - inputText.getBackground().setColorFilter(accentColor, PorterDuff.Mode.SRC_ATOP); - inputText.setHighlightColor(themeColorUtils.primaryColor(getActivity())); + viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer); + binding.userInput.setText(publicShare.getLabel()); + binding.userInput.requestFocus(); // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(view.getContext()); builder.setView(view) .setPositiveButton(R.string.file_rename, this) .setNeutralButton(R.string.common_cancel, this) .setTitle(R.string.public_share_name); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInput.getContext(), builder); + Dialog dialog = builder.create(); Window window = dialog.getWindow(); @@ -118,7 +114,6 @@ public class RenamePublicShareDialogFragment return dialog; } - @Override public void onClick(DialogInterface dialog, int which) { if (which == AlertDialog.BUTTON_POSITIVE) { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java index fbb14c5cc1..c991646b15 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.java @@ -3,7 +3,6 @@ package com.owncloud.android.ui.dialog; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ResolveInfo; -import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.LayoutInflater; @@ -28,8 +27,7 @@ import com.owncloud.android.ui.adapter.SendButtonAdapter; import com.owncloud.android.ui.components.SendButtonData; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -79,8 +77,7 @@ public class SendShareDialog extends BottomSheetDialogFragment implements Inject private boolean sharingPublicPasswordEnforced; private boolean sharingPublicAskForPassword; private FileOperationsHelper fileOperationsHelper; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeSnackbarUtils themeSnackbarUtils; + @Inject ViewThemeUtils viewThemeUtils; public static SendShareDialog newInstance(OCFile file, boolean hideNcSharingOptions, OCCapability capability) { @@ -131,11 +128,11 @@ public class SendShareDialog extends BottomSheetDialogFragment implements Inject // Share via link button TextView shareLinkText = view.findViewById(R.id.share_link_button); - shareLinkText.setOnClickListener(v -> shareByLink(themeSnackbarUtils)); + shareLinkText.setOnClickListener(v -> shareByLink()); ImageView shareLinkImageView = view.findViewById(R.id.share_link_icon); themeShareButtonImage(shareLinkImageView); - shareLinkImageView.setOnClickListener(v -> shareByLink(themeSnackbarUtils)); + shareLinkImageView.setOnClickListener(v -> shareByLink()); if (hideNcSharingOptions) { sendShareButtons.setVisibility(View.GONE); @@ -185,9 +182,9 @@ public class SendShareDialog extends BottomSheetDialogFragment implements Inject BottomSheetBehavior.from((View) requireView().getParent()).setState(BottomSheetBehavior.STATE_EXPANDED); } - private void shareByLink(ThemeSnackbarUtils themeSnackbarUtils) { + private void shareByLink() { if (file.isSharedViaLink()) { - ((FileActivity) getActivity()).getFileOperationsHelper().getFileWithLink(file, themeSnackbarUtils); + ((FileActivity) getActivity()).getFileOperationsHelper().getFileWithLink(file, viewThemeUtils); } else if (sharingPublicPasswordEnforced || sharingPublicAskForPassword) { // password enforced by server, request to the user before trying to create requestPasswordForShareViaLink(); @@ -207,11 +204,7 @@ public class SendShareDialog extends BottomSheetDialogFragment implements Inject } private void themeShareButtonImage(ImageView shareImageView) { - shareImageView.getBackground().setColorFilter(themeColorUtils.primaryColor(getContext().getApplicationContext(), - true), - PorterDuff.Mode.SRC_IN); - shareImageView.getDrawable().mutate().setColorFilter(themeColorUtils.fontColor(getContext().getApplicationContext()), - PorterDuff.Mode.SRC_IN); + viewThemeUtils.files.themeAvatarButton(shareImageView); } private void showResharingNotAllowedSnackbar() { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java index 80343159bd..b1fa949779 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SetupEncryptionDialogFragment.java @@ -24,18 +24,17 @@ import android.accounts.AccountManager; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; -import android.widget.TextView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; +import com.owncloud.android.databinding.SetupEncryptionDialogBinding; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -47,8 +46,7 @@ import com.owncloud.android.lib.resources.users.SendCSROperation; import com.owncloud.android.lib.resources.users.StorePrivateKeyOperation; import com.owncloud.android.utils.CsrHelper; import com.owncloud.android.utils.EncryptionUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.IOException; import java.security.KeyPair; @@ -62,7 +60,6 @@ import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.appcompat.app.AlertDialog; -import androidx.core.graphics.drawable.DrawableCompat; import androidx.fragment.app.DialogFragment; import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes; @@ -89,19 +86,16 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj private static final String KEY_FAILED = "KEY_FAILED"; private static final String KEY_GENERATE = "KEY_GENERATE"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ViewThemeUtils viewThemeUtils; private User user; - private TextView textView; - private TextView passphraseTextView; private ArbitraryDataProvider arbitraryDataProvider; private Button positiveButton; private Button neutralButton; private DownloadKeysAsyncTask task; - private TextView passwordField; private String keyResult; private List keyWords; + private SetupEncryptionDialogBinding binding; /** * Public factory method to create new SetupEncryptionDialogFragment instance @@ -123,11 +117,11 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj AlertDialog alertDialog = (AlertDialog) getDialog(); - positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); - neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL); - themeButtonUtils.themeBorderlessButton(themeColorUtils, - positiveButton, - neutralButton); + if (alertDialog != null) { + positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL); + viewThemeUtils.platform.colorTextButtons(positiveButton, neutralButton); + } task = new DownloadKeysAsyncTask(); task.execute(); @@ -136,34 +130,28 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - int primaryColor = themeColorUtils.primaryColor(getContext()); user = getArguments().getParcelable(ARG_USER); arbitraryDataProvider = new ArbitraryDataProvider(getContext().getContentResolver()); // Inflate the layout for the dialog LayoutInflater inflater = getActivity().getLayoutInflater(); + binding = SetupEncryptionDialogBinding.inflate(inflater, null, false); // Setup layout - View v = inflater.inflate(R.layout.setup_encryption_dialog, null); - textView = v.findViewById(R.id.encryption_status); - passphraseTextView = v.findViewById(R.id.encryption_passphrase); - passwordField = v.findViewById(R.id.encryption_passwordInput); - passwordField.getBackground().setColorFilter(primaryColor, PorterDuff.Mode.SRC_ATOP); + viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer); - Drawable wrappedDrawable = DrawableCompat.wrap(passwordField.getBackground()); - DrawableCompat.setTint(wrappedDrawable, primaryColor); - passwordField.setBackgroundDrawable(wrappedDrawable); - - return createDialog(v); + return createDialog(binding.getRoot()); } @NonNull private Dialog createDialog(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(v.getContext()); builder.setView(v).setPositiveButton(R.string.common_ok, null) - .setNeutralButton(R.string.common_cancel, null) - .setTitle(R.string.end_to_end_encryption_title); + .setNeutralButton(R.string.common_cancel, null) + .setTitle(R.string.end_to_end_encryption_title); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(v.getContext(), builder); Dialog dialog = builder.create(); dialog.setCanceledOnTouchOutside(false); @@ -188,18 +176,18 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj intentCreated.putExtra(SUCCESS, true); intentCreated.putExtra(ARG_POSITION, getArguments().getInt(ARG_POSITION)); getTargetFragment().onActivityResult(getTargetRequestCode(), - SETUP_ENCRYPTION_RESULT_CODE, intentCreated); + SETUP_ENCRYPTION_RESULT_CODE, intentCreated); break; case KEY_EXISTING_USED: Log_OC.d(TAG, "Decrypt private key"); - textView.setText(R.string.end_to_end_encryption_decrypting); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_decrypting); try { String privateKey = task.get(); - String mnemonicUnchanged = passwordField.getText().toString(); - String mnemonic = passwordField.getText().toString().replaceAll("\\s", "") + String mnemonicUnchanged = binding.encryptionPasswordInput.getText().toString(); + String mnemonic = binding.encryptionPasswordInput.getText().toString().replaceAll("\\s", "") .toLowerCase(Locale.ROOT); String decryptedPrivateKey = EncryptionUtils.decryptPrivateKey(privateKey, mnemonic); @@ -239,13 +227,13 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj SETUP_ENCRYPTION_RESULT_CODE, intentExisting); } catch (Exception e) { - textView.setText(R.string.end_to_end_encryption_wrong_password); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_wrong_password); Log_OC.d(TAG, "Error while decrypting private key: " + e.getMessage()); } break; case KEY_GENERATE: - passphraseTextView.setVisibility(View.GONE); + binding.encryptionPassphrase.setVisibility(View.GONE); positiveButton.setVisibility(View.GONE); neutralButton.setVisibility(View.GONE); getDialog().setTitle(R.string.end_to_end_encryption_storing_keys); @@ -270,7 +258,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj protected void onPreExecute() { super.onPreExecute(); - textView.setText(R.string.end_to_end_encryption_retrieving_keys); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_retrieving_keys); positiveButton.setVisibility(View.INVISIBLE); neutralButton.setVisibility(View.INVISIBLE); } @@ -319,11 +307,11 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj keyWords = EncryptionUtils.getRandomWords(12, requireContext()); showMnemonicInfo(); } catch (IOException e) { - textView.setText(R.string.common_error); + binding.encryptionStatus.setText(R.string.common_error); } } else if (!privateKey.isEmpty()) { - textView.setText(R.string.end_to_end_encryption_enter_password); - passwordField.setVisibility(View.VISIBLE); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_enter_password); + binding.encryptionPasswordInputContainer.setVisibility(View.VISIBLE); positiveButton.setVisibility(View.VISIBLE); } else { Log_OC.e(TAG, "Got empty private key string"); @@ -336,7 +324,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj protected void onPreExecute() { super.onPreExecute(); - textView.setText(R.string.end_to_end_encryption_generating_keys); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_generating_keys); } @Override @@ -370,7 +358,7 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj String privateKeyString = EncryptionUtils.encodeBytesToBase64String(privateKey.getEncoded()); String privatePemKeyString = EncryptionUtils.privateKeyToPEM(privateKey); String encryptedPrivateKey = EncryptionUtils.encryptPrivateKey(privatePemKeyString, - generateMnemonicString(false)); + generateMnemonicString(false)); // upload encryptedPrivateKey StorePrivateKeyOperation storePrivateKeyOperation = new StorePrivateKeyOperation(encryptedPrivateKey); @@ -380,10 +368,10 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj Log_OC.d(TAG, "private key success"); arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), EncryptionUtils.PRIVATE_KEY, - privateKeyString); + privateKeyString); arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), EncryptionUtils.PUBLIC_KEY, publicKey); arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), EncryptionUtils.MNEMONIC, - generateMnemonicString(true)); + generateMnemonicString(true)); keyResult = KEY_CREATED; return (String) storePrivateKeyResult.getData().get(0); @@ -434,16 +422,17 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj public void showMnemonicInfo() { requireDialog().setTitle(R.string.end_to_end_encryption_passphrase_title); - textView.setText(R.string.end_to_end_encryption_keywords_description); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_keywords_description); + viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer); - passphraseTextView.setText(generateMnemonicString(true)); + binding.encryptionPassphrase.setText(generateMnemonicString(true)); - passphraseTextView.setVisibility(View.VISIBLE); + binding.encryptionPassphrase.setVisibility(View.VISIBLE); positiveButton.setText(R.string.end_to_end_encryption_confirm_button); positiveButton.setVisibility(View.VISIBLE); neutralButton.setVisibility(View.VISIBLE); - themeButtonUtils.themeBorderlessButton(themeColorUtils, positiveButton, neutralButton); + viewThemeUtils.platform.colorTextButtons(positiveButton, neutralButton); keyResult = KEY_GENERATE; } @@ -453,11 +442,11 @@ public class SetupEncryptionDialogFragment extends DialogFragment implements Inj keyResult = KEY_FAILED; requireDialog().setTitle(R.string.common_error); - textView.setText(R.string.end_to_end_encryption_unsuccessful); - passphraseTextView.setVisibility(View.GONE); + binding.encryptionStatus.setText(R.string.end_to_end_encryption_unsuccessful); + binding.encryptionPassphrase.setVisibility(View.GONE); positiveButton.setText(R.string.end_to_end_encryption_dialog_close); positiveButton.setVisibility(View.VISIBLE); - positiveButton.setTextColor(themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.platform.colorTextButtons(positiveButton); } @VisibleForTesting diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ShareLinkToDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/ShareLinkToDialog.java index 77679f891a..6f55e0004f 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ShareLinkToDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ShareLinkToDialog.java @@ -36,6 +36,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.owncloud.android.R; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.activity.CopyToClipboardActivity; @@ -125,7 +126,7 @@ public class ShareLinkToDialog extends DialogFragment { titleId = R.string.activity_chooser_title; } - return new AlertDialog.Builder(getActivity()) + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()) .setTitle(titleId) .setAdapter(mAdapter, new DialogInterface.OnClickListener() { @Override @@ -141,8 +142,8 @@ public class ShareLinkToDialog extends DialogFragment { // Send the file getActivity().startActivity(mIntent); } - }) - .create(); + }); + return builder.create(); } class ActivityAdapter extends ArrayAdapter { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java index 479616004b..0c51a1b327 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java @@ -29,6 +29,7 @@ import android.view.View; import android.view.Window; import android.view.WindowManager; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.PasswordDialogBinding; @@ -36,9 +37,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -59,9 +58,7 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo private static final String ARG_ASK_FOR_PASSWORD = "ASK_FOR_PASSWORD"; public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT"; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; private PasswordDialogBinding binding; private OCFile file; @@ -75,11 +72,10 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo AlertDialog alertDialog = (AlertDialog) getDialog(); if (alertDialog != null) { - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); - themeButtonUtils.themeBorderlessButton(getResources().getColor(R.color.highlight_textColor_Warning), - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); + viewThemeUtils.platform.colorTextButtons(getResources().getColor(R.color.highlight_textColor_Warning), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL)); alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> { String password = binding.sharePassword.getText().toString(); @@ -104,9 +100,8 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo * Public factory method to create new SharePasswordDialogFragment instances. * * @param file OCFile bound to the public share that which password will be set or updated - * @param createShare When 'true', the request for password will be followed by the creation of a new - * public link; when 'false', a public share is assumed to exist, and the password - * is bound to it. + * @param createShare When 'true', the request for password will be followed by the creation of a new public link; + * when 'false', a public share is assumed to exist, and the password is bound to it. * @return Dialog ready to show. */ public static SharePasswordDialogFragment newInstance(OCFile file, boolean createShare, boolean askForPassword) { @@ -163,10 +158,7 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo // Setup layout binding.sharePassword.setText(""); - themeTextInputUtils.colorTextInput(binding.sharePasswordContainer, - binding.sharePassword, - themeColorUtils.primaryColor(getActivity()), - themeColorUtils.primaryAccentColor(getActivity())); + viewThemeUtils.material.colorTextInputLayout(binding.sharePasswordContainer); binding.sharePassword.requestFocus(); int negativeButtonCaption; @@ -180,13 +172,16 @@ public class SharePasswordDialogFragment extends DialogFragment implements Dialo } // Build the dialog - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(view.getContext()); builder.setView(view) .setPositiveButton(R.string.common_ok, null) .setNegativeButton(negativeButtonCaption, this) - .setNeutralButton(R.string.common_delete, this) + .setNeutralButton(R.string.common_delete, this) .setTitle(title); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(view.getContext(), builder); + Dialog d = builder.create(); Window window = d.getWindow(); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java index bdb459d890..764ca5c5e4 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.java @@ -24,19 +24,17 @@ package com.owncloud.android.ui.dialog; import android.app.Dialog; import android.graphics.Typeface; import android.os.Bundle; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.TextView; -import com.google.android.material.button.MaterialButton; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; +import com.owncloud.android.databinding.SortingOrderFragmentBinding; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.utils.FileSortOrder; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -53,13 +51,12 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject public static final String SORTING_ORDER_FRAGMENT = "SORTING_ORDER_FRAGMENT"; private static final String KEY_SORT_ORDER = "SORT_ORDER"; - private View mView; + private SortingOrderFragmentBinding binding; private View[] mTaggedViews; - private MaterialButton mCancel; private String mCurrentSortOrderName; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; + + @Inject ViewThemeUtils viewThemeUtils; public static SortingOrderDialogFragment newInstance(FileSortOrder sortOrder) { SortingOrderDialogFragment dialogFragment = new SortingOrderDialogFragment(); @@ -79,55 +76,42 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject // keep the state of the fragment on configuration changes setRetainInstance(true); - mView = null; + binding = null; mCurrentSortOrderName = getArguments().getString(KEY_SORT_ORDER, FileSortOrder.sort_a_to_z.name); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log_OC.d(TAG, "onCreateView, savedInstanceState is " + savedInstanceState); - - mView = inflater.inflate(R.layout.sorting_order_fragment, container, false); - - setupDialogElements(mView); - setupListeners(); - - return mView; - } - /** * find all relevant UI elements and set their values. * - * @param view the parent view + * @param binding the parent binding */ - private void setupDialogElements(View view) { - mCancel = view.findViewById(R.id.cancel); - mCancel.setTextColor(themeColorUtils.primaryAccentColor(getContext())); + private void setupDialogElements(SortingOrderFragmentBinding binding) { + viewThemeUtils.platform.colorTextButtons(binding.cancel); mTaggedViews = new View[12]; - mTaggedViews[0] = view.findViewById(R.id.sortByNameAscending); + mTaggedViews[0] = binding.sortByNameAscending; mTaggedViews[0].setTag(FileSortOrder.sort_a_to_z); - mTaggedViews[1] = view.findViewById(R.id.sortByNameAZText); + mTaggedViews[1] = binding.sortByNameAZText; mTaggedViews[1].setTag(FileSortOrder.sort_a_to_z); - mTaggedViews[2] = view.findViewById(R.id.sortByNameDescending); + mTaggedViews[2] = binding.sortByNameDescending; mTaggedViews[2].setTag(FileSortOrder.sort_z_to_a); - mTaggedViews[3] = view.findViewById(R.id.sortByNameZAText); + mTaggedViews[3] = binding.sortByNameZAText; mTaggedViews[3].setTag(FileSortOrder.sort_z_to_a); - mTaggedViews[4] = view.findViewById(R.id.sortByModificationDateAscending); + mTaggedViews[4] = binding.sortByModificationDateAscending; mTaggedViews[4].setTag(FileSortOrder.sort_old_to_new); - mTaggedViews[5] = view.findViewById(R.id.sortByModificationDateOldestFirstText); + mTaggedViews[5] = binding.sortByModificationDateOldestFirstText; mTaggedViews[5].setTag(FileSortOrder.sort_old_to_new); - mTaggedViews[6] = view.findViewById(R.id.sortByModificationDateDescending); + mTaggedViews[6] = binding.sortByModificationDateDescending; mTaggedViews[6].setTag(FileSortOrder.sort_new_to_old); - mTaggedViews[7] = view.findViewById(R.id.sortByModificationDateNewestFirstText); + mTaggedViews[7] = binding.sortByModificationDateNewestFirstText; mTaggedViews[7].setTag(FileSortOrder.sort_new_to_old); - mTaggedViews[8] = view.findViewById(R.id.sortBySizeAscending); + mTaggedViews[8] = binding.sortBySizeAscending; mTaggedViews[8].setTag(FileSortOrder.sort_small_to_big); - mTaggedViews[9] = view.findViewById(R.id.sortBySizeSmallestFirstText); + mTaggedViews[9] = binding.sortBySizeSmallestFirstText; mTaggedViews[9].setTag(FileSortOrder.sort_small_to_big); - mTaggedViews[10] = view.findViewById(R.id.sortBySizeDescending); + mTaggedViews[10] = binding.sortBySizeDescending; mTaggedViews[10].setTag(FileSortOrder.sort_big_to_small); - mTaggedViews[11] = view.findViewById(R.id.sortBySizeBiggestFirstText); + mTaggedViews[11] = binding.sortBySizeBiggestFirstText; mTaggedViews[11].setTag(FileSortOrder.sort_big_to_small); setupActiveOrderSelection(); @@ -137,17 +121,17 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject * tints the icon reflecting the actual sorting choice in the apps primary color. */ private void setupActiveOrderSelection() { - final int color = themeColorUtils.primaryColor(null, true, true, getContext()); - for (View view: mTaggedViews) { + for (View view : mTaggedViews) { if (!((FileSortOrder) view.getTag()).name.equals(mCurrentSortOrderName)) { continue; } if (view instanceof ImageButton) { - themeButtonUtils.colorImageButton((ImageButton) view, color); + viewThemeUtils.platform.themeImageButton((ImageButton) view); + ((ImageButton) view).setSelected(true); } if (view instanceof TextView) { - ((TextView)view).setTextColor(color); - ((TextView)view).setTypeface(Typeface.DEFAULT_BOLD); + viewThemeUtils.platform.colorPrimaryTextViewElement((TextView) view); + ((TextView) view).setTypeface(Typeface.DEFAULT_BOLD); } } } @@ -156,7 +140,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject * setup all listeners. */ private void setupListeners() { - mCancel.setOnClickListener(view -> dismiss()); + binding.cancel.setOnClickListener(view -> dismiss()); OnSortOrderClickListener sortOrderClickListener = new OnSortOrderClickListener(); @@ -168,7 +152,17 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - return super.onCreateDialog(savedInstanceState); + binding = SortingOrderFragmentBinding.inflate(requireActivity().getLayoutInflater(), null, false); + + setupDialogElements(binding); + setupListeners(); + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); + builder.setView(binding.getRoot()); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); + + return builder.create(); } @Override @@ -185,7 +179,7 @@ public class SortingOrderDialogFragment extends DialogFragment implements Inject public void onClick(View v) { dismissAllowingStateLoss(); ((SortingOrderDialogFragment.OnSortingOrderListener) getActivity()) - .onSortingOrderChosen((FileSortOrder) v.getTag()); + .onSortingOrderChosen((FileSortOrder) v.getTag()); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java index a669afb080..3046976902 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java @@ -32,6 +32,8 @@ import android.view.Window; import android.webkit.SslErrorHandler; import android.widget.Button; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding; import com.owncloud.android.lib.common.network.CertificateCombinedException; @@ -41,11 +43,14 @@ import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter; import com.owncloud.android.ui.adapter.SslCertificateViewAdapter; import com.owncloud.android.ui.adapter.SslErrorViewAdapter; import com.owncloud.android.ui.adapter.X509CertificateViewAdapter; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.cert.X509Certificate; +import javax.inject.Inject; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; @@ -56,10 +61,12 @@ import androidx.fragment.app.DialogFragment; * Abstract implementation of common functionality for different dialogs that * get the information about the error and the certificate from different classes. */ -public class SslUntrustedCertDialog extends DialogFragment { +public class SslUntrustedCertDialog extends DialogFragment implements Injectable { private final static String TAG = SslUntrustedCertDialog.class.getSimpleName(); + @Inject ViewThemeUtils viewThemeUtils; + protected SslUntrustedCertLayoutBinding binding; protected SslErrorHandler mHandler; protected X509Certificate m509Certificate; @@ -110,7 +117,6 @@ public class SslUntrustedCertDialog extends DialogFragment { return dialog; } - @Override public void onAttach(@NonNull Activity activity) { Log_OC.d(TAG, "onAttach"); @@ -120,7 +126,6 @@ public class SslUntrustedCertDialog extends DialogFragment { } } - @Override public void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState); @@ -165,7 +170,12 @@ public class SslUntrustedCertDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState); - final Dialog dialog = super.onCreateDialog(savedInstanceState); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); + builder.setView(binding.getRoot()); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); + + final Dialog dialog = builder.create(); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); return dialog; } @@ -190,7 +200,6 @@ public class SslUntrustedCertDialog extends DialogFragment { } } - private class OnCertificateTrusted implements OnClickListener { @Override @@ -210,13 +219,10 @@ public class SslUntrustedCertDialog extends DialogFragment { } } } - } - public interface OnSslUntrustedCertListener { void onSavedCertificate(); - void onFailedSavingCertificate(); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SslValidatorDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/SslValidatorDialog.java index f935bfad6d..2373681946 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SslValidatorDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SslValidatorDialog.java @@ -26,9 +26,9 @@ import android.os.Bundle; import android.view.View; import android.view.Window; import android.widget.Button; -import android.widget.TextView; import com.owncloud.android.R; +import com.owncloud.android.databinding.SslValidatorLayoutBinding; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.lib.common.network.NetworkUtils; import com.owncloud.android.lib.common.operations.RemoteOperationResult; @@ -55,7 +55,7 @@ public class SslValidatorDialog extends Dialog { private OnSslValidatorListener mListener; private CertificateCombinedException mException; - private View mView; + private SslValidatorLayoutBinding binding; /** @@ -95,10 +95,10 @@ public class SslValidatorDialog extends Dialog { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); - mView = getLayoutInflater().inflate(R.layout.ssl_validator_layout, null); - setContentView(mView); - - mView.findViewById(R.id.ok).setOnClickListener( + binding = SslValidatorLayoutBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + binding.ok.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -121,16 +121,16 @@ public class SslValidatorDialog extends Dialog { } } }); - - mView.findViewById(R.id.cancel).setOnClickListener( + + binding.cancel.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { cancel(); } }); - - mView.findViewById(R.id.details_btn).setOnClickListener( + + binding.detailsBtn.setOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { @@ -152,27 +152,27 @@ public class SslValidatorDialog extends Dialog { mException = (CertificateCombinedException) result.getException(); /// clean - mView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.GONE); - mView.findViewById(R.id.reason_cert_expired).setVisibility(View.GONE); - mView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.GONE); - mView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.GONE); - mView.findViewById(R.id.details_scroll).setVisibility(View.GONE); + binding.reasonCertNotTrusted.setVisibility(View.GONE); + binding.reasonCertExpired.setVisibility(View.GONE); + binding.reasonCertNotYetValid.setVisibility(View.GONE); + binding.reasonHostnameNotVerified.setVisibility(View.GONE); + binding.detailsScroll.setVisibility(View.GONE); /// refresh if (mException.getCertPathValidatorException() != null) { - mView.findViewById(R.id.reason_cert_not_trusted).setVisibility(View.VISIBLE); + binding.reasonCertNotTrusted.setVisibility(View.VISIBLE); } if (mException.getCertificateExpiredException() != null) { - mView.findViewById(R.id.reason_cert_expired).setVisibility(View.VISIBLE); + binding.reasonCertExpired.setVisibility(View.VISIBLE); } if (mException.getCertificateNotYetValidException() != null) { - mView.findViewById(R.id.reason_cert_not_yet_valid).setVisibility(View.VISIBLE); + binding.reasonCertNotYetValid.setVisibility(View.VISIBLE); } if (mException.getSslPeerUnverifiedException() != null ) { - mView.findViewById(R.id.reason_hostname_not_verified).setVisibility(View.VISIBLE); + binding.reasonHostnameNotVerified.setVisibility(View.VISIBLE); } showCertificateData(mException.getServerCertificate()); @@ -194,10 +194,8 @@ public class SslValidatorDialog extends Dialog { } private void showSignature(X509Certificate cert) { - TextView sigView = mView.findViewById(R.id.value_signature); - TextView algorithmView = mView.findViewById(R.id.value_signature_algorithm); - sigView.setText(getHex(cert.getSignature())); - algorithmView.setText(cert.getSigAlgName()); + binding.valueSignature.setText(getHex(cert.getSignature())); + binding.valueSignatureAlgorithm.setText(cert.getSigAlgName()); } public String getHex(final byte [] raw) { @@ -216,106 +214,91 @@ public class SslValidatorDialog extends Dialog { @SuppressWarnings("deprecation") private void showValidity(Date notBefore, Date notAfter) { - TextView fromView = mView.findViewById(R.id.value_validity_from); - TextView toView = mView.findViewById(R.id.value_validity_to); - fromView.setText(notBefore.toLocaleString()); - toView.setText(notAfter.toLocaleString()); + binding.valueValidityFrom.setText(notBefore.toLocaleString()); + binding.valueValidityTo.setText(notAfter.toLocaleString()); } private void showSubject(X500Principal subject) { Map s = parsePrincipal(subject); - TextView cnView = mView.findViewById(R.id.value_subject_CN); - TextView oView = mView.findViewById(R.id.value_subject_O); - TextView ouView = mView.findViewById(R.id.value_subject_OU); - TextView cView = mView.findViewById(R.id.value_subject_C); - TextView stView = mView.findViewById(R.id.value_subject_ST); - TextView lView = mView.findViewById(R.id.value_subject_L); if (s.get("CN") != null) { - cnView.setText(s.get("CN")); - cnView.setVisibility(View.VISIBLE); + binding.valueSubjectCN.setText(s.get("CN")); + binding.valueSubjectCN.setVisibility(View.VISIBLE); } else { - cnView.setVisibility(View.GONE); + binding.valueSubjectCN.setVisibility(View.GONE); } if (s.get("O") != null) { - oView.setText(s.get("O")); - oView.setVisibility(View.VISIBLE); + binding.valueSubjectO.setText(s.get("O")); + binding.valueSubjectO.setVisibility(View.VISIBLE); } else { - oView.setVisibility(View.GONE); + binding.valueSubjectO.setVisibility(View.GONE); } if (s.get("OU") != null) { - ouView.setText(s.get("OU")); - ouView.setVisibility(View.VISIBLE); + binding.valueSubjectOU.setText(s.get("OU")); + binding.valueSubjectOU.setVisibility(View.VISIBLE); } else { - ouView.setVisibility(View.GONE); + binding.valueSubjectOU.setVisibility(View.GONE); } if (s.get("C") != null) { - cView.setText(s.get("C")); - cView.setVisibility(View.VISIBLE); + binding.valueSubjectC.setText(s.get("C")); + binding.valueSubjectC.setVisibility(View.VISIBLE); } else { - cView.setVisibility(View.GONE); + binding.valueSubjectC.setVisibility(View.GONE); } if (s.get("ST") != null) { - stView.setText(s.get("ST")); - stView.setVisibility(View.VISIBLE); + binding.valueSubjectST.setText(s.get("ST")); + binding.valueSubjectST.setVisibility(View.VISIBLE); } else { - stView.setVisibility(View.GONE); + binding.valueSubjectST.setVisibility(View.GONE); } if (s.get("L") != null) { - lView.setText(s.get("L")); - lView.setVisibility(View.VISIBLE); + binding.valueSubjectL.setText(s.get("L")); + binding.valueSubjectL.setVisibility(View.VISIBLE); } else { - lView.setVisibility(View.GONE); + binding.valueSubjectL.setVisibility(View.GONE); } } private void showIssuer(X500Principal issuer) { Map s = parsePrincipal(issuer); - TextView cnView = mView.findViewById(R.id.value_issuer_CN); - TextView oView = mView.findViewById(R.id.value_issuer_O); - TextView ouView = mView.findViewById(R.id.value_issuer_OU); - TextView cView = mView.findViewById(R.id.value_issuer_C); - TextView stView = mView.findViewById(R.id.value_issuer_ST); - TextView lView = mView.findViewById(R.id.value_issuer_L); if (s.get("CN") != null) { - cnView.setText(s.get("CN")); - cnView.setVisibility(View.VISIBLE); + binding.valueIssuerCN.setText(s.get("CN")); + binding.valueIssuerCN.setVisibility(View.VISIBLE); } else { - cnView.setVisibility(View.GONE); + binding.valueIssuerCN.setVisibility(View.GONE); } if (s.get("O") != null) { - oView.setText(s.get("O")); - oView.setVisibility(View.VISIBLE); + binding.valueIssuerO.setText(s.get("O")); + binding.valueIssuerO.setVisibility(View.VISIBLE); } else { - oView.setVisibility(View.GONE); + binding.valueIssuerO.setVisibility(View.GONE); } if (s.get("OU") != null) { - ouView.setText(s.get("OU")); - ouView.setVisibility(View.VISIBLE); + binding.valueIssuerOU.setText(s.get("OU")); + binding.valueIssuerOU.setVisibility(View.VISIBLE); } else { - ouView.setVisibility(View.GONE); + binding.valueIssuerOU.setVisibility(View.GONE); } if (s.get("C") != null) { - cView.setText(s.get("C")); - cView.setVisibility(View.VISIBLE); + binding.valueIssuerC.setText(s.get("C")); + binding.valueIssuerC.setVisibility(View.VISIBLE); } else { - cView.setVisibility(View.GONE); + binding.valueIssuerC.setVisibility(View.GONE); } if (s.get("ST") != null) { - stView.setText(s.get("ST")); - stView.setVisibility(View.VISIBLE); + binding.valueIssuerST.setText(s.get("ST")); + binding.valueIssuerST.setVisibility(View.VISIBLE); } else { - stView.setVisibility(View.GONE); + binding.valueIssuerST.setVisibility(View.GONE); } if (s.get("L") != null) { - lView.setText(s.get("L")); - lView.setVisibility(View.VISIBLE); + binding.valueIssuerL.setText(s.get("L")); + binding.valueIssuerL.setVisibility(View.VISIBLE); } else { - lView.setVisibility(View.GONE); + binding.valueIssuerL.setVisibility(View.GONE); } } - private Map parsePrincipal(X500Principal principal) { Map result = new HashMap<>(); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/StoragePermissionDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/StoragePermissionDialogFragment.kt index 63607bc9db..18fd276fe2 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/StoragePermissionDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/StoragePermissionDialogFragment.kt @@ -32,8 +32,7 @@ import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.databinding.StoragePermissionDialogBinding import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment.Listener -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject /** @@ -51,16 +50,13 @@ class StoragePermissionDialogFragment(val listener: Listener, val permissionRequ private lateinit var binding: StoragePermissionDialogBinding @Inject - lateinit var themeButtonUtils: ThemeButtonUtils - - @Inject - lateinit var themeColorUtils: ThemeColorUtils + lateinit var viewThemeUtils: ViewThemeUtils override fun onStart() { super.onStart() dialog?.let { val alertDialog = it as AlertDialog - themeButtonUtils.themeBorderlessButton(themeColorUtils, alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)) + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)) } } @@ -77,12 +73,12 @@ class StoragePermissionDialogFragment(val listener: Listener, val permissionRequ binding.storagePermissionExplanation.text = getString(explanationResource, getString(R.string.app_name)) // Setup layout - themeButtonUtils.colorPrimaryButton(binding.btnFullAccess, context, themeColorUtils) + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.btnFullAccess) binding.btnFullAccess.setOnClickListener { listener.onClickFullAccess() dismiss() } - themeButtonUtils.themeBorderlessButton(themeColorUtils, binding.btnReadOnly) + viewThemeUtils.platform.colorTextButtons(binding.btnReadOnly) binding.btnReadOnly.setOnClickListener { listener.onClickMediaReadOnly() dismiss() @@ -93,16 +89,18 @@ class StoragePermissionDialogFragment(val listener: Listener, val permissionRequ permissionRequired -> R.string.file_management_permission else -> R.string.file_management_permission_optional } - val dialog = MaterialAlertDialogBuilder(requireActivity(), R.style.Theme_ownCloud_Dialog) + + val builder = MaterialAlertDialogBuilder(binding.btnReadOnly.context) .setTitle(titleResource) .setView(view) .setNegativeButton(R.string.common_cancel) { _, _ -> listener.onCancel() dismiss() } - .create() - return dialog + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.btnReadOnly.context, builder) + + return builder.create() } interface Listener { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java index 83e864fb14..a614a8a8a6 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncFileNotEnoughSpaceDialogFragment.java @@ -31,6 +31,9 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.ui.dialog.ConfirmationDialogFragment.ConfirmationDialogFragmentListener; import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; + +import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -47,6 +50,8 @@ public class SyncFileNotEnoughSpaceDialogFragment extends ConfirmationDialogFrag private OCFile targetFile; + @Inject ViewThemeUtils viewThemeUtils; + public static SyncFileNotEnoughSpaceDialogFragment newInstance(OCFile file, long availableDeviceSpace) { Bundle args = new Bundle(); SyncFileNotEnoughSpaceDialogFragment frag = new SyncFileNotEnoughSpaceDialogFragment(); @@ -57,7 +62,7 @@ public class SyncFileNotEnoughSpaceDialogFragment extends ConfirmationDialogFrag args.putInt(ARG_TITLE_ID, R.string.sync_not_enough_space_dialog_title); args.putInt(ARG_MESSAGE_RESOURCE_ID, R.string.sync_not_enough_space_dialog_placeholder); args.putStringArray(ARG_MESSAGE_ARGUMENTS, - new String[] { + new String[]{ file.getFileName(), properFileSize, properDiskAvailableSpace}); @@ -83,10 +88,9 @@ public class SyncFileNotEnoughSpaceDialogFragment extends ConfirmationDialogFrag AlertDialog alertDialog = (AlertDialog) getDialog(); if (alertDialog != null) { - themeButtonUtils.themeBorderlessButton(themeColorUtils, - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), - alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL), - alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); + viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), + alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL), + alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)); } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java index eb2b794123..5e140291ff 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.java @@ -24,20 +24,19 @@ import android.app.Activity; import android.app.Dialog; import android.content.DialogInterface; import android.content.Intent; -import android.graphics.Color; import android.graphics.Typeface; import android.os.Bundle; import android.text.TextUtils; import android.text.style.StyleSpan; -import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; -import android.view.ViewGroup; import android.widget.TextView; import com.google.android.material.button.MaterialButton; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; +import com.owncloud.android.databinding.SyncedFoldersSettingsLayoutBinding; import com.owncloud.android.datamodel.MediaFolderType; import com.owncloud.android.datamodel.SyncedFolderDisplayItem; import com.owncloud.android.files.services.NameCollisionPolicy; @@ -47,9 +46,7 @@ import com.owncloud.android.ui.activity.UploadFilesActivity; import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeCheckableUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; @@ -81,10 +78,8 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem private final static float alphaEnabled = 1.0f; private final static float alphaDisabled = 0.7f; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeButtonUtils themeButtonUtils; - @Inject ThemeCheckableUtils themeCheckableUtils; - protected View mView; + @Inject ViewThemeUtils viewThemeUtils; + private CharSequence[] mUploadBehaviorItemStrings; private CharSequence[] mNameCollisionPolicyItemStrings; private SwitchCompat mEnabledSwitch; @@ -104,6 +99,7 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem private boolean behaviourDialogShown; private boolean nameCollisionPolicyDialogShown; private AlertDialog behaviourDialog; + private SyncedFoldersSettingsLayoutBinding binding; public static SyncedFolderPreferencesDialogFragment newInstance(SyncedFolderDisplayItem syncedFolder, int section) { if (syncedFolder == null) { @@ -135,99 +131,82 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem // keep the state of the fragment on configuration changes setRetainInstance(true); - mView = null; + binding = null; mSyncedFolder = getArguments().getParcelable(SYNCED_FOLDER_PARCELABLE); mUploadBehaviorItemStrings = getResources().getTextArray(R.array.pref_behaviour_entries); mNameCollisionPolicyItemStrings = getResources().getTextArray(R.array.pref_name_collision_policy_entries); } - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Log_OC.d(TAG, "onCreateView, savedInstanceState is " + savedInstanceState); - - mView = inflater.inflate(R.layout.synced_folders_settings_layout, container, false); - - setupDialogElements(mView); - setupListeners(mView); - - return mView; - } - /** * find all relevant UI elements and set their values. * - * @param view the parent view + * @param binding the parent binding */ - private void setupDialogElements(View view) { - int accentColor = themeColorUtils.primaryAccentColor(getContext()); - + private void setupDialogElements(SyncedFoldersSettingsLayoutBinding binding) { if (mSyncedFolder.getType().getId() > MediaFolderType.CUSTOM.getId()) { // hide local folder chooser and delete for non-custom folders - view.findViewById(R.id.local_folder_container).setVisibility(View.GONE); - view.findViewById(R.id.delete).setVisibility(View.GONE); + binding.localFolderContainer.setVisibility(View.GONE); + binding.delete.setVisibility(View.GONE); } else if (mSyncedFolder.getId() <= UNPERSISTED_ID) { // Hide delete/enabled for unpersisted custom folders - view.findViewById(R.id.delete).setVisibility(View.GONE); - view.findViewById(R.id.sync_enabled).setVisibility(View.GONE); + binding.delete.setVisibility(View.GONE); + binding.syncEnabled.setVisibility(View.GONE); // auto set custom folder to enabled mSyncedFolder.setEnabled(true); // switch text to create headline - ((TextView) view.findViewById(R.id.synced_folders_settings_title)) - .setText(R.string.autoupload_create_new_custom_folder); + binding.syncedFoldersSettingsTitle.setText(R.string.autoupload_create_new_custom_folder); // disable save button - view.findViewById(R.id.save).setEnabled(false); + binding.save.setEnabled(false); } else { - view.findViewById(R.id.local_folder_container).setVisibility(View.GONE); + binding.localFolderContainer.setVisibility(View.GONE); } // find/saves UI elements - mEnabledSwitch = view.findViewById(R.id.sync_enabled); - themeCheckableUtils.tintSwitch(mEnabledSwitch, themeColorUtils); + mEnabledSwitch = binding.syncEnabled; + viewThemeUtils.androidx.colorSwitchCompat(mEnabledSwitch); - mLocalFolderPath = view.findViewById(R.id.synced_folders_settings_local_folder_path); + mLocalFolderPath = binding.syncedFoldersSettingsLocalFolderPath; - mLocalFolderSummary = view.findViewById(R.id.local_folder_summary); - mRemoteFolderSummary = view.findViewById(R.id.remote_folder_summary); + mLocalFolderSummary = binding.localFolderSummary; + mRemoteFolderSummary = binding.remoteFolderSummary; - mUploadOnWifiCheckbox = view.findViewById(R.id.setting_instant_upload_on_wifi_checkbox); + mUploadOnWifiCheckbox = binding.settingInstantUploadOnWifiCheckbox; - mUploadOnChargingCheckbox = view.findViewById(R.id.setting_instant_upload_on_charging_checkbox); + mUploadOnChargingCheckbox = binding.settingInstantUploadOnChargingCheckbox; - mUploadExistingCheckbox = view.findViewById(R.id.setting_instant_upload_existing_checkbox); + mUploadExistingCheckbox = binding.settingInstantUploadExistingCheckbox; - mUploadUseSubfoldersCheckbox = view.findViewById( - R.id.setting_instant_upload_path_use_subfolders_checkbox); + mUploadUseSubfoldersCheckbox = binding.settingInstantUploadPathUseSubfoldersCheckbox; - themeCheckableUtils.tintCheckbox(accentColor, - mUploadOnWifiCheckbox, - mUploadOnChargingCheckbox, - mUploadExistingCheckbox, - mUploadUseSubfoldersCheckbox); + viewThemeUtils.platform.themeCheckbox(mUploadOnWifiCheckbox, + mUploadOnChargingCheckbox, + mUploadExistingCheckbox, + mUploadUseSubfoldersCheckbox); - mUploadBehaviorSummary = view.findViewById(R.id.setting_instant_behaviour_summary); + mUploadBehaviorSummary = binding.settingInstantBehaviourSummary; - mNameCollisionPolicySummary = view.findViewById(R.id.setting_instant_name_collision_policy_summary); + mNameCollisionPolicySummary = binding.settingInstantNameCollisionPolicySummary; - mCancel = view.findViewById(R.id.cancel); - mSave = view.findViewById(R.id.save); + mCancel = binding.cancel; + mSave = binding.save; - themeButtonUtils.themeBorderlessButton(themeColorUtils, mCancel, mSave); + viewThemeUtils.platform.colorTextButtons(mCancel, mSave); // Set values setEnabled(mSyncedFolder.isEnabled()); if (!TextUtils.isEmpty(mSyncedFolder.getLocalPath())) { mLocalFolderPath.setText( - DisplayUtils.createTextWithSpan( - String.format( - getString(R.string.synced_folders_preferences_folder_path), - mSyncedFolder.getLocalPath()), - mSyncedFolder.getFolderName(), - new StyleSpan(Typeface.BOLD))); + DisplayUtils.createTextWithSpan( + String.format( + getString(R.string.synced_folders_preferences_folder_path), + mSyncedFolder.getLocalPath()), + mSyncedFolder.getFolderName(), + new StyleSpan(Typeface.BOLD))); mLocalFolderSummary.setText(FileStorageUtils.pathToUserFriendlyDisplay( mSyncedFolder.getLocalPath(), getActivity(), @@ -264,13 +243,13 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem mSyncedFolder.setEnabled(enabled); mEnabledSwitch.setChecked(enabled); - setupViews(mView, enabled); + setupViews(binding, enabled); } /** - * set (new) remote path on activity result of the folder picker activity. The result gets originally propagated - * to the underlying activity since the picker is an activity and the result can't get passed to the dialog - * fragment directly. + * set (new) remote path on activity result of the folder picker activity. The result gets originally propagated to + * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment + * directly. * * @param path the remote path to be set */ @@ -281,9 +260,9 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem } /** - * set (new) local path on activity result of the folder picker activity. The result gets originally propagated - * to the underlying activity since the picker is an activity and the result can't get passed to the dialog - * fragment directly. + * set (new) local path on activity result of the folder picker activity. The result gets originally propagated to + * the underlying activity since the picker is an activity and the result can't get passed to the dialog fragment + * directly. * * @param path the local path to be set */ @@ -291,20 +270,20 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem mSyncedFolder.setLocalPath(path); mLocalFolderSummary.setText(FileStorageUtils.pathToUserFriendlyDisplay(path, getActivity(), getResources())); mLocalFolderPath.setText( - DisplayUtils.createTextWithSpan( - String.format( - getString(R.string.synced_folders_preferences_folder_path), - mSyncedFolder.getLocalPath()), - new File(mSyncedFolder.getLocalPath()).getName(), - new StyleSpan(Typeface.BOLD))); + DisplayUtils.createTextWithSpan( + String.format( + getString(R.string.synced_folders_preferences_folder_path), + mSyncedFolder.getLocalPath()), + new File(mSyncedFolder.getLocalPath()).getName(), + new StyleSpan(Typeface.BOLD))); checkAndUpdateSaveButtonState(); } private void checkAndUpdateSaveButtonState() { if (mSyncedFolder.getLocalPath() != null && mSyncedFolder.getRemotePath() != null) { - mView.findViewById(R.id.save).setEnabled(true); + binding.save.setEnabled(true); } else { - mView.findViewById(R.id.save).setEnabled(false); + binding.save.setEnabled(false); } checkWritableFolder(); @@ -312,18 +291,18 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem private void checkWritableFolder() { if (!mSyncedFolder.isEnabled()) { - mView.findViewById(R.id.setting_instant_behaviour_container).setEnabled(false); - mView.findViewById(R.id.setting_instant_behaviour_container).setAlpha(alphaDisabled); + binding.settingInstantBehaviourContainer.setEnabled(false); + binding.settingInstantBehaviourContainer.setAlpha(alphaDisabled); return; } if (mSyncedFolder.getLocalPath() != null && new File(mSyncedFolder.getLocalPath()).canWrite()) { - mView.findViewById(R.id.setting_instant_behaviour_container).setEnabled(true); - mView.findViewById(R.id.setting_instant_behaviour_container).setAlpha(alphaEnabled); + binding.settingInstantBehaviourContainer.setEnabled(true); + binding.settingInstantBehaviourContainer.setAlpha(alphaEnabled); mUploadBehaviorSummary.setText(mUploadBehaviorItemStrings[mSyncedFolder.getUploadActionInteger()]); } else { - mView.findViewById(R.id.setting_instant_behaviour_container).setEnabled(false); - mView.findViewById(R.id.setting_instant_behaviour_container).setAlpha(alphaDisabled); + binding.settingInstantBehaviourContainer.setEnabled(false); + binding.settingInstantBehaviourContainer.setAlpha(alphaDisabled); mSyncedFolder.setUploadAction( getResources().getTextArray(R.array.pref_behaviour_entryValues)[0].toString()); @@ -332,47 +311,38 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem } } - private void setupViews(View view, boolean enable) { + private void setupViews(SyncedFoldersSettingsLayoutBinding binding, boolean enable) { float alpha; if (enable) { alpha = alphaEnabled; } else { alpha = alphaDisabled; } - view.findViewById(R.id.setting_instant_upload_on_wifi_container).setEnabled(enable); - view.findViewById(R.id.setting_instant_upload_on_wifi_container).setAlpha(alpha); + binding.settingInstantUploadOnWifiContainer.setEnabled(enable); + binding.settingInstantUploadOnWifiContainer.setAlpha(alpha); - view.findViewById(R.id.setting_instant_upload_on_charging_container).setEnabled(enable); - view.findViewById(R.id.setting_instant_upload_on_charging_container).setAlpha(alpha); + binding.settingInstantUploadOnChargingContainer.setEnabled(enable); + binding.settingInstantUploadOnChargingContainer.setAlpha(alpha); - view.findViewById(R.id.setting_instant_upload_existing_container).setEnabled(enable); - view.findViewById(R.id.setting_instant_upload_existing_container).setAlpha(alpha); + binding.settingInstantUploadExistingContainer.setEnabled(enable); + binding.settingInstantUploadExistingContainer.setAlpha(alpha); - view.findViewById(R.id.setting_instant_upload_path_use_subfolders_container).setEnabled(enable); - view.findViewById(R.id.setting_instant_upload_path_use_subfolders_container).setAlpha(alpha); + binding.settingInstantUploadPathUseSubfoldersContainer.setEnabled(enable); + binding.settingInstantUploadPathUseSubfoldersContainer.setAlpha(alpha); - view.findViewById(R.id.remote_folder_container).setEnabled(enable); - view.findViewById(R.id.remote_folder_container).setAlpha(alpha); + binding.remoteFolderContainer.setEnabled(enable); + binding.remoteFolderContainer.setAlpha(alpha); - view.findViewById(R.id.local_folder_container).setEnabled(enable); - view.findViewById(R.id.local_folder_container).setAlpha(alpha); + binding.localFolderContainer.setEnabled(enable); + binding.localFolderContainer.setAlpha(alpha); - view.findViewById(R.id.setting_instant_name_collision_policy_container).setEnabled(enable); - view.findViewById(R.id.setting_instant_name_collision_policy_container).setAlpha(alpha); + binding.settingInstantNameCollisionPolicyContainer.setEnabled(enable); + binding.settingInstantNameCollisionPolicyContainer.setAlpha(alpha); - if (enable) { - themeCheckableUtils.tintCheckbox(themeColorUtils.primaryAccentColor(getContext()), - mUploadOnWifiCheckbox, - mUploadOnChargingCheckbox, - mUploadExistingCheckbox, - mUploadUseSubfoldersCheckbox); - } else { - themeCheckableUtils.tintCheckbox(Color.GRAY, - mUploadOnWifiCheckbox, - mUploadOnChargingCheckbox, - mUploadExistingCheckbox, - mUploadUseSubfoldersCheckbox); - } + mUploadOnWifiCheckbox.setEnabled(enable); + mUploadOnChargingCheckbox.setEnabled(enable); + mUploadExistingCheckbox.setEnabled(enable); + mUploadUseSubfoldersCheckbox.setEnabled(enable); checkWritableFolder(); } @@ -380,14 +350,14 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem /** * setup all listeners. * - * @param view the parent view + * @param binding the parent binding */ - private void setupListeners(View view) { + private void setupListeners(SyncedFoldersSettingsLayoutBinding binding) { mSave.setOnClickListener(new OnSyncedFolderSaveClickListener()); mCancel.setOnClickListener(new OnSyncedFolderCancelClickListener()); - view.findViewById(R.id.delete).setOnClickListener(new OnSyncedFolderDeleteClickListener()); + binding.delete.setOnClickListener(new OnSyncedFolderDeleteClickListener()); - view.findViewById(R.id.setting_instant_upload_on_wifi_container).setOnClickListener( + binding.settingInstantUploadOnWifiContainer.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { @@ -396,7 +366,7 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem } }); - view.findViewById(R.id.setting_instant_upload_on_charging_container).setOnClickListener( + binding.settingInstantUploadOnChargingContainer.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { @@ -405,52 +375,52 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem } }); - view.findViewById(R.id.setting_instant_upload_existing_container).setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - mSyncedFolder.setExisting(!mSyncedFolder.isExisting()); - mUploadExistingCheckbox.toggle(); - } - }); + binding.settingInstantUploadExistingContainer.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + mSyncedFolder.setExisting(!mSyncedFolder.isExisting()); + mUploadExistingCheckbox.toggle(); + } + }); - view.findViewById(R.id.setting_instant_upload_path_use_subfolders_container).setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - mSyncedFolder.setSubfolderByDate(!mSyncedFolder.isSubfolderByDate()); - mUploadUseSubfoldersCheckbox.toggle(); - } - }); + binding.settingInstantUploadPathUseSubfoldersContainer.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + mSyncedFolder.setSubfolderByDate(!mSyncedFolder.isSubfolderByDate()); + mUploadUseSubfoldersCheckbox.toggle(); + } + }); - view.findViewById(R.id.remote_folder_container).setOnClickListener(v -> { + binding.remoteFolderContainer.setOnClickListener(v -> { Intent action = new Intent(getActivity(), FolderPickerActivity.class); getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_REMOTE_FOLDER); }); - view.findViewById(R.id.local_folder_container).setOnClickListener(v -> { + binding.localFolderContainer.setOnClickListener(v -> { Intent action = new Intent(getActivity(), UploadFilesActivity.class); action.putExtra(UploadFilesActivity.KEY_LOCAL_FOLDER_PICKER_MODE, true); action.putExtra(REQUEST_CODE_KEY, REQUEST_CODE__SELECT_LOCAL_FOLDER); getActivity().startActivityForResult(action, REQUEST_CODE__SELECT_LOCAL_FOLDER); }); - view.findViewById(R.id.sync_enabled).setOnClickListener(new OnClickListener() { + binding.syncEnabled.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { setEnabled(!mSyncedFolder.isEnabled()); } }); - view.findViewById(R.id.setting_instant_behaviour_container).setOnClickListener( - new OnClickListener() { - @Override - public void onClick(View v) { - showBehaviourDialog(); - } - }); + binding.settingInstantBehaviourContainer.setOnClickListener( + new OnClickListener() { + @Override + public void onClick(View v) { + showBehaviourDialog(); + } + }); - view.findViewById(R.id.setting_instant_name_collision_policy_container).setOnClickListener( + binding.settingInstantNameCollisionPolicyContainer.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { @@ -460,35 +430,38 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem } private void showBehaviourDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); builder.setTitle(R.string.prefs_instant_behaviour_dialogTitle) - .setSingleChoiceItems(getResources().getTextArray(R.array.pref_behaviour_entries), - mSyncedFolder.getUploadActionInteger(), - new - DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mSyncedFolder.setUploadAction( - getResources().getTextArray( - R.array.pref_behaviour_entryValues)[which].toString()); - mUploadBehaviorSummary.setText(SyncedFolderPreferencesDialogFragment - .this.mUploadBehaviorItemStrings[which]); - behaviourDialogShown = false; - dialog.dismiss(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - behaviourDialogShown = false; - } - }); + .setSingleChoiceItems(getResources().getTextArray(R.array.pref_behaviour_entries), + mSyncedFolder.getUploadActionInteger(), + new + DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mSyncedFolder.setUploadAction( + getResources().getTextArray( + R.array.pref_behaviour_entryValues)[which].toString()); + mUploadBehaviorSummary.setText(SyncedFolderPreferencesDialogFragment + .this.mUploadBehaviorItemStrings[which]); + behaviourDialogShown = false; + dialog.dismiss(); + } + }) + .setOnCancelListener(new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + behaviourDialogShown = false; + } + }); behaviourDialogShown = true; + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getActivity(), builder); + behaviourDialog = builder.create(); behaviourDialog.show(); } private void showNameCollisionPolicyDialog() { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); builder.setTitle(R.string.pref_instant_name_collision_policy_dialogTitle) .setSingleChoiceItems(getResources().getTextArray(R.array.pref_name_collision_policy_entries), @@ -497,6 +470,9 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem .setOnCancelListener(dialog -> nameCollisionPolicyDialogShown = false); nameCollisionPolicyDialogShown = true; + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getActivity(), builder); + behaviourDialog = builder.create(); behaviourDialog.show(); } @@ -504,9 +480,19 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - final Dialog dialog = super.onCreateDialog(savedInstanceState); - dialog.setTitle(null); - return dialog; + Log_OC.d(TAG, "onCreateView, savedInstanceState is " + savedInstanceState); + + binding = SyncedFoldersSettingsLayoutBinding.inflate(requireActivity().getLayoutInflater(), null, false); + + setupDialogElements(binding); + setupListeners(binding); + + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); + builder.setView(binding.getRoot()); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); + + return builder.create(); } @Override @@ -534,14 +520,14 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem @Override public void onViewStateRestored(@Nullable Bundle savedInstanceState) { behaviourDialogShown = savedInstanceState != null && - savedInstanceState.getBoolean(BEHAVIOUR_DIALOG_STATE, false); + savedInstanceState.getBoolean(BEHAVIOUR_DIALOG_STATE, false); nameCollisionPolicyDialogShown = savedInstanceState != null && savedInstanceState.getBoolean(NAME_COLLISION_POLICY_DIALOG_STATE, false); if (behaviourDialogShown) { showBehaviourDialog(); } - if (nameCollisionPolicyDialogShown){ + if (nameCollisionPolicyDialogShown) { showNameCollisionPolicyDialog(); } @@ -594,6 +580,7 @@ public class SyncedFolderPreferencesDialogFragment extends DialogFragment implem /** * Get index for name collision selection dialog. + * * @return 0 if ASK_USER, 1 if OVERWRITE, 2 if RENAME, 3 if SKIP, Otherwise: 0 */ static private Integer getSelectionIndexForNameCollisionPolicy(NameCollisionPolicy nameCollisionPolicy) { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java index 233cc36b6b..93209f54a6 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java @@ -68,10 +68,7 @@ import com.owncloud.android.ui.activity.UploadFilesActivity; import com.owncloud.android.ui.adapter.LocalFileListAdapter; import com.owncloud.android.ui.adapter.OCFileListAdapter; import com.owncloud.android.ui.events.SearchEvent; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; -import com.owncloud.android.utils.theme.ThemeLayoutUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; @@ -116,10 +113,8 @@ public class ExtendedListFragment extends Fragment implements @Inject AppPreferences preferences; @Inject UserAccountManager accountManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeLayoutUtils themeLayoutUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; + @Inject ViewThemeUtils viewThemeUtils; + private ScaleGestureDetector mScaleGestureDetector; protected SwipeRefreshLayout mRefreshListLayout; protected MaterialButton mSortButton; @@ -183,13 +178,10 @@ public class ExtendedListFragment extends Fragment implements public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) { final MenuItem item = menu.findItem(R.id.action_search); searchView = (SearchView) MenuItemCompat.getActionView(item); + viewThemeUtils.androidx.themeToolbarSearchView(searchView); closeButton = searchView.findViewById(androidx.appcompat.R.id.search_close_btn); searchView.setOnQueryTextListener(this); searchView.setOnCloseListener(this); - themeToolbarUtils.themeSearchView(searchView, requireContext()); - - SearchView.SearchAutoComplete theTextArea = searchView.findViewById(R.id.search_src_text); - theTextArea.setHighlightColor(themeColorUtils.primaryAccentColor(getContext())); final Handler handler = new Handler(); @@ -347,11 +339,17 @@ public class ExtendedListFragment extends Fragment implements // Pull-down to refresh layout mRefreshListLayout = binding.swipeContainingList; - themeLayoutUtils.colorSwipeRefreshLayout(getContext(), mRefreshListLayout); + viewThemeUtils.androidx.themeSwipeRefreshLayout(mRefreshListLayout); mRefreshListLayout.setOnRefreshListener(this); mSortButton = getActivity().findViewById(R.id.sort_button); + if (mSortButton != null) { + viewThemeUtils.material.colorMaterialTextButton(mSortButton); + } mSwitchGridViewButton = getActivity().findViewById(R.id.switch_grid_view_button); + if (mSwitchGridViewButton != null) { + viewThemeUtils.material.colorMaterialTextButton(mSwitchGridViewButton); + } return v; } @@ -587,8 +585,7 @@ public class ExtendedListFragment extends Fragment implements if (tintIcon) { if (getContext() != null) { mEmptyListIcon.setImageDrawable( - themeDrawableUtils.tintDrawable(icon, - themeColorUtils.primaryColor(getContext(), true))); + viewThemeUtils.platform.tintPrimaryDrawable(getContext(), icon)); } } else { mEmptyListIcon.setImageResource(icon); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java index 90de6aa4d7..4377b02b02 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FeatureFragment.java @@ -1,6 +1,7 @@ package com.owncloud.android.ui.fragment; import android.content.Context; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableString; import android.text.Spanned; @@ -16,18 +17,19 @@ import android.widget.TextView; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.features.FeatureItem; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.Fragment; public class FeatureFragment extends Fragment implements Injectable { private FeatureItem item; - @Inject ThemeDrawableUtils themeDrawableUtils; + @Inject ViewThemeUtils viewThemeUtils; static public FeatureFragment newInstance(FeatureItem item) { FeatureFragment f = new FeatureFragment(); @@ -53,7 +55,8 @@ public class FeatureFragment extends Fragment implements Injectable { ImageView whatsNewImage = view.findViewById(R.id.whatsNewImage); if (item.shouldShowImage()) { - whatsNewImage.setImageDrawable(themeDrawableUtils.tintDrawable(item.getImage(), fontColor)); + final Drawable image = ResourcesCompat.getDrawable(getResources(), item.getImage(), null); + whatsNewImage.setImageDrawable(viewThemeUtils.platform.colorDrawable(image, fontColor)); } TextView whatsNewTitle = view.findViewById(R.id.whatsNewTitle); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java index 19a2abc564..9c4865423a 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java @@ -59,11 +59,7 @@ import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.ui.interfaces.ActivityListInterface; import com.owncloud.android.ui.interfaces.VersionListInterface; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; -import com.owncloud.android.utils.theme.ThemeLayoutUtils; -import com.owncloud.android.utils.theme.ThemeTextInputUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.apache.commons.httpclient.HttpStatus; import org.greenrobot.eventbus.EventBus; @@ -114,11 +110,7 @@ public class FileDetailActivitiesFragment extends Fragment implements @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject ContentResolver contentResolver; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeLayoutUtils themeLayoutUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; - @Inject ThemeTextInputUtils themeTextInputUtils; + @Inject ViewThemeUtils viewThemeUtils; public static FileDetailActivitiesFragment newInstance(OCFile file, User user) { FileDetailActivitiesFragment fragment = new FileDetailActivitiesFragment(); @@ -151,8 +143,8 @@ public class FileDetailActivitiesFragment extends Fragment implements setupView(); - themeLayoutUtils.colorSwipeRefreshLayout(getContext(), binding.swipeContainingEmpty); - themeLayoutUtils.colorSwipeRefreshLayout(getContext(), binding.swipeContainingList); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingEmpty); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList); fetchAndSetData(-1); @@ -183,10 +175,7 @@ public class FileDetailActivitiesFragment extends Fragment implements binding.submitComment.setOnClickListener(v -> submitComment()); - themeTextInputUtils.colorTextInput(binding.commentInputFieldContainer, - binding.commentInputField, - themeColorUtils.primaryColor(getContext()), - themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.material.colorTextInputLayout(binding.commentInputFieldContainer); DisplayUtils.setAvatar(user, this, @@ -245,8 +234,7 @@ public class FileDetailActivitiesFragment extends Fragment implements this, this, clientFactory, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ); binding.list.setAdapter(adapter); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 5ee810c876..bb49671fef 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -72,9 +72,7 @@ import com.owncloud.android.ui.dialog.RenameFileDialogFragment; import com.owncloud.android.ui.events.FavoriteEvent; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeBarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeLayoutUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -116,9 +114,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject FileDataStorageManager storageManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeLayoutUtils themeLayoutUtils; - @Inject ThemeBarUtils themeBarUtils; + @Inject ViewThemeUtils viewThemeUtils; @Inject BackgroundJobManager backgroundJobManager; /** @@ -233,7 +229,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { if (getFile() != null && user != null) { - themeBarUtils.colorHorizontalProgressBar(binding.progressBar, themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.platform.themeHorizontalProgressBar(binding.progressBar); progressListener = new ProgressListener(binding.progressBar); binding.cancelBtn.setOnClickListener(this); binding.favorite.setOnClickListener(this); @@ -257,7 +253,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener, binding.tabLayout.removeAllTabs(); binding.tabLayout.addTab(binding.tabLayout.newTab().setText(R.string.drawer_item_activities).setIcon(R.drawable.ic_activity)); - themeLayoutUtils.colorTabLayout(getContext().getApplicationContext(), binding.tabLayout); + viewThemeUtils.material.themeTabLayout(binding.tabLayout); if (!getFile().isEncrypted()) { binding.tabLayout.addTab(binding.tabLayout.newTab().setText(R.string.share_dialog_title).setIcon(R.drawable.shared_via_users)); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index 446b2b634c..f67dd70993 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -61,11 +61,7 @@ import com.owncloud.android.ui.fragment.util.FileDetailSharingFragmentHelper; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.utils.ClipboardUtil; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeAvatarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -101,11 +97,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; - @Inject ThemeSnackbarUtils themeSnackbarUtils; - @Inject ThemeDrawableUtils themeDrawableUtils; - @Inject ThemeAvatarUtils themeAvatarUtils; + @Inject ViewThemeUtils viewThemeUtils; public static FileDetailSharingFragment newInstance(OCFile file, User user) { FileDetailSharingFragment fragment = new FileDetailSharingFragment(); @@ -171,8 +163,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda this, userId, user, - themeColorUtils, - themeAvatarUtils)); + viewThemeUtils)); binding.sharesList.setLayoutManager(new LinearLayoutManager(getContext())); setupView(); @@ -206,7 +197,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda (SearchManager) fileActivity.getSystemService(Context.SEARCH_SERVICE), binding.searchView, fileActivity.getComponentName()); - themeToolbarUtils.themeSearchView(binding.searchView, requireContext()); + viewThemeUtils.androidx.themeToolbarSearchView(binding.searchView); if (file.canReshare()) { binding.searchView.setQueryHint(getResources().getString(R.string.share_search)); @@ -289,7 +280,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda private void showSendLinkTo(OCShare publicShare) { if (file.isSharedViaLink()) { if (TextUtils.isEmpty(publicShare.getShareLink())) { - fileOperationsHelper.getFileWithLink(file, themeSnackbarUtils); + fileOperationsHelper.getFileWithLink(file, viewThemeUtils); } else { FileDisplayActivity.showShareLinkDialog(fileActivity, file, publicShare.getShareLink()); } @@ -299,7 +290,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda public void copyLink(OCShare share) { if (file.isSharedViaLink()) { if (TextUtils.isEmpty(share.getShareLink())) { - fileOperationsHelper.getFileWithLink(file, themeSnackbarUtils); + fileOperationsHelper.getFileWithLink(file, viewThemeUtils); } else { ClipboardUtil.copyToClipboard(getActivity(), share.getShareLink()); } @@ -314,7 +305,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda @Override @VisibleForTesting public void showSharingMenuActionSheet(OCShare share) { - new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share).show(); + new FileDetailSharingMenuBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); } /** @@ -324,7 +315,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda */ @Override public void showPermissionsDialog(OCShare share) { - new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share).show(); + new QuickSharingPermissionsBottomSheetDialog(fileActivity, this, share, viewThemeUtils).show(); } /** @@ -395,8 +386,7 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda shareWith, fileActivity, clientFactory, - themeColorUtils, - themeDrawableUtils).execute(); + viewThemeUtils).execute(); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java index 83dd05421a..aea75ca074 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java @@ -31,6 +31,7 @@ import com.owncloud.android.databinding.FileDetailsSharingMenuBottomSheetFragmen import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.utils.theme.ViewThemeUtils; /** * File Details Sharing option menus {@link android.app.Dialog} styled as a bottom sheet for main actions. @@ -39,13 +40,16 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog { private FileDetailsSharingMenuBottomSheetFragmentBinding binding; private final FileDetailsSharingMenuBottomSheetActions actions; private final OCShare ocShare; + private final ViewThemeUtils viewThemeUtils; public FileDetailSharingMenuBottomSheetDialog(FileActivity fileActivity, FileDetailsSharingMenuBottomSheetActions actions, - OCShare ocShare) { + OCShare ocShare, + ViewThemeUtils viewThemeUtils) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -58,6 +62,14 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog { getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } + viewThemeUtils.platform.themeDialog(binding.getRoot()); + + viewThemeUtils.platform.colorImageView(binding.menuIconAddAnotherLink); + viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions); + viewThemeUtils.platform.colorImageView(binding.menuIconSendLink); + viewThemeUtils.platform.colorImageView(binding.menuIconUnshare); + viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail); + updateUI(); setupClickListener(); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt index 9c07c757cb..e3be7adefd 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailsSharingProcessFragment.kt @@ -29,6 +29,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.databinding.FileDetailsSharingProcessFragmentBinding import com.owncloud.android.datamodel.OCFile @@ -41,8 +42,10 @@ import com.owncloud.android.ui.fragment.util.SharingMenuHelper import com.owncloud.android.ui.helpers.FileOperationsHelper import com.owncloud.android.utils.ClipboardUtil import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import java.text.SimpleDateFormat import java.util.Date +import javax.inject.Inject /** * Fragment class to show share permission options, set expiration date, change label, set password, send note @@ -53,7 +56,10 @@ import java.util.Date * 2. This will handle both Advanced Permissions and Send New Email functionality for existing shares to modify them. */ @Suppress("TooManyFunctions") -class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialogFragment.OnExpiryDateListener { +class FileDetailsSharingProcessFragment : + Fragment(), + Injectable, + ExpirationDatePickerDialogFragment.OnExpiryDateListener { companion object { const val TAG = "FileDetailsSharingProcessFragment" @@ -100,6 +106,9 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog } } + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + private lateinit var onEditShareListener: FileDetailSharingFragment.OnEditShareListener private lateinit var binding: FileDetailsSharingProcessFragmentBinding @@ -164,6 +173,31 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog showShareProcessSecond() } implementClickEvents() + + themeView() + } + + private fun themeView() { + viewThemeUtils.platform.colorPrimaryTextViewElement(binding.shareProcessEditShareLink) + viewThemeUtils.platform.colorPrimaryTextViewElement(binding.shareProcessAdvancePermissionTitle) + + viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionReadOnly) + viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionUploadEditing) + viewThemeUtils.platform.themeRadioButton(binding.shareProcessPermissionFileDrop) + + viewThemeUtils.platform.themeCheckbox(binding.shareProcessAllowResharingCheckbox) + + viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetPasswordSwitch) + viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessSetExpDateSwitch) + viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessHideDownloadCheckbox) + viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessChangeNameSwitch) + + viewThemeUtils.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer) + viewThemeUtils.material.colorTextInputLayout(binding.shareProcessChangeNameContainer) + viewThemeUtils.material.colorTextInputLayout(binding.noteContainer) + + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext) + viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.shareProcessBtnCancel) } override fun onConfigurationChanged(newConfig: Configuration) { @@ -251,7 +285,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog // external share if (shareType == ShareType.EMAIL) { binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameEt.visibility = View.GONE + binding.shareProcessChangeNameContainer.visibility = View.GONE updateViewForExternalAndLinkShare() } // link share @@ -259,7 +293,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog updateViewForExternalAndLinkShare() binding.shareProcessChangeNameSwitch.visibility = View.VISIBLE if (share != null) { - binding.shareProcessChangeNameEt.setText(share?.label) + binding.shareProcessChangeName.setText(share?.label) binding.shareProcessChangeNameSwitch.isChecked = !TextUtils.isEmpty(share?.label) } showChangeNameInput(binding.shareProcessChangeNameSwitch.isChecked) @@ -267,7 +301,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog // internal share else { binding.shareProcessChangeNameSwitch.visibility = View.GONE - binding.shareProcessChangeNameEt.visibility = View.GONE + binding.shareProcessChangeNameContainer.visibility = View.GONE binding.shareProcessHideDownloadCheckbox.visibility = View.GONE binding.shareProcessAllowResharingCheckbox.visibility = View.VISIBLE binding.shareProcessSetPasswordSwitch.visibility = View.GONE @@ -383,9 +417,9 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog } private fun showChangeNameInput(isChecked: Boolean) { - binding.shareProcessChangeNameEt.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessChangeNameContainer.visibility = if (isChecked) View.VISIBLE else View.GONE if (!isChecked) { - binding.shareProcessChangeNameEt.setText("") + binding.shareProcessChangeName.setText("") } } @@ -417,7 +451,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog } private fun showPasswordInput(isChecked: Boolean) { - binding.shareProcessEnterPassword.visibility = if (isChecked) View.VISIBLE else View.GONE + binding.shareProcessEnterPasswordContainer.visibility = if (isChecked) View.VISIBLE else View.GONE // reset the password if switch is unchecked if (!isChecked) { @@ -462,7 +496,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog } if (binding.shareProcessChangeNameSwitch.isChecked && - binding.shareProcessChangeNameEt.text?.trim().isNullOrEmpty() + binding.shareProcessChangeName.text?.trim().isNullOrEmpty() ) { DisplayUtils.showSnackMessage(binding.root, R.string.label_empty) return @@ -499,7 +533,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog binding.shareProcessHideDownloadCheckbox.isChecked, binding.shareProcessEnterPassword.text.toString().trim(), chosenExpDateInMills, - binding.shareProcessChangeNameEt.text.toString().trim() + binding.shareProcessChangeName.text.toString().trim() ) // copy the share link if available if (!TextUtils.isEmpty(share?.shareLink)) { @@ -527,7 +561,7 @@ class FileDetailsSharingProcessFragment : Fragment(), ExpirationDatePickerDialog binding.shareProcessEnterPassword.text.toString().trim(), chosenExpDateInMills, noteText, - binding.shareProcessChangeNameEt.text.toString().trim() + binding.shareProcessChangeName.text.toString().trim() ) } removeCurrentFragment() diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java index 03637712db..cacaca6a4c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java @@ -34,7 +34,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import com.nextcloud.utils.view.FastScroll; +import com.nextcloud.utils.view.FastScrollUtils; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; @@ -47,7 +47,6 @@ import com.owncloud.android.ui.adapter.GalleryAdapter; import com.owncloud.android.ui.asynctasks.GallerySearchTask; import com.owncloud.android.ui.events.ChangeMenuEvent; import com.owncloud.android.ui.fragment.util.GalleryFastScrollViewHelper; -import com.owncloud.android.utils.theme.ThemeMenuUtils; import javax.inject.Inject; @@ -74,8 +73,8 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme private OCFile remoteFile; private GalleryFragmentBottomSheetDialog galleryFragmentBottomSheetDialog; - @Inject ThemeMenuUtils themeMenuUtils; @Inject FileDataStorageManager fileDataStorageManager; + @Inject FastScrollUtils fastScrollUtils; @Override public void onCreate(Bundle savedInstanceState) { @@ -139,8 +138,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme this, preferences, mContainerActivity, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); setRecyclerViewAdapter(mAdapter); @@ -149,11 +147,9 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme mAdapter.setLayoutManager(layoutManager); getRecyclerView().setLayoutManager(layoutManager); - FastScroll.applyFastScroll(requireContext(), - themeColorUtils, - themeDrawableUtils, - getRecyclerView(), - new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter)); + fastScrollUtils.applyFastScroll( + getRecyclerView(), + new GalleryFastScrollViewHelper(getRecyclerView(), mAdapter)); } @Override @@ -252,8 +248,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme MenuItem menuItem = menu.findItem(R.id.action_three_dot_icon); if (menuItem != null) { - themeMenuUtils.tintMenuIcon(menuItem, - themeColorUtils.appBarPrimaryFontColor(requireContext())); + viewThemeUtils.platform.colorMenuItemText(requireContext(), menuItem); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt index d1fb2f84bb..1199018795 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/GalleryFragmentBottomSheetDialog.kt @@ -26,11 +26,17 @@ import android.view.View import android.view.ViewGroup import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.nextcloud.client.di.Injectable import com.owncloud.android.databinding.FragmentGalleryBottomSheetBinding +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject class GalleryFragmentBottomSheetDialog( private val actions: GalleryFragmentBottomSheetActions -) : BottomSheetDialogFragment() { +) : BottomSheetDialogFragment(), Injectable { + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + private lateinit var binding: FragmentGalleryBottomSheetBinding private lateinit var mBottomBehavior: BottomSheetBehavior<*> private var currentMediaState: MediaState = MediaState.MEDIA_STATE_DEFAULT @@ -52,7 +58,17 @@ class GalleryFragmentBottomSheetDialog( mBottomBehavior.state = BottomSheetBehavior.STATE_EXPANDED } - private fun setupLayout() { + fun setupLayout() { + listOf( + binding.tickMarkShowImages, + binding.tickMarkShowVideo, + binding.hideImagesImageview, + binding.hideVideoImageView, + binding.selectMediaFolderImageView + ).forEach { + viewThemeUtils.platform.colorImageView(it) + } + when (currentMediaState) { MediaState.MEDIA_STATE_PHOTOS_ONLY -> { binding.tickMarkShowImages.visibility = View.VISIBLE diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java index 8d8bfa0881..db5e8dc4a4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/LocalFileListFragment.java @@ -135,8 +135,7 @@ public class LocalFileListFragment extends ExtendedListFragment implements this, preferences, getActivity(), - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); setRecyclerViewAdapter(mAdapter); listDirectory(mContainerActivity.getInitialDirectory()); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java index 741c09cb0c..6db23e9a8b 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java @@ -22,9 +22,7 @@ package com.owncloud.android.ui.fragment; import android.os.Bundle; import android.view.View; -import android.view.ViewGroup; -import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.gson.Gson; import com.nextcloud.client.account.User; @@ -42,11 +40,8 @@ import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.ui.activity.AppScanActivity; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; import com.owncloud.android.utils.theme.ThemeUtils; - -import javax.inject.Inject; +import com.owncloud.android.utils.theme.ViewThemeUtils; /** * FAB menu {@link android.app.Dialog} styled as a bottom sheet for main actions. @@ -59,9 +54,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In private final DeviceInfo deviceInfo; private final User user; private final OCFile file; - private final ThemeColorUtils themeColorUtils; private final ThemeUtils themeUtils; - private final ThemeDrawableUtils themeDrawableUtils; + private final ViewThemeUtils viewThemeUtils; public OCFileListBottomSheetDialog(FileActivity fileActivity, @@ -69,18 +63,16 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In DeviceInfo deviceInfo, User user, OCFile file, - ThemeColorUtils themeColorUtils, ThemeUtils themeUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { super(fileActivity); this.actions = actions; this.fileActivity = fileActivity; this.deviceInfo = deviceInfo; this.user = user; this.file = file; - this.themeColorUtils = themeColorUtils; this.themeUtils = themeUtils; - this.themeDrawableUtils = themeDrawableUtils; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -89,15 +81,12 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In binding = FileListActionsBottomSheetFragmentBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - if (getWindow() != null) { - getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - } - - int primaryColor = themeColorUtils.primaryColor(getContext(), true); - themeDrawableUtils.tintDrawable(binding.menuIconUploadFiles.getDrawable(), primaryColor); - themeDrawableUtils.tintDrawable(binding.menuIconUploadFromApp.getDrawable(), primaryColor); - themeDrawableUtils.tintDrawable(binding.menuIconDirectCameraUpload.getDrawable(), primaryColor); - themeDrawableUtils.tintDrawable(binding.menuIconMkdir.getDrawable(), primaryColor); + viewThemeUtils.platform.colorImageView(binding.menuIconUploadFiles); + viewThemeUtils.platform.colorImageView(binding.menuIconUploadFromApp); + viewThemeUtils.platform.colorImageView(binding.menuIconDirectCameraUpload); + viewThemeUtils.platform.colorImageView(binding.menuIconScanDocUpload); + viewThemeUtils.platform.colorImageView(binding.menuIconMkdir); + viewThemeUtils.platform.colorImageView(binding.menuIconAddFolderInfo); binding.addToCloud.setText(getContext().getResources().getString(R.string.add_to_cloud, themeUtils.getDefaultDisplayNameForRootFolder(getContext()))); @@ -135,10 +124,8 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In creatorViewBinding.creatorThumbnail.setImageDrawable( MimeTypeUtil.getFileTypeIcon(creator.getMimetype(), creator.getExtension(), - user, - getContext(), - themeColorUtils, - themeDrawableUtils)); + creatorViewBinding.creatorThumbnail.getContext(), + viewThemeUtils)); creatorView.setOnClickListener(v -> { actions.showTemplate(creator, creatorViewBinding.creatorName.getText().toString()); @@ -165,19 +152,17 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In // != "": info set -> hide button if (file.getRichWorkspace() == null || !"".equals(file.getRichWorkspace())) { binding.menuCreateRichWorkspace.setVisibility(View.GONE); + binding.menuCreateRichWorkspaceDivider.setVisibility(View.GONE); } else { binding.menuCreateRichWorkspace.setVisibility(View.VISIBLE); + binding.menuCreateRichWorkspaceDivider.setVisibility(View.VISIBLE); } } else { binding.menuCreateRichWorkspace.setVisibility(View.GONE); + binding.menuCreateRichWorkspaceDivider.setVisibility(View.GONE); } setupClickListener(); - - setOnShowListener(d -> - BottomSheetBehavior.from((View) binding.getRoot().getParent()) - .setPeekHeight(binding.getRoot().getMeasuredHeight()) - ); } private void setupClickListener() { diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt index 810f9ed8e4..e9c6646cf4 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialogFragment.kt @@ -29,9 +29,8 @@ import com.nextcloud.client.device.DeviceInfo import com.nextcloud.client.di.Injectable import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.activity.FileActivity -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils import com.owncloud.android.utils.theme.ThemeUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject class OCFileListBottomSheetDialogFragment( @@ -42,14 +41,11 @@ class OCFileListBottomSheetDialogFragment( private val file: OCFile ) : DialogFragment(), Injectable { - @Inject - lateinit var themeColorUtils: ThemeColorUtils - @Inject lateinit var themeUtils: ThemeUtils @Inject - lateinit var themeDrawableUtils: ThemeDrawableUtils + lateinit var viewThemeUtils: ViewThemeUtils override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return OCFileListBottomSheetDialog( @@ -58,9 +54,8 @@ class OCFileListBottomSheetDialogFragment( deviceInfo, user, file, - themeColorUtils, themeUtils, - themeDrawableUtils + viewThemeUtils ) } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index a188cddbfd..b9c84e9cf0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -27,7 +27,6 @@ package com.owncloud.android.ui.fragment; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; @@ -43,7 +42,6 @@ import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.Toast; -import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.behavior.HideBottomViewOnScrollBehavior; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; @@ -60,7 +58,7 @@ import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.client.utils.Throttler; import com.nextcloud.common.NextcloudClient; -import com.nextcloud.utils.view.FastScroll; +import com.nextcloud.utils.view.FastScrollUtils; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; @@ -109,11 +107,8 @@ import com.owncloud.android.utils.EncryptionUtils; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ThemeAvatarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeFabUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.apache.commons.httpclient.HttpStatus; import org.greenrobot.eventbus.EventBus; @@ -135,6 +130,7 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.content.ContextCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.FragmentActivity; import androidx.recyclerview.widget.GridLayoutManager; @@ -195,13 +191,11 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject Throttler throttler; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeFabUtils themeFabUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; @Inject ThemeUtils themeUtils; - @Inject ThemeAvatarUtils themeAvatarUtils; @Inject ArbitraryDataProvider arbitraryDataProvider; @Inject BackgroundJobManager backgroundJobManager; + @Inject ViewThemeUtils viewThemeUtils; + @Inject FastScrollUtils fastScrollUtils; protected FileFragment.ContainerActivity mContainerActivity; @@ -321,7 +315,7 @@ public class OCFileListFragment extends ExtendedListFragment implements mFabMain = requireActivity().findViewById(R.id.fab_main); if (mFabMain != null) { // is not available in FolderPickerActivity - themeFabUtils.colorFloatingActionButton(mFabMain, R.drawable.ic_plus, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } Log_OC.i(TAG, "onCreateView() end"); @@ -426,14 +420,12 @@ public class OCFileListFragment extends ExtendedListFragment implements this, hideItemOptions, isGridViewPreferred(mFile), - themeColorUtils, - themeDrawableUtils, - themeAvatarUtils + viewThemeUtils ); setRecyclerViewAdapter(mAdapter); - FastScroll.applyFastScroll(requireContext(), themeColorUtils, themeDrawableUtils, getRecyclerView()); + fastScrollUtils.applyFastScroll(getRecyclerView()); } protected void prepareCurrentSearch(SearchEvent event) { @@ -472,7 +464,7 @@ public class OCFileListFragment extends ExtendedListFragment implements FileActivity activity = (FileActivity) getActivity(); if (mFabMain != null) { // is not available in FolderPickerActivity - themeFabUtils.colorFloatingActionButton(mFabMain, R.drawable.ic_plus, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); mFabMain.setOnClickListener(v -> { final OCFileListBottomSheetDialogFragment dialog = new OCFileListBottomSheetDialogFragment(activity, @@ -723,7 +715,9 @@ public class OCFileListFragment extends ExtendedListFragment implements mode.invalidate(); //set actionMode color - themeToolbarUtils.colorStatusBar(getActivity(), themeColorUtils.actionModeColor(requireContext())); + viewThemeUtils.platform.colorStatusBar( + getActivity(), + ContextCompat.getColor(getContext(), R.color.action_mode_background)); // hide FAB in multi selection mode setFabVisible(false); @@ -784,6 +778,11 @@ public class OCFileListFragment extends ExtendedListFragment implements setFabVisible(true); } + Activity activity = getActivity(); + if (activity != null) { + viewThemeUtils.platform.resetStatusBar(activity); + } + getCommonAdapter().setMultiSelect(false); getCommonAdapter().clearCheckedItems(); } @@ -827,7 +826,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Override public void onPrepareOptionsMenu(@NonNull Menu menu) { - if (mOriginalMenuItems.size() == 0) { + if (mOriginalMenuItems.isEmpty()) { mOriginalMenuItems.add(menu.findItem(R.id.action_search)); } @@ -1743,10 +1742,11 @@ public class OCFileListFragment extends ExtendedListFragment implements protected void setTitle(final String title) { getActivity().runOnUiThread(() -> { if (getActivity() != null) { - ActionBar actionBar = ((FileDisplayActivity) getActivity()).getSupportActionBar(); + final ActionBar actionBar = ((FileDisplayActivity) getActivity()).getSupportActionBar(); + final Context context = getContext(); - if (actionBar != null) { - themeToolbarUtils.setColoredTitle(actionBar, title, getContext()); + if (actionBar != null && context != null) { + viewThemeUtils.files.themeActionBar(context, actionBar, title); } } }); @@ -1871,7 +1871,7 @@ public class OCFileListFragment extends ExtendedListFragment implements getActivity().runOnUiThread(() -> { if (visible) { mFabMain.show(); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.hide(); } @@ -1921,10 +1921,10 @@ public class OCFileListFragment extends ExtendedListFragment implements getActivity().runOnUiThread(() -> { if (enabled) { mFabMain.setEnabled(true); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext()); + viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.setEnabled(false); - themeFabUtils.colorFloatingActionButton(mFabMain, requireContext(), Color.GRAY); + viewThemeUtils.material.themeFAB(mFabMain); } }); } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt b/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt index b1fb38d25e..564773e90c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ProfileBottomSheetDialog.kt @@ -39,8 +39,7 @@ import com.owncloud.android.R import com.owncloud.android.databinding.ProfileBottomSheetActionBinding import com.owncloud.android.databinding.ProfileBottomSheetFragmentBinding import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils /** * Show actions of an user @@ -49,8 +48,7 @@ class ProfileBottomSheetDialog( private val fileActivity: FragmentActivity, private val user: User, private val hoverCard: HoverCard, - private val themeColorUtils: ThemeColorUtils, - private val themeDrawableUtils: ThemeDrawableUtils + private val viewThemeUtils: ViewThemeUtils ) : BottomSheetDialog(fileActivity), DisplayUtils.AvatarGenerationListener { private var _binding: ProfileBottomSheetFragmentBinding? = null @@ -64,7 +62,8 @@ class ProfileBottomSheetDialog( if (window != null) { window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } - val primaryColor = themeColorUtils.primaryColor(context, true) + + viewThemeUtils.platform.themeDialog(binding.root) binding.icon.tag = hoverCard.userId DisplayUtils.setAvatar( @@ -106,7 +105,7 @@ class ProfileBottomSheetDialog( null ) ) - themeDrawableUtils.tintDrawable(actionBinding.icon.drawable, primaryColor) + viewThemeUtils.platform.tintPrimaryDrawable(context, actionBinding.icon.drawable) creatorView.setOnClickListener { v: View? -> send(hoverCard.userId, action) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java index 2725f047c6..0e337dbdd3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/QuickSharingPermissionsBottomSheetDialog.java @@ -34,6 +34,7 @@ import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.adapter.QuickSharingPermissionsAdapter; import com.owncloud.android.ui.fragment.util.SharingMenuHelper; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; @@ -53,14 +54,17 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog private final QuickPermissionSharingBottomSheetActions actions; private final FileActivity fileActivity; private final OCShare ocShare; + private final ViewThemeUtils viewThemeUtils; public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity, QuickPermissionSharingBottomSheetActions actions, - OCShare ocShare) { + OCShare ocShare, + ViewThemeUtils viewThemeUtils) { super(fileActivity); this.actions = actions; this.ocShare = ocShare; this.fileActivity = fileActivity; + this.viewThemeUtils = viewThemeUtils; } @Override @@ -73,6 +77,8 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } + viewThemeUtils.platform.themeDialog(binding.getRoot()); + setUpRecyclerView(); setOnShowListener(d -> BottomSheetBehavior.from((View) binding.getRoot().getParent()) @@ -82,17 +88,21 @@ public class QuickSharingPermissionsBottomSheetDialog extends BottomSheetDialog private void setUpRecyclerView() { List quickPermissionModelList = getQuickPermissionList(); - QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter(quickPermissionModelList, new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { - @Override - public void onPermissionChanged(int position) { - handlePermissionChanged(quickPermissionModelList, position); - } + QuickSharingPermissionsAdapter adapter = new QuickSharingPermissionsAdapter( + quickPermissionModelList, + new QuickSharingPermissionsAdapter.QuickSharingPermissionViewHolder.OnPermissionChangeListener() { + @Override + public void onPermissionChanged(int position) { + handlePermissionChanged(quickPermissionModelList, position); + } - @Override - public void onDismissSheet() { - dismiss(); - } - }); + @Override + public void onDismissSheet() { + dismiss(); + } + }, + viewThemeUtils + ); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(fileActivity); binding.rvQuickSharePermissions.setLayoutManager(linearLayoutManager); binding.rvQuickSharePermissions.setAdapter(adapter); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt index 846b4f5fd3..962d9eb0d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/UnifiedSearchFragment.kt @@ -54,8 +54,7 @@ import com.owncloud.android.ui.unifiedsearch.ProviderID import com.owncloud.android.ui.unifiedsearch.UnifiedSearchSection import com.owncloud.android.ui.unifiedsearch.UnifiedSearchViewModel import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject /** @@ -84,10 +83,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface lateinit var clientFactory: ClientFactory @Inject - lateinit var themeColorUtils: ThemeColorUtils - - @Inject - lateinit var themeDrawableUtils: ThemeDrawableUtils + lateinit var viewThemeUtils: ViewThemeUtils override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -127,10 +123,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface binding.emptyList.emptyListViewText.text = requireContext().getString(R.string.file_list_empty_unified_search_no_results) binding.emptyList.emptyListIcon.setImageDrawable( - themeDrawableUtils.tintDrawable( - R.drawable.ic_search_grey, - themeColorUtils.primaryColor(context, true) - ) + viewThemeUtils.platform.tintPrimaryDrawable(requireContext(), R.drawable.ic_search_grey) ) } } @@ -186,8 +179,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface currentAccountProvider.user, clientFactory, requireContext(), - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) adapter.shouldShowFooters(true) adapter.setLayoutManager(gridLayoutManager) @@ -235,6 +227,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { val item = menu.findItem(R.id.action_search) val searchView = MenuItemCompat.getActionView(item) as SearchView + viewThemeUtils.androidx.themeToolbarSearchView(searchView) searchView.setQuery(vm.query.value, false) searchView.setOnQueryTextListener(this) searchView.isIconified = false diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java index 547087f80e..07fedb17a7 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.java @@ -37,7 +37,6 @@ import android.widget.Toast; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.BackgroundJobManager; -import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.java.util.Optional; import com.owncloud.android.R; import com.owncloud.android.databinding.BackupFragmentBinding; @@ -53,11 +52,8 @@ import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.PermissionUtil; -import com.owncloud.android.utils.theme.ThemeButtonUtils; -import com.owncloud.android.utils.theme.ThemeCheckableUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.Calendar; @@ -91,12 +87,10 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD private BackupFragmentBinding binding; @Inject BackgroundJobManager backgroundJobManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; @Inject ThemeUtils themeUtils; - @Inject ThemeCheckableUtils themeCheckableUtils; - @Inject ThemeButtonUtils themeButtonUtils; + @Inject ArbitraryDataProvider arbitraryDataProvider; + @Inject ViewThemeUtils viewThemeUtils; private Date selectedDate; private boolean calendarPickerOpen; @@ -156,16 +150,14 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD ActionBar actionBar = contactsPreferenceActivity != null ? contactsPreferenceActivity.getSupportActionBar() : null; if (actionBar != null) { - themeToolbarUtils.setColoredTitle(actionBar, getString(R.string.backup_title), getContext()); - actionBar.setDisplayHomeAsUpEnabled(true); - themeToolbarUtils.tintBackButton(actionBar, getContext()); + viewThemeUtils.files.themeActionBar(requireContext(), actionBar, R.string.backup_title); } - themeCheckableUtils.tintSwitch(binding.contacts, themeColorUtils); - themeCheckableUtils.tintSwitch(binding.calendar, themeColorUtils); - themeCheckableUtils.tintSwitch(binding.dailyBackup, themeColorUtils); + viewThemeUtils.androidx.colorSwitchCompat(binding.contacts); + viewThemeUtils.androidx.colorSwitchCompat(binding.calendar); + viewThemeUtils.androidx.colorSwitchCompat(binding.dailyBackup); binding.dailyBackup.setChecked(arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)); @@ -202,12 +194,11 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD calendarPickerOpen = true; } - themeButtonUtils.colorPrimaryButton(binding.backupNow, getContext(), themeColorUtils); - themeButtonUtils.themeBorderlessButton(themeColorUtils, binding.contactsDatepicker); + viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.backupNow); + viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.contactsDatepicker); - int primaryAccentColor = themeColorUtils.primaryAccentColor(getContext()); - binding.dataToBackUpTitle.setTextColor(primaryAccentColor); - binding.backupSettingsTitle.setTextColor(primaryAccentColor); + viewThemeUtils.platform.colorTextView(binding.dataToBackUpTitle); + viewThemeUtils.platform.colorTextView(binding.backupSettingsTitle); return view; } @@ -292,7 +283,7 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD if (folder != null) { RefreshFolderOperation operation = new RefreshFolderOperation(folder, System.currentTimeMillis(), - false, false, storageManager, user, context); + false, false, storageManager, user, context); RemoteOperationResult result = operation.execute(user, context); return result.isSuccess(); @@ -312,7 +303,7 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD Collections.sort(backupFiles, new AlphanumComparator<>()); if (backupFiles == null || backupFiles.isEmpty()) { - binding.contactsDatepicker.setVisibility(View.GONE); + binding.contactsDatepicker.setVisibility(View.INVISIBLE); } else { binding.contactsDatepicker.setVisibility(View.VISIBLE); } @@ -464,7 +455,7 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD backgroundJobManager.cancelPeriodicCalendarBackup(user); } - arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), + arbitraryDataProvider.storeOrUpdateKeyValue(user.getAccountName(), PREFERENCE_CONTACTS_AUTOMATIC_BACKUP, String.valueOf(enabled)); } @@ -562,15 +553,15 @@ public class BackupFragment extends FileFragment implements DatePickerDialog.OnD datePickerDialog.setTitle(""); datePickerDialog.show(); - datePickerDialog.getButton(DatePickerDialog.BUTTON_NEGATIVE).setTextColor(themeColorUtils.primaryColor(getContext(), true)); - datePickerDialog.getButton(DatePickerDialog.BUTTON_POSITIVE).setTextColor(themeColorUtils.primaryColor(getContext(), true)); + viewThemeUtils.platform.colorTextButtons(datePickerDialog.getButton(DatePickerDialog.BUTTON_NEGATIVE), + datePickerDialog.getButton(DatePickerDialog.BUTTON_POSITIVE)); // set background to transparent datePickerDialog.getButton(DatePickerDialog.BUTTON_NEGATIVE).setBackgroundColor(0x00000000); datePickerDialog.getButton(DatePickerDialog.BUTTON_POSITIVE).setBackgroundColor(0x00000000); } else { DisplayUtils.showSnackMessage(getView().findViewById(R.id.contacts_linear_layout), - R.string.contacts_preferences_something_strange_happened); + R.string.contacts_preferences_something_strange_happened); } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt index 7c7de75c2e..dec70b3342 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListAdapter.kt @@ -26,7 +26,6 @@ import android.content.Context import android.content.res.Resources import android.database.Cursor import android.graphics.BitmapFactory -import android.graphics.PorterDuff import android.graphics.drawable.Drawable import android.provider.ContactsContract import android.view.LayoutInflater @@ -51,7 +50,7 @@ import com.owncloud.android.ui.TextDrawable import com.owncloud.android.ui.fragment.contactsbackup.BackupListFragment.getDisplayName import com.owncloud.android.utils.BitmapUtils import com.owncloud.android.utils.DisplayUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import ezvcard.VCard import ezvcard.property.Photo import third_parties.sufficientlysecure.AndroidCalendar @@ -64,7 +63,7 @@ class BackupListAdapter( private val checkedCalendars: HashMap = HashMap(), val backupListFragment: BackupListFragment, val context: Context, - private val themeColorUtils: ThemeColorUtils + private val viewThemeUtils: ViewThemeUtils ) : SectionedRecyclerViewAdapter() { private val calendarFiles = arrayListOf() private val contacts = arrayListOf() @@ -160,7 +159,7 @@ class BackupListAdapter( override fun onBindHeaderViewHolder(holder: SectionedViewHolder?, section: Int, expanded: Boolean) { val headerViewHolder = holder as BackupListHeaderViewHolder - headerViewHolder.binding.name.setTextColor(themeColorUtils.primaryColor(context)) + viewThemeUtils.platform.colorPrimaryTextViewElement(headerViewHolder.binding.name) if (section == SECTION_CALENDAR) { headerViewHolder.binding.name.text = context.resources.getString(R.string.calendars) @@ -207,6 +206,7 @@ class BackupListAdapter( setChecked(checkedVCards.contains(position), holder.binding.name) holder.binding.name.text = getDisplayName(vCard) + viewThemeUtils.platform.themeCheckedTextView(holder.binding.name) // photo if (vCard.photos.size > 0) { @@ -229,24 +229,13 @@ class BackupListAdapter( private fun setChecked(checked: Boolean, checkedTextView: CheckedTextView) { checkedTextView.isChecked = checked - if (checked) { - checkedTextView.checkMarkDrawable - .setColorFilter(themeColorUtils.primaryColor(context), PorterDuff.Mode.SRC_ATOP) - } else { - checkedTextView.checkMarkDrawable.clearColorFilter() - } } private fun toggleVCard(holder: ContactItemViewHolder, position: Int) { holder.binding.name.isChecked = !holder.binding.name.isChecked if (holder.binding.name.isChecked) { - holder.binding.name.checkMarkDrawable.setColorFilter( - themeColorUtils.primaryColor(context), - PorterDuff.Mode.SRC_ATOP - ) checkedVCards.add(position) } else { - holder.binding.name.checkMarkDrawable.clearColorFilter() checkedVCards.remove(position) } @@ -282,9 +271,7 @@ class BackupListAdapter( context, url, target, - R.drawable.ic_user, - imageView.width, - imageView.height + R.drawable.ic_user ) } } @@ -297,6 +284,7 @@ class BackupListAdapter( val calendarName = name.substring(0, name.indexOf("_")) val date = name.substring(name.lastIndexOf("_") + 1).replace(".ics", "").replace("-", ":") holder.binding.name.text = context.resources.getString(R.string.calendar_name_linewrap, calendarName, date) + viewThemeUtils.platform.themeCheckedTextView(holder.binding.name) holder.setCalendars(ArrayList(AndroidCalendar.loadAll(context.contentResolver))) holder.binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View?, calendarPosition: Int, id: Long) { @@ -315,14 +303,9 @@ class BackupListAdapter( val checkedTextView = holder.binding.name checkedTextView.isChecked = !checkedTextView.isChecked if (checkedTextView.isChecked) { - checkedTextView.checkMarkDrawable.setColorFilter( - themeColorUtils.primaryColor(context), - PorterDuff.Mode.SRC_ATOP - ) holder.showCalendars(true) checkedCalendars[calendarFiles[position].storagePath] = 0 } else { - checkedTextView.checkMarkDrawable.clearColorFilter() checkedCalendars.remove(calendarFiles[position].storagePath) holder.showCalendars(false) } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java index 63faba0821..fed19fa241 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupListFragment.java @@ -54,8 +54,7 @@ import com.owncloud.android.ui.events.VCardToggleEvent; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.PermissionUtil; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeToolbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -94,8 +93,7 @@ public class BackupListFragment extends FileFragment implements Injectable { @Inject UserAccountManager accountManager; @Inject ClientFactory clientFactory; @Inject BackgroundJobManager backgroundJobManager; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeToolbarUtils themeToolbarUtils; + @Inject ViewThemeUtils viewThemeUtils; private TransferManagerConnection fileDownloader; private LoadContactsTask loadContactsTask = null; private ContactsAccount selectedAccount; @@ -142,9 +140,7 @@ public class BackupListFragment extends FileFragment implements Injectable { if (contactsPreferenceActivity != null) { ActionBar actionBar = contactsPreferenceActivity.getSupportActionBar(); if (actionBar != null) { - themeToolbarUtils.setColoredTitle(actionBar, - R.string.actionbar_calendar_contacts_restore, - getContext()); + viewThemeUtils.files.themeActionBar(requireContext(), actionBar, R.string.actionbar_calendar_contacts_restore); actionBar.setDisplayHomeAsUpEnabled(true); } contactsPreferenceActivity.setDrawerIndicatorEnabled(false); @@ -157,7 +153,7 @@ public class BackupListFragment extends FileFragment implements Injectable { new HashMap<>(), this, requireContext(), - themeColorUtils); + viewThemeUtils); } else { HashMap checkedCalendarItems = new HashMap<>(); String[] checkedCalendarItemsArray = savedInstanceState.getStringArray(CHECKED_CALENDAR_ITEMS_ARRAY_KEY); @@ -187,7 +183,7 @@ public class BackupListFragment extends FileFragment implements Injectable { checkedCalendarItems, this, requireContext(), - themeColorUtils); + viewThemeUtils); } binding.list.setAdapter(listAdapter); @@ -252,7 +248,7 @@ public class BackupListFragment extends FileFragment implements Injectable { closeFragment(); }); - binding.restoreSelected.setTextColor(themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.restoreSelected); return view; } diff --git a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 5976906fe9..b0a751130a 100755 --- a/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/app/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -85,7 +85,7 @@ import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.PermissionUtil; import com.owncloud.android.utils.UriUtils; -import com.owncloud.android.utils.theme.ThemeSnackbarUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; @@ -497,13 +497,13 @@ public class FileOperationsHelper { } } - public void getFileWithLink(@NonNull OCFile file, ThemeSnackbarUtils themeSnackbarUtils) { + public void getFileWithLink(@NonNull OCFile file, final ViewThemeUtils viewThemeUtils) { List shares = fileActivity.getStorageManager().getSharesByPathAndType(file.getRemotePath(), ShareType.PUBLIC_LINK, ""); if (shares.size() == SINGLE_LINK_SIZE) { - FileActivity.copyAndShareFileLink(fileActivity, file, shares.get(0).getShareLink(), themeSnackbarUtils); + FileActivity.copyAndShareFileLink(fileActivity, file, shares.get(0).getShareLink(), viewThemeUtils); } else { if (fileActivity instanceof FileDisplayActivity) { ((FileDisplayActivity) fileActivity).showDetails(file, 1); diff --git a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java index 5a98fff485..6c70dc45c9 100644 --- a/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java +++ b/app/src/main/java/com/owncloud/android/ui/notifications/NotificationUtils.java @@ -25,7 +25,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Process; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.security.SecureRandom; @@ -61,8 +61,10 @@ public final class NotificationUtils { * @param context Context that will use the builder to create notifications * @return An instance of the regular {@link NotificationCompat.Builder}. */ - public static NotificationCompat.Builder newNotificationBuilder(Context context, ThemeColorUtils themeColorUtils) { - return new NotificationCompat.Builder(context).setColor(themeColorUtils.primaryColor(context)); + public static NotificationCompat.Builder newNotificationBuilder(Context context, final ViewThemeUtils viewThemeUtils) { + final NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + viewThemeUtils.androidx.themeNotificationCompatBuilder(context, builder); + return builder; } @SuppressFBWarnings("DMI") diff --git a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java index 3e4dda2688..ffca7c685a 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/FileDownloadFragment.java @@ -34,8 +34,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.ui.fragment.FileFragment; -import com.owncloud.android.utils.theme.ThemeBarUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.lang.ref.WeakReference; @@ -62,8 +61,7 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene private View mView; private User user; - @Inject ThemeColorUtils themeColorUtils; - @Inject ThemeBarUtils themeBarUtils; + @Inject ViewThemeUtils viewThemeUtils; public ProgressListener mProgressListener; private boolean mListening; @@ -145,7 +143,7 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene mView = inflater.inflate(R.layout.file_download_fragment, container, false); ProgressBar progressBar = mView.findViewById(R.id.progressBar); - themeBarUtils.colorHorizontalProgressBar(progressBar, themeColorUtils.primaryAccentColor(getContext())); + viewThemeUtils.platform.themeHorizontalProgressBar(progressBar); mProgressListener = new ProgressListener(progressBar); (mView.findViewById(R.id.cancelBtn)).setOnClickListener(this); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt index 33481876ce..d71a5dab6d 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewBitmapActivity.kt @@ -24,17 +24,23 @@ package com.owncloud.android.ui.preview import android.graphics.BitmapFactory import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.nextcloud.client.di.Injectable import com.owncloud.android.databinding.ActivityPreviewBitmapBinding +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject /** * Zoomable preview of a single bitmap */ -class PreviewBitmapActivity : AppCompatActivity() { +class PreviewBitmapActivity : AppCompatActivity(), Injectable { companion object { const val EXTRA_BITMAP_PATH = "EXTRA_BITMAP_PATH" } + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + private lateinit var binding: ActivityPreviewBitmapBinding override fun onCreate(savedInstanceState: Bundle?) { @@ -47,6 +53,7 @@ class PreviewBitmapActivity : AppCompatActivity() { supportActionBar?.let { it.setDisplayHomeAsUpEnabled(true) it.setDisplayShowHomeEnabled(true) + viewThemeUtils.files.setWhiteBackButton(this, it) } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 45041d71c5..df1ac4616b 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -122,7 +122,10 @@ public class PreviewImageActivity extends FileActivity implements // ActionBar updateActionBarTitleAndHomeButton(null); - themeToolbarUtils.tintBackButton(actionBar, this, Color.WHITE); + if (actionBar != null) { + viewThemeUtils.files.setWhiteBackButton(this, actionBar); + actionBar.setDisplayHomeAsUpEnabled(true); + } mFullScreenAnchorView = getWindow().getDecorView(); // to keep our UI controls visibility in line with system bars visibility diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java index c53f6b5be3..8bf2d483ff 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFileFragment.java @@ -42,6 +42,7 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.mozilla.universalchardet.ReaderFactory; @@ -73,6 +74,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment { private User user; @Inject UserAccountManager accountManager; + @Inject ViewThemeUtils viewThemeUtils; public static PreviewTextFileFragment create(User user, OCFile file, boolean openSearch, String searchQuery) { Bundle args = new Bundle(); @@ -228,7 +230,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment { if (textView != null) { originalText = stringWriter.toString(); - setText(textView, originalText, getFile(), requireActivity(), false, false, themeColorUtils); + setText(textView, originalText, getFile(), requireActivity(), false, false, viewThemeUtils); if (searchView != null) { searchView.setOnQueryTextListener(PreviewTextFileFragment.this); @@ -260,6 +262,7 @@ public class PreviewTextFileFragment extends PreviewTextFragment { menuItem.setVisible(true); searchView = (SearchView) MenuItemCompat.getActionView(menuItem); searchView.setMaxWidth(Integer.MAX_VALUE); + viewThemeUtils.androidx.themeToolbarSearchView(searchView); if (searchOpen) { searchView.setIconified(false); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java index 23a64cd99c..f8e2ad4e7d 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java @@ -23,7 +23,6 @@ import android.app.Activity; import android.content.Intent; import android.content.res.Resources; import android.graphics.Color; -import android.graphics.PorterDuff; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -48,7 +47,7 @@ import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.MimeTypeUtil; import com.owncloud.android.utils.StringUtils; -import com.owncloud.android.utils.theme.ThemeColorUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -88,7 +87,7 @@ public abstract class PreviewTextFragment extends FileFragment implements Search @Inject UserAccountManager accountManager; @Inject DeviceInfo deviceInfo; - @Inject ThemeColorUtils themeColorUtils; + @Inject ViewThemeUtils viewThemeUtils; protected TextFilePreviewBinding binding; @@ -174,23 +173,23 @@ public abstract class PreviewTextFragment extends FileFragment implements Search resources.getColor(R.color.primary)); binding.textPreview.setText(Html.fromHtml(coloredText.replace("\n", "
"))); } else { - setText(binding.textPreview, originalText, getFile(), activity, false, false, themeColorUtils); + setText(binding.textPreview, originalText, getFile(), activity, false, false, viewThemeUtils); } } protected static Spanned getRenderedMarkdownText(Activity activity, String markdown, - ThemeColorUtils themeColorUtils) { + ViewThemeUtils viewThemeUtils) { Prism4j prism4j = new Prism4j(new MarkwonGrammarLocator()); Prism4jTheme prism4jTheme = Prism4jThemeDefault.create(); TaskListDrawable drawable = new TaskListDrawable(Color.GRAY, Color.GRAY, Color.WHITE); - drawable.setColorFilter(themeColorUtils.primaryColor(activity, true), PorterDuff.Mode.SRC_ATOP); + viewThemeUtils.platform.tintPrimaryDrawable(activity, drawable); final Markwon markwon = Markwon.builder(activity) .usePlugin(new AbstractMarkwonPlugin() { @Override public void configureTheme(@NonNull MarkwonTheme.Builder builder) { - builder.linkColor(themeColorUtils.primaryColor(activity, true)); + builder.linkColor(viewThemeUtils.platform.primaryColor(activity)); builder.headingBreakHeight(0); } @@ -225,7 +224,7 @@ public abstract class PreviewTextFragment extends FileFragment implements Search Activity activity, boolean ignoreMimetype, boolean preview, - ThemeColorUtils themeColorUtils) { + ViewThemeUtils viewThemeUtils) { if (text == null) { return; } @@ -236,7 +235,7 @@ public abstract class PreviewTextFragment extends FileFragment implements Search // clickable links prevent to open full view of rich workspace textView.setMovementMethod(LinkMovementMethod.getInstance()); } - textView.setText(getRenderedMarkdownText(activity, text, themeColorUtils)); + textView.setText(getRenderedMarkdownText(activity, text, viewThemeUtils)); } else { textView.setText(text); } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java index 4ab987e6fe..3d7c5a52d0 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java @@ -38,7 +38,7 @@ import com.owncloud.android.R; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.theme.ThemeFabUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -50,7 +50,7 @@ public class PreviewTextStringFragment extends PreviewTextFragment { private static final String EXTRA_FILE = "FILE"; @Inject UserAccountManager accountManager; - @Inject ThemeFabUtils themeFabUtils; + @Inject ViewThemeUtils viewThemeUtils; /** * Creates an empty fragment for previews. @@ -100,7 +100,9 @@ public class PreviewTextStringFragment extends PreviewTextFragment { fabMain.setVisibility(View.VISIBLE); fabMain.setEnabled(true); fabMain.setOnClickListener(v -> edit()); - themeFabUtils.colorFloatingActionButton(fabMain, R.drawable.ic_edit, requireContext()); + + fabMain.setImageResource(R.drawable.ic_edit); + viewThemeUtils.material.themeFAB(fabMain); return view; } @@ -117,6 +119,7 @@ public class PreviewTextStringFragment extends PreviewTextFragment { searchView = (SearchView) MenuItemCompat.getActionView(menuItem); searchView.setOnQueryTextListener(this); searchView.setMaxWidth(Integer.MAX_VALUE); + viewThemeUtils.androidx.themeToolbarSearchView(searchView); if (searchOpen) { searchView.setIconified(false); @@ -127,7 +130,7 @@ public class PreviewTextStringFragment extends PreviewTextFragment { void loadAndShowTextPreview() { originalText = getFile().getRichWorkspace(); - setText(binding.textPreview, originalText, getFile(), requireActivity(), true, false, themeColorUtils); + setText(binding.textPreview, originalText, getFile(), requireActivity(), true, false, viewThemeUtils); binding.textPreview.setVisibility(View.VISIBLE); binding.emptyListProgress.setVisibility(View.GONE); diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java index 96e6ecbbe8..7a823e21fb 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.java @@ -49,6 +49,7 @@ import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; import com.owncloud.android.ui.interfaces.TrashbinActivityInterface; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileSortOrder; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.List; @@ -73,6 +74,8 @@ public class TrashbinActivity extends DrawerActivity implements @Inject AppPreferences preferences; @Inject CurrentAccountProvider accountProvider; @Inject ClientFactory clientFactory; + @Inject ViewThemeUtils viewThemeUtils; + private TrashbinListAdapter trashbinListAdapter; @VisibleForTesting @@ -141,17 +144,18 @@ public class TrashbinActivity extends DrawerActivity implements preferences, this, getUser().orElse(accountProvider.getUser()), - themeColorUtils, - themeDrawableUtils + viewThemeUtils ); recyclerView.setAdapter(trashbinListAdapter); recyclerView.setHasFixedSize(true); recyclerView.setHasFooter(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); - themeLayoutUtils.colorSwipeRefreshLayout(this, binding.swipeContainingList); + viewThemeUtils.androidx.themeSwipeRefreshLayout(binding.swipeContainingList); binding.swipeContainingList.setOnRefreshListener(this::loadFolder); + viewThemeUtils.material.colorMaterialTextButton(findViewById(R.id.sort_button)); + findViewById(R.id.sort_button).setOnClickListener(l -> openSortingOrderDialogFragment(getSupportFragmentManager(), preferences.getSortOrderByType( diff --git a/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java b/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java index 231d4f5787..70c3debcde 100644 --- a/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/BitmapUtils.java @@ -27,8 +27,10 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.widget.ImageView; @@ -47,6 +49,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Locale; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; @@ -429,7 +432,7 @@ public final class BitmapUtils { imageView); } - public static Bitmap createAvatarWithStatus(Bitmap avatar, StatusType statusType, String icon, Context context) { + public static Bitmap createAvatarWithStatus(Bitmap avatar, StatusType statusType, @NonNull String icon, Context context) { float avatarRadius = getResources().getDimension(R.dimen.list_item_avatar_icon_radius); int width = DisplayUtils.convertDpToPixel(2 * avatarRadius, context); @@ -453,6 +456,42 @@ public final class BitmapUtils { return output; } + /** + * Inspired from https://www.demo2s.com/android/android-bitmap-get-a-round-version-of-the-bitmap.html + */ + public static Bitmap roundBitmap(Bitmap bitmap) { + Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + + final Canvas canvas = new Canvas(output); + + final int color = R.color.white; + final Paint paint = new Paint(); + final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); + final RectF rectF = new RectF(rect); + + paint.setAntiAlias(true); + canvas.drawARGB(0, 0, 0, 0); + paint.setColor(getResources().getColor(color, null)); + canvas.drawOval(rectF, paint); + + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + canvas.drawBitmap(bitmap, rect, rect, paint); + + return output; + } + + /** + * from https://stackoverflow.com/a/38249623 + **/ + public static Bitmap tintImage(Bitmap bitmap, int color) { + Paint paint = new Paint(); + paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); + Bitmap bitmapResult = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmapResult); + canvas.drawBitmap(bitmap, 0, 0, paint); + return bitmapResult; + } + /** * from https://stackoverflow.com/a/12089127 */ diff --git a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java index 6d4876e1ef..3a1e1337dd 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -36,7 +36,6 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.drawable.Drawable; -import android.graphics.drawable.PictureDrawable; import android.net.Uri; import android.os.AsyncTask; import android.text.Spannable; @@ -81,8 +80,7 @@ import com.owncloud.android.ui.fragment.OCFileListFragment; import com.owncloud.android.utils.glide.CustomGlideUriLoader; import com.owncloud.android.utils.svg.SvgDecoder; import com.owncloud.android.utils.svg.SvgDrawableTranscoder; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; @@ -128,7 +126,6 @@ public final class DisplayUtils { private static final String[] sizeSuffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}; private static final int[] sizeScales = {0, 0, 1, 1, 1, 2, 2, 2, 2}; - private static final int RELATIVE_THRESHOLD_WARNING = 80; private static final String MIME_TYPE_UNKNOWN = "Unknown type"; private static final String HTTP_PROTOCOL = "http://"; @@ -142,6 +139,7 @@ public final class DisplayUtils { public static final String MONTH_YEAR_PATTERN = "MMMM yyyy"; public static final String MONTH_PATTERN = "MMMM"; public static final String YEAR_PATTERN = "yyyy"; + public static final int SVG_SIZE = 512; private static Map mimeType2HumanReadable; @@ -336,22 +334,6 @@ public final class DisplayUtils { showFuture); } - - /** - * determines the info level color based on {@link #RELATIVE_THRESHOLD_WARNING}. - * - * @param context the app's context - * @param relative relative value for which the info level color should be looked up - * @return info level color - */ - public static int getRelativeInfoColor(Context context, int relative, ThemeColorUtils themeColorUtils) { - if (relative < RELATIVE_THRESHOLD_WARNING) { - return themeColorUtils.primaryColor(context, true); - } else { - return context.getResources().getColor(R.color.infolevel_warning); - } - } - public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, long transitionResolution, int flags) { return getRelativeDateTimeString(c, time, minResolution, transitionResolution, flags, false); @@ -552,13 +534,10 @@ public final class DisplayUtils { Context context, String iconUrl, SimpleTarget imageView, - int placeholder, - int width, - int height) { + int placeholder) { try { - if (iconUrl.endsWith(".svg")) { - downloadSVGIcon(currentAccountProvider, clientFactory, context, iconUrl, imageView, placeholder, width, - height); + if (Uri.parse(iconUrl).getEncodedPath().endsWith(".svg")) { + downloadSVGIcon(currentAccountProvider, clientFactory, context, iconUrl, imageView, placeholder); } else { downloadPNGIcon(context, iconUrl, imageView, placeholder); } @@ -583,17 +562,15 @@ public final class DisplayUtils { Context context, String iconUrl, SimpleTarget imageView, - int placeholder, - int width, - int height) { - GenericRequestBuilder requestBuilder = Glide.with(context) + int placeholder) { + GenericRequestBuilder requestBuilder = Glide.with(context) .using(new CustomGlideUriLoader(currentAccountProvider.getUser(), clientFactory), InputStream.class) .from(Uri.class) .as(SVG.class) - .transcode(new SvgDrawableTranscoder(), PictureDrawable.class) + .transcode(new SvgDrawableTranscoder(context), Drawable.class) .sourceEncoder(new StreamEncoder()) - .cacheDecoder(new FileToStreamDecoder<>(new SvgDecoder(height, width))) - .decoder(new SvgDecoder(height, width)) + .cacheDecoder(new FileToStreamDecoder<>(new SvgDecoder())) + .decoder(new SvgDecoder()) .placeholder(placeholder) .error(placeholder) .animate(android.R.anim.fade_in); @@ -851,8 +828,7 @@ public final class DisplayUtils { Context context, LoaderImageView shimmerThumbnail, AppPreferences preferences, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { if (file.isFolder()) { stopShimmer(shimmerThumbnail, thumbnailView); thumbnailView.setImageDrawable(MimeTypeUtil @@ -862,8 +838,7 @@ public final class DisplayUtils { file.isGroupFolder(), file.getMountType(), context, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } else { if (file.getRemoteId() != null && file.isPreviewAvailable()) { // Thumbnail in cache? @@ -904,10 +879,8 @@ public final class DisplayUtils { if (thumbnail == null) { Drawable drawable = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), - user, context, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); if (drawable == null) { drawable = ResourcesCompat.getDrawable(context.getResources(), R.drawable.file_image, @@ -957,10 +930,8 @@ public final class DisplayUtils { stopShimmer(shimmerThumbnail, thumbnailView); thumbnailView.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimeType(), file.getFileName(), - user, context, - themeColorUtils, - themeDrawableUtils)); + viewThemeUtils)); } } } diff --git a/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java b/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java index 7a82487104..cd44c80b3b 100644 --- a/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java +++ b/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java @@ -23,13 +23,11 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.webkit.MimeTypeMap; -import com.nextcloud.client.account.User; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.lib.common.network.WebdavEntry; import com.owncloud.android.lib.resources.files.model.ServerFileInterface; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; import java.util.ArrayList; @@ -40,7 +38,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; /** @@ -95,32 +92,13 @@ public final class MimeTypeUtil { public static Drawable getFileTypeIcon(String mimetype, String filename, Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { - return getFileTypeIcon(mimetype, filename, null, context, themeColorUtils, themeDrawableUtils); - } - - /** - * Returns the Drawable of an image to use as icon associated to a known MIME type. - * - * @param mimetype MIME type string; if NULL, the method tries to guess it from the extension in filename - * @param filename Name, with extension. - * @param user user which color should be used - * @return Drawable of an image resource. - */ - @Nullable - public static Drawable getFileTypeIcon(String mimetype, - String filename, - @Nullable User user, - Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { if (context != null) { int iconId = MimeTypeUtil.getFileTypeIconId(mimetype, filename); Drawable icon = ContextCompat.getDrawable(context, iconId); if (R.drawable.file_zip == iconId) { - themeDrawableUtils.tintDrawable(icon, themeColorUtils.primaryColor(user, true, context)); + viewThemeUtils.platform.tintPrimaryDrawable(context, icon); } return icon; @@ -147,50 +125,21 @@ public final class MimeTypeUtil { return determineIconIdByMimeTypeList(possibleMimeTypes); } - /** - * Returns the resource identifier of an image to use as icon associated to a type of folder. - * - * @param isSharedViaUsers flag if the folder is shared via the users system - * @param isSharedViaLink flag if the folder is publicly shared via link - * @return Identifier of an image resource. - */ - public static Drawable getFolderTypeIcon(boolean isSharedViaUsers, - boolean isSharedViaLink, - boolean isEncrypted, - boolean isGroupfolder, - WebdavEntry.MountType mountType, - Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { - return getFolderTypeIcon(isSharedViaUsers, - isSharedViaLink, - isEncrypted, - isGroupfolder, - null, - mountType, - context, - themeColorUtils, - themeDrawableUtils); - } - /** * Returns the resource identifier of an image to use as icon associated to a type of folder. * * @param isSharedViaUsers flag if the folder is shared via the users system * @param isSharedViaLink flag if the folder is publicly shared via link * @param isEncrypted flag if the folder is encrypted - * @param user user which color should be used * @return Identifier of an image resource. */ public static Drawable getFolderTypeIcon(boolean isSharedViaUsers, boolean isSharedViaLink, boolean isEncrypted, boolean isGroupFolder, - @Nullable User user, WebdavEntry.MountType mountType, Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { int drawableId; if (isSharedViaLink) { @@ -207,26 +156,22 @@ public final class MimeTypeUtil { drawableId = R.drawable.folder; } - int color = themeColorUtils.primaryColor(user != null ? user.toPlatformAccount() : null, - true, - context); - return themeDrawableUtils.tintDrawable(drawableId, color); + Drawable drawable = ContextCompat.getDrawable(context, drawableId); + viewThemeUtils.platform.tintPrimaryDrawable(context, drawable); + return drawable; } public static Drawable getDefaultFolderIcon(Context context, - ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { + ViewThemeUtils viewThemeUtils) { return getFolderTypeIcon(false, false, false, false, WebdavEntry.MountType.INTERNAL, context, - themeColorUtils, - themeDrawableUtils); + viewThemeUtils); } - /** * Returns a single MIME type of all the possible, by inspection of the file extension, and taking * into account the MIME types known by ownCloud first. diff --git a/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt b/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt index 182eefb45c..ca919a233d 100644 --- a/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt @@ -42,7 +42,7 @@ import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.AppPreferencesImpl import com.owncloud.android.R import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment -import com.owncloud.android.utils.theme.ThemeSnackbarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils object PermissionUtil { const val PERMISSIONS_EXTERNAL_STORAGE = 1 @@ -116,7 +116,7 @@ object PermissionUtil { @JvmOverloads fun requestExternalStoragePermission( activity: AppCompatActivity, - themeSnackbarUtils: ThemeSnackbarUtils, + viewThemeUtils: ViewThemeUtils, permissionRequired: Boolean = false ) { if (!checkExternalStoragePermission(activity)) { @@ -124,20 +124,20 @@ object PermissionUtil { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { if (canRequestAllFilesPermission(activity)) { // can request All Files, show choice - showPermissionChoiceDialog(activity, permissionRequired, themeSnackbarUtils) + showPermissionChoiceDialog(activity, permissionRequired, viewThemeUtils) } else { // can not request all files, request READ_EXTERNAL_STORAGE requestStoragePermission( activity, Manifest.permission.READ_EXTERNAL_STORAGE, - themeSnackbarUtils + viewThemeUtils ) } } else -> requestStoragePermission( activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, - themeSnackbarUtils + viewThemeUtils ) } } @@ -146,10 +146,11 @@ object PermissionUtil { /** * Request a storage permission */ + // TODO inject this class to avoid passing ViewThemeUtils around private fun requestStoragePermission( activity: Activity, permission: String, - themeSnackbarUtils: ThemeSnackbarUtils + viewThemeUtils: ViewThemeUtils ) { fun doRequest() { ActivityCompat.requestPermissions( @@ -171,7 +172,7 @@ object PermissionUtil { .setAction(R.string.common_ok) { doRequest() } - .also { themeSnackbarUtils.colorSnackbar(activity, it) } + .also { viewThemeUtils.material.themeSnackbar(it) } .show() } else { // No explanation needed, request the permission. @@ -205,7 +206,7 @@ object PermissionUtil { private fun showPermissionChoiceDialog( activity: AppCompatActivity, permissionRequired: Boolean, - themeSnackbarUtils: ThemeSnackbarUtils + viewThemeUtils: ViewThemeUtils ) { val preferences: AppPreferences = AppPreferencesImpl.fromContext(activity) @@ -228,7 +229,7 @@ object PermissionUtil { requestStoragePermission( activity, Manifest.permission.READ_EXTERNAL_STORAGE, - themeSnackbarUtils + viewThemeUtils ) } } diff --git a/app/src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java b/app/src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java index 788d314565..e314786264 100644 --- a/app/src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java +++ b/app/src/main/java/com/owncloud/android/utils/svg/SvgDecoder.java @@ -25,14 +25,6 @@ import java.io.InputStream; * Decodes an SVG internal representation from an {@link InputStream}. */ public class SvgDecoder implements ResourceDecoder { - private int height = -1; - private int width = -1; - - public SvgDecoder(int height, int width) { - this.height = height; - this.width = width; - } - public SvgDecoder() { // empty constructor } @@ -40,13 +32,9 @@ public class SvgDecoder implements ResourceDecoder { public Resource decode(InputStream source, int w, int h) throws IOException { try { SVG svg = SVG.getFromInputStream(source); - - if (width > 0) { - svg.setDocumentWidth(width); - } - if (height > 0) { - svg.setDocumentHeight(height); - } + svg.setDocumentViewBox(0, 0, svg.getDocumentWidth(), svg.getDocumentHeight()); + svg.setDocumentWidth("100%"); + svg.setDocumentHeight("100%"); svg.setDocumentPreserveAspectRatio(PreserveAspectRatio.LETTERBOX); return new SimpleResource<>(svg); diff --git a/app/src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java b/app/src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java index 38cb2fb06d..77c97b4aac 100644 --- a/app/src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java +++ b/app/src/main/java/com/owncloud/android/utils/svg/SvgDrawableTranscoder.java @@ -10,7 +10,12 @@ */ package com.owncloud.android.utils.svg; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Picture; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.graphics.drawable.PictureDrawable; import com.bumptech.glide.load.engine.Resource; @@ -21,13 +26,27 @@ import com.caverock.androidsvg.SVG; /** * Convert the {@link SVG}'s internal representation to an Android-compatible one ({@link Picture}). */ -public class SvgDrawableTranscoder implements ResourceTranscoder { +public class SvgDrawableTranscoder implements ResourceTranscoder { + private final Context context; + + public SvgDrawableTranscoder(Context context) { + this.context = context; + } + @Override - public Resource transcode(Resource toTranscode) { + public Resource transcode(Resource toTranscode) { SVG svg = toTranscode.get(); Picture picture = svg.renderToPicture(); PictureDrawable drawable = new PictureDrawable(picture); - return new SimpleResource(drawable); + + Bitmap returnedBitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(returnedBitmap); + canvas.drawPicture(drawable.getPicture()); + Drawable d = new BitmapDrawable(context.getResources(), returnedBitmap); + + return new SimpleResource<>(d); } @Override diff --git a/app/src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java b/app/src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java index 12bf2541a8..d7d56fdea5 100644 --- a/app/src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java +++ b/app/src/main/java/com/owncloud/android/utils/svg/SvgSoftwareLayerSetter.java @@ -10,7 +10,7 @@ */ package com.owncloud.android.utils.svg; -import android.graphics.drawable.PictureDrawable; +import android.graphics.drawable.Drawable; import android.os.Build; import android.widget.ImageView; @@ -18,10 +18,10 @@ import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.ImageViewTarget; import com.bumptech.glide.request.target.Target; -public class SvgSoftwareLayerSetter implements RequestListener { +public class SvgSoftwareLayerSetter implements RequestListener { @Override - public boolean onException(Exception e, T model, Target target, boolean isFirstResource) { + public boolean onException(Exception e, T model, Target target, boolean isFirstResource) { ImageView view = ((ImageViewTarget) target).getView(); if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) { view.setLayerType(ImageView.LAYER_TYPE_NONE, null); @@ -30,7 +30,7 @@ public class SvgSoftwareLayerSetter implements RequestListener target, + public boolean onResourceReady(Drawable resource, T model, Target target, boolean isFromMemoryCache, boolean isFirstResource) { ImageView view = ((ImageViewTarget) target).getView(); if (Build.VERSION_CODES.HONEYCOMB <= Build.VERSION.SDK_INT) { diff --git a/app/src/main/java/com/owncloud/android/utils/theme/CapabilityUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/CapabilityUtils.java index d236cec390..7055a6ee8b 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/CapabilityUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/theme/CapabilityUtils.java @@ -34,9 +34,6 @@ import com.owncloud.android.lib.resources.status.OCCapability; import java.util.HashMap; import java.util.Map; -/** - * Utility class with methods for client side button theming. - */ public final class CapabilityUtils { private static final Map cachedCapabilities = new HashMap<>(); diff --git a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt new file mode 100644 index 0000000000..e5b83865a3 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt @@ -0,0 +1,256 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme + +import android.content.Context +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.PorterDuff +import android.graphics.drawable.Drawable +import android.preference.PreferenceCategory +import android.text.Spannable +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.widget.ImageView +import androidx.annotation.DrawableRes +import androidx.annotation.Px +import androidx.annotation.StringRes +import androidx.appcompat.app.ActionBar +import androidx.core.content.res.ResourcesCompat +import com.google.android.material.card.MaterialCardView +import com.nextcloud.android.common.ui.color.ColorUtil +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase +import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils +import com.nextcloud.utils.view.FastScrollPopupBackground +import com.owncloud.android.R +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.shares.ShareType +import me.zhanghai.android.fastscroll.FastScrollerBuilder +import me.zhanghai.android.fastscroll.PopupStyles +import javax.inject.Inject + +class FilesSpecificViewThemeUtils @Inject constructor( + schemes: MaterialSchemes, + private val colorUtil: ColorUtil, + private val androidViewThemeUtils: AndroidViewThemeUtils, + private val androidXViewThemeUtils: AndroidXViewThemeUtils +) : ViewThemeUtilsBase(schemes) { + // not ported to common lib because PreferenceCategory is deprecated + fun themePreferenceCategory(category: PreferenceCategory) { + withScheme(category.context) { + val text: Spannable = SpannableString(category.title) + text.setSpan( + ForegroundColorSpan(it.primary), + 0, + text.length, + Spannable.SPAN_INCLUSIVE_INCLUSIVE + ) + category.title = text + } + } + + fun createAvatar(type: ShareType?, avatar: ImageView, context: Context) { + fun createAvatarBase(@DrawableRes icon: Int, padding: Int = AvatarPadding.SMALL) { + avatar.setImageResource(icon) + avatar.background = ResourcesCompat.getDrawable( + context.resources, + R.drawable.round_bgnd, + null + ) + avatar.cropToPadding = true + avatar.setPadding(padding, padding, padding, padding) + } + + when (type) { + ShareType.GROUP -> { + createAvatarBase(R.drawable.ic_group) + androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) + } + ShareType.ROOM -> { + createAvatarBase(R.drawable.first_run_talk, AvatarPadding.LARGE) + androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) + } + ShareType.CIRCLE -> { + createAvatarBase(R.drawable.ic_circles) + avatar.background.setColorFilter( + context.resources.getColor(R.color.nc_grey), + PorterDuff.Mode.SRC_IN + ) + avatar.drawable.mutate().setColorFilter( + context.resources.getColor(R.color.icon_on_nc_grey), + PorterDuff.Mode.SRC_IN + ) + } + ShareType.EMAIL -> { + createAvatarBase(R.drawable.ic_email, AvatarPadding.LARGE) + androidViewThemeUtils.colorImageViewBackgroundAndIcon(avatar) + } + else -> Log_OC.d(TAG, "Unknown share type") + } + } + + fun themeFastScrollerBuilder(context: Context, builder: FastScrollerBuilder): FastScrollerBuilder { + return withScheme(context) { scheme -> + builder + .useMd2Style() + .setThumbDrawable(getThumbDrawable(context)) + .setPopupStyle { + PopupStyles.MD2.accept(it) + it.background = FastScrollPopupBackground(context, scheme.primary) + } + } + } + + private fun getThumbDrawable( + context: Context + ): Drawable { + val thumbDrawable = + ResourcesCompat.getDrawable( + context.resources, + me.zhanghai.android.fastscroll.R.drawable.afs_md2_thumb, + null + ) + return androidViewThemeUtils.tintPrimaryDrawable(context, thumbDrawable)!! + } + + /** + * Sets title and colors the actionbar, the title and the back arrow + */ + // TODO move back arrow resource to lib and use lib method directly? + fun themeActionBar(context: Context, actionBar: ActionBar, title: String) { + val backArrow = ResourcesCompat.getDrawable( + context.resources, + R.drawable.ic_arrow_back, + null + )!! + androidXViewThemeUtils.themeActionBar( + context, + actionBar, + title, + backArrow + ) + } + + /** + * Sets title and colors the actionbar, the title and the back arrow + */ + fun themeActionBar(context: Context, actionBar: ActionBar, @StringRes titleRes: Int) { + val title = context.getString(titleRes) + themeActionBar( + context, + actionBar, + title + ) + } + + /** + * Colors actionbar background and back arrow but not the title + */ + fun themeActionBar(context: Context, actionBar: ActionBar) { + val backArrow = ResourcesCompat.getDrawable( + context.resources, + R.drawable.ic_arrow_back, + null + )!! + androidXViewThemeUtils.themeActionBar(context, actionBar, backArrow) + } + + fun themeTemplateCardView(cardView: MaterialCardView) { + withScheme(cardView.context) { scheme -> + cardView.setStrokeColor( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.primary, + scheme.outline + ) + ) + ) + } + } + + fun themeStatusCardView(cardView: MaterialCardView) { + withScheme(cardView) { scheme -> + val background = cardView.context.getColor(R.color.grey_200) + cardView.backgroundTintList = + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.secondaryContainer, + background + ) + ) + cardView.setStrokeColor( + ColorStateList( + arrayOf( + intArrayOf(android.R.attr.state_checked), + intArrayOf(-android.R.attr.state_checked) + ), + intArrayOf( + scheme.onSecondaryContainer, + scheme.surface + ) + ) + ) + } + } + + fun themeAvatarButton(shareImageView: ImageView) { + withScheme(shareImageView.context) { scheme -> + shareImageView.background.setColorFilter(scheme.primary, PorterDuff.Mode.SRC_IN) + shareImageView.drawable.mutate().setColorFilter(scheme.onPrimary, PorterDuff.Mode.SRC_IN) + } + } + + fun primaryColorToHexString(context: Context): String { + return withScheme(context) { scheme -> + colorUtil.colorToHexString(scheme.primary) + } + } + + fun setWhiteBackButton(context: Context, supportActionBar: ActionBar) { + val backArrow = ResourcesCompat.getDrawable(context.resources, R.drawable.ic_arrow_back, null) + val tinted = androidViewThemeUtils.colorDrawable(backArrow!!, Color.WHITE) + supportActionBar.setHomeAsUpIndicator(tinted) + } + + companion object { + private val TAG = FilesSpecificViewThemeUtils::class.simpleName + + private object AvatarPadding { + @Px + const val SMALL = 4 + + @Px + const val LARGE = 8 + } + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProvider.kt b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProvider.kt new file mode 100644 index 0000000000..09bae79587 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProvider.kt @@ -0,0 +1,38 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme + +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.client.account.User +import com.owncloud.android.lib.resources.status.OCCapability + +interface MaterialSchemesProvider { + fun getMaterialSchemesForUser(user: User): MaterialSchemes + fun getMaterialSchemesForCapability(capability: OCCapability): MaterialSchemes + fun getMaterialSchemesForCurrentUser(): MaterialSchemes + + /** + * Color schemes for when there's no logged in user + */ + fun getDefaultMaterialSchemes(): MaterialSchemes +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt new file mode 100644 index 0000000000..929dc6959f --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/MaterialSchemesProviderImpl.kt @@ -0,0 +1,80 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme + +import android.content.Context +import androidx.core.content.ContextCompat +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.client.account.AnonymousUser +import com.nextcloud.client.account.User +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.logger.Logger +import com.owncloud.android.R +import com.owncloud.android.lib.resources.status.OCCapability +import java.util.concurrent.ConcurrentHashMap +import javax.inject.Inject + +internal class MaterialSchemesProviderImpl @Inject constructor( + private val logger: Logger, + private val context: Context, + private val userAccountManager: UserAccountManager, + private val themeFactory: ServerThemeImpl.Factory +) : MaterialSchemesProvider { + + private val themeCache: MutableMap = ConcurrentHashMap() + + override fun getMaterialSchemesForUser(user: User): MaterialSchemes { + val url: String = user.server.uri.toString() + + if (!themeCache.containsKey(url)) { + val capability = CapabilityUtils.getCapability(user, context) + themeCache[url] = getMaterialSchemesForCapability(capability) + } + + return themeCache[url]!! + } + + override fun getMaterialSchemesForCapability(capability: OCCapability): MaterialSchemes { + val serverTheme = themeFactory.create(capability) + return MaterialSchemes.fromServerTheme(serverTheme) + } + + override fun getMaterialSchemesForCurrentUser(): MaterialSchemes { + return when (val user = userAccountManager.user) { + is AnonymousUser -> { + logger.d(TAG, "User is anonymous, using default schemes") + getDefaultMaterialSchemes() + } + else -> getMaterialSchemesForUser(user) + } + } + + override fun getDefaultMaterialSchemes(): MaterialSchemes { + val primaryColor = ContextCompat.getColor(context, R.color.primary) + return MaterialSchemes.fromColor(primaryColor) + } + + companion object { + private val TAG = MaterialSchemesProviderImpl::class.java.simpleName + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ServerThemeImpl.kt b/app/src/main/java/com/owncloud/android/utils/theme/ServerThemeImpl.kt new file mode 100644 index 0000000000..2a2d78b132 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/ServerThemeImpl.kt @@ -0,0 +1,55 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme + +import com.nextcloud.android.common.ui.color.ColorUtil +import com.nextcloud.android.common.ui.theme.ServerTheme +import com.owncloud.android.R +import com.owncloud.android.lib.resources.status.OCCapability +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +class ServerThemeImpl @AssistedInject constructor(colorUtil: ColorUtil, @Assisted capability: OCCapability) : + ServerTheme { + override val colorElement: Int + override val colorElementBright: Int + override val colorElementDark: Int + override val colorText: Int + override val primaryColor: Int + + init { + primaryColor = + colorUtil.getNullSafeColorWithFallbackRes(capability.serverColor, R.color.colorPrimary) + colorElement = colorUtil.getNullSafeColor(capability.serverElementColor, primaryColor) + colorElementBright = + colorUtil.getNullSafeColor(capability.serverElementColorBright, primaryColor) + colorElementDark = colorUtil.getNullSafeColor(capability.serverElementColorDark, primaryColor) + colorText = colorUtil.getTextColor(capability.serverTextColor, primaryColor) + } + + @AssistedFactory + interface Factory { + fun create(capability: OCCapability): ServerThemeImpl + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeAvatarUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeAvatarUtils.java deleted file mode 100644 index ab3595cddd..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeAvatarUtils.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.widget.ImageView; - -import com.owncloud.android.R; -import com.owncloud.android.lib.resources.shares.ShareType; - -import androidx.core.content.res.ResourcesCompat; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -/** - * Utility class with methods for client side button theming. - */ -public final class ThemeAvatarUtils { - public void colorIconImageViewWithBackground(ImageView imageView, - Context context, - ThemeColorUtils themeColorUtils) { - int primaryColor = themeColorUtils.primaryColor(null, true, false, context); - - imageView.getBackground().setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN); - imageView.getDrawable().mutate().setColorFilter(themeColorUtils.getColorForPrimary(primaryColor, context), - PorterDuff.Mode.SRC_IN); - } - - @SuppressFBWarnings( - value = "SF_SWITCH_NO_DEFAULT", - justification = "We only create avatars for a subset of share types") - public void createAvatar(ShareType type, - ImageView avatar, - Context context, - ThemeColorUtils themeColorUtils) { - switch (type) { - case GROUP: - avatar.setImageResource(R.drawable.ic_group); - avatar.setBackground(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.round_bgnd, - null)); - avatar.setCropToPadding(true); - avatar.setPadding(4, 4, 4, 4); - colorIconImageViewWithBackground(avatar, context, themeColorUtils); - break; - - case ROOM: - avatar.setImageResource(R.drawable.first_run_talk); - avatar.setBackground(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.round_bgnd, - null)); - avatar.setCropToPadding(true); - avatar.setPadding(8, 8, 8, 8); - colorIconImageViewWithBackground(avatar, context, themeColorUtils); - break; - - case CIRCLE: - avatar.setImageResource(R.drawable.ic_circles); - avatar.setBackground(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.round_bgnd, - null)); - avatar.getBackground().setColorFilter(context.getResources().getColor(R.color.nc_grey), - PorterDuff.Mode.SRC_IN); - avatar.getDrawable().mutate().setColorFilter(context.getResources().getColor(R.color.icon_on_nc_grey), - PorterDuff.Mode.SRC_IN); - avatar.setCropToPadding(true); - avatar.setPadding(4, 4, 4, 4); - break; - - case EMAIL: - avatar.setImageResource(R.drawable.ic_email); - avatar.setBackground(ResourcesCompat.getDrawable(context.getResources(), - R.drawable.round_bgnd, - null)); - avatar.setCropToPadding(true); - avatar.setPadding(8, 8, 8, 8); - avatar.getBackground().setColorFilter(context.getResources().getColor(R.color.nc_grey), - PorterDuff.Mode.SRC_IN); - avatar.getDrawable().mutate().setColorFilter(context.getResources().getColor(R.color.icon_on_nc_grey), - PorterDuff.Mode.SRC_IN); - break; - } - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeBarUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeBarUtils.java deleted file mode 100644 index 4e75a29e2c..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeBarUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.PorterDuff; -import android.widget.ProgressBar; -import android.widget.SeekBar; - -import androidx.annotation.ColorInt; - -/** - * Utility class with methods for client side button theming. - */ -public final class ThemeBarUtils { - /** - * sets the coloring of the given progress bar to given color. - * - * @param progressBar the progress bar to be colored - * @param color the color to be used - */ - public void colorHorizontalProgressBar(ProgressBar progressBar, @ColorInt int color) { - if (progressBar != null) { - progressBar.getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN); - progressBar.getProgressDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - } - - /** - * sets the coloring of the given progress bar's progress to given color. - * - * @param progressBar the progress bar to be colored - * @param color the color to be used - */ - public void colorProgressBar(ProgressBar progressBar, @ColorInt int color) { - if (progressBar != null) { - progressBar.setProgressTintList(ColorStateList.valueOf(color)); - } - } - - /** - * sets the coloring of the given seek bar to color_accent. - * - * @param seekBar the seek bar to be colored - */ - public void colorHorizontalSeekBar(SeekBar seekBar, Context context, ThemeColorUtils themeColorUtils) { - int color = themeColorUtils.primaryAccentColor(context); - - colorHorizontalProgressBar(seekBar, color); - seekBar.getThumb().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } - - public void themeProgressBar(Context context, ProgressBar progressBar, ThemeColorUtils themeColorUtils) { - // TODO harmonize methods - int color = themeColorUtils.primaryAccentColor(context); - progressBar.getIndeterminateDrawable().setColorFilter(color, PorterDuff.Mode.SRC_IN); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeButtonUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeButtonUtils.java deleted file mode 100644 index 74cb20cb7c..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeButtonUtils.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.widget.Button; -import android.widget.ImageButton; - -import com.owncloud.android.R; - -import androidx.annotation.ColorInt; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; - -/** - * Utility class with methods for client side button theming. - */ -public final class ThemeButtonUtils { - /** - * sets the tinting of the given ImageButton's icon to color_accent. - * - * @param imageButton the image button who's icon should be colored - */ - public void colorImageButton(ImageButton imageButton, @ColorInt int color) { - if (imageButton != null) { - imageButton.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - } - } - - public void colorPrimaryButton(Button button, Context context, ThemeColorUtils themeColorUtils) { - int primaryColor = themeColorUtils.primaryColor(null, true, false, context); - int fontColor = themeColorUtils.fontColor(context, false); - - button.setBackgroundColor(primaryColor); - - if (Color.BLACK == primaryColor) { - button.setTextColor(Color.WHITE); - } else if (Color.WHITE == primaryColor) { - button.setTextColor(Color.BLACK); - } else { - button.setTextColor(fontColor); - } - } - - /** - * theme buttons based on accent color. - * - * @param buttons borderless buttons to be themed - */ - public void themeBorderlessButton(ThemeColorUtils themeColorUtils, @Nullable Button... buttons) { - if (buttons == null || buttons.length < 1) { - return; - } - themeBorderlessButton(themeColorUtils.primaryAccentColor(buttons[0].getContext()), buttons); - } - - /** - * theme buttons based on given color. - * - * @param color theme color - * @param buttons borderless buttons to be themed - */ - public void themeBorderlessButton(int color, @Nullable Button... buttons) { - if (buttons == null || buttons.length < 1) { - return; - } - Context context = buttons[0].getContext(); - int disabledColor = ContextCompat.getColor(context, R.color.disabled_text); - ColorStateList colorStateList = new ColorStateList( - new int[][]{ - new int[]{android.R.attr.state_enabled}, // enabled - new int[]{-android.R.attr.state_enabled}, // disabled - }, - new int[]{ - color, - disabledColor - } - ); - for (Button button: buttons) { - button.setTextColor(colorStateList); - } - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeCheckableUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeCheckableUtils.java deleted file mode 100644 index 2f69cb4d45..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeCheckableUtils.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.res.ColorStateList; -import android.graphics.Color; - -import com.owncloud.android.R; - -import androidx.appcompat.app.AppCompatDelegate; -import androidx.appcompat.widget.AppCompatCheckBox; -import androidx.appcompat.widget.SwitchCompat; -import androidx.core.graphics.drawable.DrawableCompat; -import androidx.core.widget.CompoundButtonCompat; - -/** - * Utility class with methods for client side checkable theming. - */ -public final class ThemeCheckableUtils { - public void tintCheckbox(int color, AppCompatCheckBox... checkBoxes) { - if (checkBoxes != null) { - for (AppCompatCheckBox checkBox : checkBoxes) { - CompoundButtonCompat.setButtonTintList(checkBox, new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_checked}, - new int[]{android.R.attr.state_checked}, - }, - new int[]{ - Color.GRAY, - color - } - )); - } - } - } - - public void tintSwitch(SwitchCompat switchView, ThemeColorUtils themeColorUtils) { - int trackColor = switchView.getContext().getResources().getColor(R.color.grey_200); - ColorStateList thumbColorStateList; - ColorStateList trackColorStateList; - int thumbColor = themeColorUtils.primaryAccentColor(switchView.getContext()); - if (themeColorUtils.darkTheme(switchView.getContext()) && - AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { - thumbColor = Color.WHITE; - trackColor = Color.DKGRAY; - } - thumbColorStateList = new ColorStateList( - new int[][]{new int[]{android.R.attr.state_checked}, new int[]{}}, - new int[]{thumbColor, switchView.getContext().getResources().getColor(R.color.switch_thumb_color_unchecked)}); - trackColorStateList = new ColorStateList( - new int[][]{new int[]{android.R.attr.state_checked}, - new int[]{}}, - new int[]{trackColor, trackColor}); - DrawableCompat.setTintList(switchView.getThumbDrawable(), thumbColorStateList); - DrawableCompat.setTintList(switchView.getTrackDrawable(), trackColorStateList); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeColorUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeColorUtils.java index fae8703d2f..92980125f9 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeColorUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/theme/ThemeColorUtils.java @@ -24,277 +24,20 @@ package com.owncloud.android.utils.theme; import android.accounts.Account; import android.content.Context; -import android.content.res.Configuration; import android.graphics.Color; -import com.nextcloud.client.account.User; +import com.nextcloud.android.common.ui.util.PlatformThemeUtil; import com.owncloud.android.R; -import com.owncloud.android.lib.resources.status.OCCapability; - -import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.ColorUtils; import static com.owncloud.android.utils.theme.CapabilityUtils.getCapability; /** * Utility class with methods for theming related. + * + * @deprecated use material 3 Schemes and utilities from common lib instead */ +@Deprecated public class ThemeColorUtils { - - private static final int INDEX_LUMINATION = 2; - private static final double MAX_LIGHTNESS = 0.92; - public static final double LUMINATION_THRESHOLD = 0.8; - - public ThemeColorUtils() { - } - - public int primaryAccentColor(Context context) { - OCCapability capability = CapabilityUtils.getCapability(context); - - try { - float adjust; - if (isDarkModeActive(context)) { - adjust = +0.5f; - } else { - adjust = -0.1f; - } - return adjustLightness(adjust, Color.parseColor(capability.getServerColor()), 0.35f); - } catch (Exception e) { - return context.getResources().getColor(R.color.color_accent); - } - } - - public int primaryDarkColor(Context context) { - return primaryDarkColor(null, context); - } - - public int primaryDarkColor(Account account, Context context) { - OCCapability capability = CapabilityUtils.getCapability(account, context); - - try { - return calculateDarkColor(Color.parseColor(capability.getServerColor()), context); - } catch (Exception e) { - return context.getResources().getColor(R.color.primary_dark); - } - } - - public int calculateDarkColor(int color, Context context) { - try { - return adjustLightness(-0.2f, color, -1f); - } catch (Exception e) { - return context.getResources().getColor(R.color.primary_dark); - } - } - - public int primaryColor(Context context) { - return primaryColor(context, false); - } - - public int primaryColor(Context context, boolean replaceEdgeColors) { - User nullUser = null; - return primaryColor(nullUser, replaceEdgeColors, context); - } - - public int primaryColor(User user, boolean replaceEdgeColors, Context context) { - return primaryColor(user != null ? user.toPlatformAccount() : null, - replaceEdgeColors, - false, - context); - } - - public int primaryColor(Account account, boolean replaceEdgeColors, Context context) { - return primaryColor(account, replaceEdgeColors, false, context); - } - - /** - * return the primary color defined in the server-side theming respecting Android dark/light theming and edge case - * scenarios including drawer menu. - * - * @param account the Nextcloud user - * @param replaceEdgeColors flag if edge case color scenarios should be handled - * @param replaceEdgeColorsByInvertedColor flag in edge case handling should be done via color inversion - * (black/white) - * @param context the context (needed to load client-side colors) - * @return the color - */ - public int primaryColor(Account account, - boolean replaceEdgeColors, - boolean replaceEdgeColorsByInvertedColor, - Context context) { - if (context == null) { - return Color.GRAY; - } - - try { - int color = Color.parseColor(getCapability(account, context).getServerColor()); - if (replaceEdgeColors) { - if (isDarkModeActive(context)) { - if (Color.BLACK == color) { - if (replaceEdgeColorsByInvertedColor) { - return Color.WHITE; - } else { - return getNeutralGrey(context); - } - } else { - return color; - } - } else { - if (Color.WHITE == color) { - if (replaceEdgeColorsByInvertedColor) { - return Color.BLACK; - } else { - return getNeutralGrey(context); - } - } else { - return color; - } - } - } else { - return color; - } - } catch (Exception e) { - return context.getResources().getColor(R.color.primary); - } - } - - public int getNeutralGrey(Context context) { - return darkTheme(context) ? context.getResources().getColor(R.color.fg_contrast) : Color.GRAY; - } - - public boolean themingEnabled(Context context) { - return CapabilityUtils.getCapability(context).getServerColor() != null && - !CapabilityUtils.getCapability(context).getServerColor().isEmpty(); - } - - /** - * returns the font color based on the server side theming and uses black/white as a fallback based on - * replaceWhite. - * - * @param context the context - * @param replaceWhite FLAG to return white/black if server side color isn't available - * @return int font color to use - */ - public int fontColor(Context context, boolean replaceWhite) { - if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { - if (replaceWhite) { - return Color.BLACK; - } else { - return Color.WHITE; - } - } - - try { - return Color.parseColor(getCapability(context).getServerTextColor()); - } catch (Exception e) { - if (darkTheme(context)) { - return Color.WHITE; - } else { - return Color.BLACK; - } - } - } - - public int fontColor(Context context) { - return fontColor(context, false); - } - - /** - * Tests if light color is set - * - * @param color the color - * @return true if primaryColor is lighter than MAX_LIGHTNESS - */ - public boolean lightTheme(int color) { - float[] hsl = colorToHSL(color); - - return hsl[INDEX_LUMINATION] >= MAX_LIGHTNESS; - } - - /** - * Tests if dark color is set - * - * @return true if dark theme -> e.g.use light font color, darker accent color - */ - public boolean darkTheme(Context context) { - int primaryColor = primaryColor(context); - float[] hsl = colorToHSL(primaryColor); - - return hsl[INDEX_LUMINATION] <= 0.55; - } - - public int primaryAppbarColor(Context context) { - return ContextCompat.getColor(context, R.color.appbar); - } - - public int appBarPrimaryFontColor(Context context) { - return ContextCompat.getColor(context, R.color.fontAppbar); - } - - public int appBarSecondaryFontColor(Context context) { - return ContextCompat.getColor(context, R.color.fontSecondaryAppbar); - } - - public int actionModeColor(Context context) { - return ContextCompat.getColor(context, R.color.action_mode_background); - } - - /** - * Adjust lightness of given color - * - * @param lightnessDelta values -1..+1 - * @param color original color - * @param threshold 0..1 as maximum value, -1 to disable - * @return color adjusted by lightness - */ - public int adjustLightness(float lightnessDelta, int color, float threshold) { - float[] hsl = colorToHSL(color); - - if (threshold == -1f) { - hsl[INDEX_LUMINATION] += lightnessDelta; - } else { - hsl[INDEX_LUMINATION] = Math.min(hsl[INDEX_LUMINATION] + lightnessDelta, threshold); - } - - return ColorUtils.HSLToColor(hsl); - } - - private float[] colorToHSL(int color) { - float[] hsl = new float[3]; - ColorUtils.RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), hsl); - - return hsl; - } - - public String colorToHexString(int color) { - return String.format("#%06X", 0xFFFFFF & color); - } - - /** - * returns a primary color matching color for texts/icons on top of a primary-colored element (like buttons). - * - * @param primaryColor the primary color - */ - public int getColorForPrimary(int primaryColor, Context context) { - if (Color.BLACK == primaryColor) { - return Color.WHITE; - } else if (Color.WHITE == primaryColor) { - return Color.BLACK; - } else { - return fontColor(context, false); - } - } - - public static boolean isDarkModeActive(Context context) { - int nightModeFlag = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - - return Configuration.UI_MODE_NIGHT_YES == nightModeFlag; - } - - public String primaryColorToHexString(Context context) { - return String.format("#%06X", 0xFFFFFF & primaryColor(context, true)); - } - public int unchangedPrimaryColor(Account account, Context context) { try { return Color.parseColor(getCapability(account, context).getServerColor()); @@ -307,7 +50,7 @@ public class ThemeColorUtils { try { return Color.parseColor(getCapability(context).getServerTextColor()); } catch (Exception e) { - if (darkTheme(context)) { + if (PlatformThemeUtil.isDarkMode(context)) { return Color.WHITE; } else { return Color.BLACK; diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeDrawableUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeDrawableUtils.java deleted file mode 100644 index 68138b9f49..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeDrawableUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; - -import androidx.annotation.DrawableRes; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatDelegate; -import androidx.core.content.res.ResourcesCompat; -import androidx.core.graphics.drawable.DrawableCompat; - -/** - * Utility class with methods for client side button theming. - */ -public final class ThemeDrawableUtils { - private final Context context; - - public ThemeDrawableUtils(Context context) { - this.context = context; - } - - public Drawable tintDrawable(@DrawableRes int id, int color) { - return tintDrawable(ResourcesCompat.getDrawable(context.getResources(), id, null), color); - } - - @Nullable - public Drawable tintDrawable(Drawable drawable, int color) { - if (drawable != null) { - Drawable wrap = DrawableCompat.wrap(drawable); - wrap.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - - return wrap; - } - - return null; - } - - public void setIconColor(Drawable drawable) { - int color; - - if (AppCompatDelegate.getDefaultNightMode() == AppCompatDelegate.MODE_NIGHT_YES) { - color = Color.WHITE; - } else { - color = Color.BLACK; - } - - tintDrawable(drawable, color); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeFabUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeFabUtils.java deleted file mode 100644 index 250e1a4e42..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeFabUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.content.res.ColorStateList; - -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import androidx.annotation.DrawableRes; - -/** - * Utility class with methods for client side FAB theming. - */ -public class ThemeFabUtils { - private final ThemeColorUtils themeColorUtils; - private final ThemeDrawableUtils themeDrawableUtils; - - public ThemeFabUtils(ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils) { - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; - } - - public void colorFloatingActionButton(FloatingActionButton button, - @DrawableRes int drawable, - Context context) { - int primaryColor = themeColorUtils.primaryColor(null, true, false, context); - - colorFloatingActionButton(button, context, primaryColor); - button.setImageDrawable(themeDrawableUtils.tintDrawable(drawable, - themeColorUtils.getColorForPrimary(primaryColor, - context))); - } - - public void colorFloatingActionButton(FloatingActionButton button, - Context context) { - colorFloatingActionButton(button, - context, - themeColorUtils.primaryColor(null, true, false, context)); - } - - public void colorFloatingActionButton(FloatingActionButton button, - Context context, - int primaryColor) { - colorFloatingActionButton(button, primaryColor, themeColorUtils.calculateDarkColor(primaryColor, context)); - } - - public void colorFloatingActionButton(FloatingActionButton button, int backgroundColor, int rippleColor) { - button.setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); - button.setRippleColor(rippleColor); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeLayoutUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeLayoutUtils.java deleted file mode 100644 index 14e5615ad6..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeLayoutUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; - -import com.google.android.material.tabs.TabLayout; -import com.owncloud.android.R; - -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -/** - * Utility class with methods for client side checkable theming. - */ -public class ThemeLayoutUtils { - private final ThemeColorUtils themeColorUtils; - - public ThemeLayoutUtils(ThemeColorUtils themeColorUtils) { - this.themeColorUtils = themeColorUtils; - } - - public void colorSwipeRefreshLayout(Context context, - SwipeRefreshLayout swipeRefreshLayout) { - int primaryColor = themeColorUtils.primaryColor(context); - int darkColor = themeColorUtils.primaryDarkColor(context); - int accentColor = themeColorUtils.primaryAccentColor(context); - - swipeRefreshLayout.setColorSchemeColors(accentColor, primaryColor, darkColor); - swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.bg_elevation_one); - } - - public void colorTabLayout(Context context, TabLayout tabLayout) { - int primaryColor = themeColorUtils.primaryColor(context, true); - int textColor = context.getResources().getColor(R.color.text_color); - tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); - tabLayout.setSelectedTabIndicatorColor(primaryColor); - tabLayout.setTabTextColors(textColor, primaryColor); - tabLayout.setTabIconTint(new ColorStateList( - new int[][]{ - new int[]{android.R.attr.state_selected}, - new int[]{android.R.attr.state_enabled}, - new int[]{-android.R.attr.state_enabled} - }, - new int[]{ - primaryColor, - textColor, - Color.GRAY - } - )); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeMenuUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeMenuUtils.java deleted file mode 100644 index 7b862b665f..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeMenuUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * @author TSI-mc - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * Copyright (C) 2022 TSI-mc - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.graphics.drawable.Drawable; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; -import android.view.MenuItem; - -import androidx.annotation.NonNull; -import androidx.core.graphics.drawable.DrawableCompat; - -/** - * Utility class with methods for client side checkable theming. - */ -public final class ThemeMenuUtils { - /** - * Will change a menu item text tint - * - * @param item the menu item object - * @param color the wanted color (as resource or color) - */ - public void tintMenuItemText(MenuItem item, int color) { - SpannableString newItemTitle = new SpannableString(item.getTitle()); - newItemTitle.setSpan(new ForegroundColorSpan(color), 0, newItemTitle.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - item.setTitle(newItemTitle); - } - - /** - * tinting menu item color - * - * @param item the menu item object - * @param color the color wanted as a color resource - */ - public void tintMenuIcon(@NonNull MenuItem item, int color) { - Drawable normalDrawable = item.getIcon(); - Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable); - DrawableCompat.setTint(wrapDrawable, color); - item.setIcon(wrapDrawable); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeSnackbarUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeSnackbarUtils.java deleted file mode 100644 index 6511954fe4..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeSnackbarUtils.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; - -import com.google.android.material.snackbar.Snackbar; -import com.owncloud.android.R; - -import androidx.core.content.ContextCompat; - -/** - * Utility class with methods for client side button theming. - */ -public final class ThemeSnackbarUtils { - /** - * set the Nextcloud standard colors for the snackbar. - * - * @param context the context relevant for setting the color according to the context's theme - * @param snackbar the snackbar to be colored - */ - public void colorSnackbar(Context context, Snackbar snackbar) { - // Changing action button text color - snackbar.setActionTextColor(ContextCompat.getColor(context, R.color.fg_inverse)); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextInputUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextInputUtils.java deleted file mode 100644 index c7a7e471d2..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextInputUtils.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Color; -import android.graphics.PorterDuff; -import android.widget.EditText; - -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; -import com.owncloud.android.R; - -import androidx.core.content.ContextCompat; - -/** - * Utility class with methods for client side text input theming. - */ -public final class ThemeTextInputUtils { - /** - * Sets the color of the (containerized) text input TextInputLayout to {@code color} for hint text, box stroke and - * highlight color. - * - * @param textInputLayout the TextInputLayout instance - * @param textInputEditText the TextInputEditText child element - * @param color the color to be used for the hint text and box stroke - */ - public void colorTextInput(TextInputLayout textInputLayout, - TextInputEditText textInputEditText, - int color, - int errorColor) { - textInputEditText.setHighlightColor(color); - colorTextInputLayout(textInputLayout, color, errorColor); - } - - /** - * Sets the color of the TextInputLayout to {@code color} for hint text and box stroke. - * - * @param textInputLayout the TextInputLayout instance - * @param color the color to be used for the hint text and box stroke - */ - private void colorTextInputLayout(TextInputLayout textInputLayout, int color, int errorColor) { - textInputLayout.setBoxStrokeColor(color); - textInputLayout.setErrorIconTintList(new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_focused}, - new int[]{android.R.attr.state_focused}, - }, - new int[]{ - errorColor, - errorColor - } - )); - textInputLayout.setErrorTextColor(new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_focused}, - new int[]{android.R.attr.state_focused}, - }, - new int[]{ - errorColor, - errorColor - } - )); - textInputLayout.setBoxStrokeErrorColor(new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_focused}, - new int[]{android.R.attr.state_focused}, - }, - new int[]{ - errorColor, - errorColor - } - )); - textInputLayout.setDefaultHintTextColor(new ColorStateList( - new int[][]{ - new int[]{-android.R.attr.state_focused}, - new int[]{android.R.attr.state_focused}, - }, - new int[]{ - Color.GRAY, - color - } - )); - } - - public void themeEditText(Context context, - EditText editText, - boolean themedBackground, - ThemeColorUtils themeColorUtils) { - if (editText == null) { - return; - } - - int color = ContextCompat.getColor(context, R.color.text_color); - - if (themedBackground) { - if (themeColorUtils.darkTheme(context)) { - color = ContextCompat.getColor(context, R.color.themed_fg); - } else { - color = ContextCompat.getColor(context, R.color.themed_fg_inverse); - } - } - - setEditTextColor(context, editText, color); - } - - public void setEditTextColor(Context context, EditText editText, int color) { - editText.setTextColor(color); - editText.setHighlightColor(context.getResources().getColor(R.color.fg_contrast)); - } - - public void colorEditText(EditText editText, int color) { - if (editText != null) { - editText.setTextColor(color); - editText.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP); - } - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextUtils.java deleted file mode 100644 index 1d3a300921..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeTextUtils.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.style.ForegroundColorSpan; - -/** - * Utility class with methods for client side checkable theming. - */ -public final class ThemeTextUtils { - public Spanned getColoredTitle(String title, int color) { - Spannable text = new SpannableString(title); - text.setSpan(new ForegroundColorSpan(color), - 0, - text.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - - return text; - } - - -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeToolbarUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeToolbarUtils.java deleted file mode 100644 index 2939c9c7fc..0000000000 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeToolbarUtils.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Nextcloud Android client application - * - * @author Tobias Kaminsky - * @author Andy Scherzinger - * Copyright (C) 2017 Tobias Kaminsky - * Copyright (C) 2017 Nextcloud GmbH - * Copyright (C) 2018 Andy Scherzinger - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * at your option) any later version. - * - * 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 Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package com.owncloud.android.utils.theme; - -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.os.Build; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; -import android.view.View; -import android.view.Window; -import android.widget.ImageView; - -import com.owncloud.android.R; - -import androidx.annotation.ColorInt; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.SearchView; -import androidx.core.content.res.ResourcesCompat; - -/** - * Utility class with methods for client side action/toolbar theming. - */ -public class ThemeToolbarUtils { - private final ThemeColorUtils themeColorUtils; - private final ThemeDrawableUtils themeDrawableUtils; - private final ThemeTextInputUtils themeTextInputUtils; - - public ThemeToolbarUtils(ThemeColorUtils themeColorUtils, - ThemeDrawableUtils themeDrawableUtils, - ThemeTextInputUtils themeTextInputUtils) { - this.themeColorUtils = themeColorUtils; - this.themeDrawableUtils = themeDrawableUtils; - this.themeTextInputUtils = themeTextInputUtils; - } - - /** - * For activities that do not use drawer, e.g. Settings, this can be used to correctly tint back button based on - * theme - * - * @param supportActionBar the back button's action bar - */ - public void tintBackButton(@Nullable ActionBar supportActionBar, Context context) { - tintBackButton(supportActionBar, context, themeColorUtils.appBarPrimaryFontColor(context)); - } - - public void tintBackButton(@Nullable ActionBar supportActionBar, Context context, @ColorInt int color) { - if (supportActionBar == null) { - return; - } - - Drawable backArrow = ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_arrow_back, null); - supportActionBar.setHomeAsUpIndicator(themeDrawableUtils.tintDrawable(backArrow, color)); - } - - /** - * Set color of title to white/black depending on background color - * - * @param actionBar actionBar to be used - * @param title title to be shown - */ - public void setColoredTitle(@Nullable ActionBar actionBar, String title, Context context) { - if (actionBar != null) { - Spannable text = new SpannableString(title); - text.setSpan(new ForegroundColorSpan(themeColorUtils.appBarPrimaryFontColor(context)), - 0, - text.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - actionBar.setTitle(text); - } - } - - public void setColoredTitle(@Nullable ActionBar actionBar, int titleId, Context context) { - setColoredTitle(actionBar, context.getString(titleId), context); - } - - /** - * Set color of subtitle to white/black depending on background color - * - * @param actionBar actionBar to be used - * @param title title to be shown - */ - public void setColoredSubtitle(@Nullable ActionBar actionBar, String title, Context context) { - if (actionBar != null) { - Spannable text = new SpannableString(title); - text.setSpan(new ForegroundColorSpan(themeColorUtils.appBarSecondaryFontColor(context)), - 0, - text.length(), - Spannable.SPAN_INCLUSIVE_INCLUSIVE); - actionBar.setSubtitle(text); - } - } - - /** - * Theme search view - * - * @param searchView searchView to be changed - * @param context the app's context - */ - public void themeSearchView(SearchView searchView, Context context) { - // hacky as no default way is provided - int fontColor = themeColorUtils.appBarPrimaryFontColor(context); - SearchView.SearchAutoComplete editText = searchView.findViewById(R.id.search_src_text); - editText.setTextSize(16); - themeTextInputUtils.setEditTextColor(context, editText, fontColor); - editText.setHintTextColor(themeColorUtils.appBarSecondaryFontColor(context)); - - ImageView closeButton = searchView.findViewById(androidx.appcompat.R.id.search_close_btn); - closeButton.setColorFilter(fontColor); - ImageView searchButton = searchView.findViewById(androidx.appcompat.R.id.search_button); - searchButton.setColorFilter(fontColor); - } - - /** - * Sets the color of the status bar to {@code color}. - * - * @param fragmentActivity fragment activity - * @param color the color - */ - public void colorStatusBar(Activity fragmentActivity, @ColorInt int color) { - Window window = fragmentActivity.getWindow(); - boolean isLightTheme = themeColorUtils.lightTheme(color); - if (window != null) { - window.setStatusBarColor(color); - View decor = window.getDecorView(); - if (isLightTheme) { - int systemUiFlagLightStatusBar; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; - } else { - systemUiFlagLightStatusBar = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; - } - decor.setSystemUiVisibility(systemUiFlagLightStatusBar); - } else { - decor.setSystemUiVisibility(0); - } - } - } - - public void colorStatusBar(Activity fragmentActivity) { - colorStatusBar(fragmentActivity, themeColorUtils.primaryAppbarColor(fragmentActivity)); - } -} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ThemeUtils.java b/app/src/main/java/com/owncloud/android/utils/theme/ThemeUtils.java index 0939c8d809..94a5207c05 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/ThemeUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/theme/ThemeUtils.java @@ -51,10 +51,4 @@ public final class ThemeUtils { } } } - - public boolean isDarkModeActive(Context context) { - int nightModeFlag = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; - - return Configuration.UI_MODE_NIGHT_YES == nightModeFlag; - } } diff --git a/app/src/main/java/com/owncloud/android/utils/theme/ViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/ViewThemeUtils.kt new file mode 100644 index 0000000000..38da91860b --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/ViewThemeUtils.kt @@ -0,0 +1,55 @@ +/* + * Nextcloud Android client application + * + * @author Álvaro Brey + * Copyright (C) 2022 Álvaro Brey + * Copyright (C) 2022 Nextcloud GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * 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 AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . + * + */ + +package com.owncloud.android.utils.theme + +import com.nextcloud.android.common.ui.color.ColorUtil +import com.nextcloud.android.common.ui.theme.MaterialSchemes +import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase +import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.AndroidXViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.DialogViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.MaterialViewThemeUtils +import javax.inject.Inject + +/** + * Child fields intentionally constructed instead of injected in order to reuse schemes for performance + */ +class ViewThemeUtils @Inject constructor( + schemes: MaterialSchemes, + colorUtil: ColorUtil +) : ViewThemeUtilsBase(schemes) { + @JvmField + val platform = AndroidViewThemeUtils(schemes, colorUtil) + + @JvmField + val material = MaterialViewThemeUtils(schemes, colorUtil) + + @JvmField + val androidx = AndroidXViewThemeUtils(schemes, platform) + + @JvmField + val dialog = DialogViewThemeUtils(schemes) + + @JvmField + val files = FilesSpecificViewThemeUtils(schemes, colorUtil, platform, androidx) +} diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml new file mode 100644 index 0000000000..834940ea35 --- /dev/null +++ b/app/src/main/res/drawable/ic_check.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/ic_dashboard.xml b/app/src/main/res/drawable/ic_dashboard.xml new file mode 100644 index 0000000000..ddff828159 --- /dev/null +++ b/app/src/main/res/drawable/ic_dashboard.xml @@ -0,0 +1,35 @@ + + + + + diff --git a/app/src/main/res/layout/account_item.xml b/app/src/main/res/layout/account_item.xml index 7dbe268cb5..f942d11740 100644 --- a/app/src/main/res/layout/account_item.xml +++ b/app/src/main/res/layout/account_item.xml @@ -27,7 +27,8 @@ android:layout_margin="@dimen/standard_quarter_margin" android:orientation="horizontal" app:cardBackgroundColor="@color/transparent" - app:cardElevation="0dp"> + app:cardElevation="0dp" + app:strokeWidth="@dimen/zero"> @@ -93,7 +94,7 @@ android:layout_height="wrap_content" android:text="@string/daily_backup" android:textColor="@color/text_color" - android:textSize="14sp" /> + android:textSize="@dimen/two_line_primary_text_size" /> - - + android:layout_marginTop="@dimen/standard_margin" + android:gravity="center" + android:orientation="horizontal" + android:weightSum="1.0"> + + + diff --git a/app/src/main/res/layout/backuplist_fragment.xml b/app/src/main/res/layout/backuplist_fragment.xml index e8394f3d7d..d1b312f74f 100644 --- a/app/src/main/res/layout/backuplist_fragment.xml +++ b/app/src/main/res/layout/backuplist_fragment.xml @@ -54,6 +54,9 @@ style="@style/Button.Borderless" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginStart="@dimen/standard_margin" + android:layout_marginEnd="@dimen/standard_margin" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/restore_selected" /> diff --git a/app/src/main/res/layout/dashboard_widget.xml b/app/src/main/res/layout/dashboard_widget.xml new file mode 100644 index 0000000000..435a42e206 --- /dev/null +++ b/app/src/main/res/layout/dashboard_widget.xml @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dashboard_widget_configuration_layout.xml b/app/src/main/res/layout/dashboard_widget_configuration_layout.xml new file mode 100644 index 0000000000..47ffc07000 --- /dev/null +++ b/app/src/main/res/layout/dashboard_widget_configuration_layout.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_choose_account.xml b/app/src/main/res/layout/dialog_choose_account.xml index dd77ce5edd..d99f9dec73 100644 --- a/app/src/main/res/layout/dialog_choose_account.xml +++ b/app/src/main/res/layout/dialog_choose_account.xml @@ -44,12 +44,6 @@ app:layout_constraintTop_toBottomOf="@id/current_account" tools:visibility="visible"> - - + app:cardCornerRadius="@dimen/button_corner_radius" + app:cardElevation="0dp" + app:checkedIcon="@null"> + app:cardCornerRadius="@dimen/button_corner_radius" + app:cardElevation="0dp" + app:checkedIcon="@null"> + app:cardCornerRadius="@dimen/button_corner_radius" + app:cardElevation="0dp" + app:checkedIcon="@null"> + app:cardCornerRadius="@dimen/button_corner_radius" + app:cardElevation="0dp" + app:checkedIcon="@null"> @@ -432,9 +443,9 @@ . --> + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + android:paddingRight="@dimen/drawer_content_horizontal_padding" + android:paddingBottom="@dimen/standard_padding" + android:visibility="gone" + tools:visibility="visible"> - + android:text="@string/drawer_quota" + app:trackCornerRadius="5dp" + app:trackThickness="5dp" + tools:progress="50" /> + android:padding="@dimen/dialog_padding"> - - + android:scrollbars="vertical" /> diff --git a/app/src/main/res/layout/file_details_fragment.xml b/app/src/main/res/layout/file_details_fragment.xml index a9879e7349..a779e4cf59 100644 --- a/app/src/main/res/layout/file_details_fragment.xml +++ b/app/src/main/res/layout/file_details_fragment.xml @@ -185,7 +185,6 @@ android:background="@color/bg_default" app:tabGravity="center" app:tabMode="fixed" - app:tabTextAppearance="@style/AppTabTextAppearance" app:tabTextColor="@color/text_color" app:tabInlineLabel="true" /> diff --git a/app/src/main/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml b/app/src/main/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml index d8e48e5fdc..b0313fba36 100644 --- a/app/src/main/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml @@ -25,15 +25,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" + android:paddingTop="@dimen/dialog_padding" android:background="@color/bg_default"> @@ -63,8 +64,7 @@ @@ -96,8 +96,7 @@ @@ -131,8 +130,7 @@ @@ -164,8 +162,7 @@ - diff --git a/app/src/main/res/layout/file_details_sharing_process_fragment.xml b/app/src/main/res/layout/file_details_sharing_process_fragment.xml index 249ef8dde1..5514622bf6 100644 --- a/app/src/main/res/layout/file_details_sharing_process_fragment.xml +++ b/app/src/main/res/layout/file_details_sharing_process_fragment.xml @@ -24,9 +24,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:minHeight="400dp" android:focusable="true" - android:focusableInTouchMode="true"> + android:focusableInTouchMode="true" + android:minHeight="400dp"> @@ -66,18 +66,21 @@ android:id="@+id/share_process_permission_read_only" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_share_view_only" /> @@ -88,7 +91,8 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_margin" android:text="@string/advanced_settings" - android:textColor="@color/secondary_text_color" + android:textColor="@color/primary" + android:textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/share_process_permission_radio_group" /> @@ -97,6 +101,7 @@ android:id="@+id/share_process_allow_resharing_checkbox" android:layout_width="0dp" android:layout_height="wrap_content" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/allow_resharing" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" @@ -108,39 +113,54 @@ android:id="@+id/share_process_set_password_switch" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/share_no_password_title" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/share_process_allow_resharing_checkbox" /> - + tools:visibility="visible"> + + + + + + + app:layout_constraintTop_toBottomOf="@+id/share_process_enter_password_container" /> @@ -163,6 +183,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_half_margin" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/share_via_link_hide_download" android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" @@ -175,23 +196,36 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_half_margin" + android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_name" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/share_process_hide_download_checkbox" /> - + tools:visibility="visible"> + + + + + + + share_process_change_name_container" /> + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@+id/share_process_btn_next" /> + diff --git a/app/src/main/res/layout/file_list_actions_bottom_sheet_creator.xml b/app/src/main/res/layout/file_list_actions_bottom_sheet_creator.xml index 5e437c3e5e..50aafa58ae 100644 --- a/app/src/main/res/layout/file_list_actions_bottom_sheet_creator.xml +++ b/app/src/main/res/layout/file_list_actions_bottom_sheet_creator.xml @@ -22,20 +22,22 @@ @@ -44,7 +46,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginStart="@dimen/standard_margin" + android:layout_marginStart="@dimen/bottom_sheet_text_start_margin" android:text="@string/create_new_presentation" android:textColor="@color/text_color" android:textSize="@dimen/bottom_sheet_text_size" /> diff --git a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml index 06440c2e51..35c652aa6c 100644 --- a/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml +++ b/app/src/main/res/layout/file_list_actions_bottom_sheet_fragment.xml @@ -17,10 +17,10 @@ License along with this program. If not, see . --> @@ -66,9 +67,10 @@ @@ -97,9 +99,10 @@ @@ -128,8 +131,9 @@ - - - - + android:visibility="gone" + tools:visibility="visible"> @@ -244,9 +232,10 @@ @@ -273,9 +262,10 @@ - - - + android:visibility="gone" + tools:visibility="visible"> - - - + android:orientation="vertical" /> + + + app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior" + app:srcCompat="@drawable/ic_plus" + tools:visibility="visible"/> diff --git a/app/src/main/res/layout/fragment_gallery_bottom_sheet.xml b/app/src/main/res/layout/fragment_gallery_bottom_sheet.xml index aa628c8979..5201aa0cea 100644 --- a/app/src/main/res/layout/fragment_gallery_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_gallery_bottom_sheet.xml @@ -127,6 +127,7 @@ android:paddingBottom="@dimen/standard_half_padding"> + android:layout_height="@dimen/bottom_sheet_item_height" + android:background="?android:attr/selectableItemBackground" + android:paddingStart="@dimen/standard_padding" + android:paddingEnd="@dimen/standard_padding"> + android:padding="@dimen/dialog_padding"> + android:layout_marginBottom="@dimen/standard_margin" + tools:text="@string/end_to_end_encryption_keywords_description" /> + android:visibility="gone" + tools:text="passphrase" + tools:visibility="visible" /> - + tools:visibility="visible"> + + + + + diff --git a/app/src/main/res/layout/sorting_order_fragment.xml b/app/src/main/res/layout/sorting_order_fragment.xml index 2bd6600b14..8388e705a5 100644 --- a/app/src/main/res/layout/sorting_order_fragment.xml +++ b/app/src/main/res/layout/sorting_order_fragment.xml @@ -24,6 +24,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minWidth="300dp" + android:padding="@dimen/dialog_padding" android:orientation="vertical"> + android:text="@string/sort_by" + android:paddingBottom="@dimen/standard_padding"/> + android:paddingEnd="@dimen/standard_half_padding" + android:paddingBottom="@dimen/standard_half_padding" + android:src="@drawable/ic_alphabetical_asc" /> - - + diff --git a/app/src/main/res/layout/upload_files_layout.xml b/app/src/main/res/layout/upload_files_layout.xml index 03c214e504..ee799542bc 100644 --- a/app/src/main/res/layout/upload_files_layout.xml +++ b/app/src/main/res/layout/upload_files_layout.xml @@ -23,7 +23,8 @@ android:layout_height="fill_parent" android:orientation="vertical"> - + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/widget_item_load_more.xml b/app/src/main/res/layout/widget_item_load_more.xml new file mode 100644 index 0000000000..93ed31ae2d --- /dev/null +++ b/app/src/main/res/layout/widget_item_load_more.xml @@ -0,0 +1,37 @@ + + + + + + + + diff --git a/app/src/main/res/layout/widget_list_item.xml b/app/src/main/res/layout/widget_list_item.xml new file mode 100644 index 0000000000..632bf43e10 --- /dev/null +++ b/app/src/main/res/layout/widget_list_item.xml @@ -0,0 +1,47 @@ + + + + + + + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index be0edc80c3..e0324371e0 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -184,7 +184,6 @@ التصريح غير مفعل النسخ الاحتياطي اليومي البيانات التي سيتم نسخها احتياطيا - غير معروف التصريح خاطئ حذف الحساب حذف الحساب %s وحذف جميع الملفات المحلية؟\n\nعملية الحذف لا يمكن التراجع عنها. diff --git a/app/src/main/res/values-b+en+001/strings.xml b/app/src/main/res/values-b+en+001/strings.xml index 462a5fa18c..055bcce90b 100644 --- a/app/src/main/res/values-b+en+001/strings.xml +++ b/app/src/main/res/values-b+en+001/strings.xml @@ -184,7 +184,6 @@ Credentials disabled Daily backup Data to back up - Unknown Incorrect credentials Remove account Remove account %s and delete all local files?\n\nDeletion cannot be undone. diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index ccb5c6d95b..8d5fcbc13d 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -127,7 +127,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 7a18034482..441d811e2d 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -185,7 +185,6 @@ Потребителските данни са спрени Ежедневно архивиране Данни за архивиране - Неизвестен Грешни данни за вход Изтриване Изтриване на профила %s и всички локални файлове?\n\nИзтриването е необратима операция. diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index efebdee1e3..d10c517669 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -166,7 +166,6 @@ Ouzhpennañ titouroù an teuliad kroui titouroù an teuliad Titouroù identitelez disaotreet - Dianv Titouroù identitelez fall Lemel ar c\'hont Lemel ar c\'hont %s ha toud e restroù ?\n\nN\'eo ket posuple disober ur wech graet. diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 616a342b75..53dd186222 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -184,7 +184,6 @@ Credencials desactivades Còpia de seguretat diària Dades a fer una còpia de seguretat - Desconegut Credencials incorrectes Suprimeix el compte Suprimeix el compte %s i tots els fitxers locals?\n\nAquesta acció no es pot desfer. diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 76b3fde024..78a6d3db12 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -184,7 +184,6 @@ Přihlašovací údaje znepřístupněny Každodenní záloha Data k zálohování - Neznámé Neplatné přihlašovací údaje Odebrat účet Odebrat účet %s a smazat všechny místní soubory?\n\nTuto akci nelze vzít zpět. diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index f06f728a6b..b39cf00796 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -184,7 +184,6 @@ Brugeroplysninger deaktiverede Daglig backup Data at sikkerhedskopiere - Ukendt Ukorrekte brugeroplysninger Fjern konto Slet konto %s og slet alle filer lokalt?\n\nDu kan ikke fortryde en sletning. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ad1e57e066..72f41a4bde 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -184,7 +184,6 @@ Zugangsdaten ausgeschaltet Tägliche Sicherung Zu sichernde Daten - Unbekannt Zugangsdaten falsch Benutzerkonto löschen Konto %s und alle lokalen Dateien löschen?\n\nLöschung kann nicht rückgängig gemacht werden. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 168a697643..ae3533b963 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -184,7 +184,6 @@ Απενεργοποιημένα διαπιστευτήρια Ημερήσιο αντίγραφο ασφαλείας Δεδομένα για δημιουργία αντιγράφου ασφαλείας - Άγνωστο Λανθασμένα διαπιστευτήρια Αφαίρεση λογαριασμού Κατάργηση λογαριασμού %s και διαγραφή όλων των τοπικών αρχείων; \ n \ nΗ διαγραφή δεν μπορεί να ανακληθεί. diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index bab0e62ff0..ed19673472 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -148,7 +148,6 @@ Krei novan prezentaĵon Krei novan kalkultabelon Akreditiloj estas malebligitaj - Nekonata Malĝustaj akreditiloj Forigi konton Ĉu forigi la konton %s kaj forigi ĉiujn lokajn dosierojn?\n\nMalfari la forigadon tute ne eblas. diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 0fecaaf6cb..2e8604a82f 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -171,7 +171,6 @@ Agregar información de carpeta Crear información de carpeta Contraseña deshabilitada - Desconocido Contraseña incorrecta Eliminar cuenta ¿Deseas eliminar la cuenta %s y eliminar todos los archivos locales?\n\nLa eliminación no se puede deshacer. diff --git a/app/src/main/res/values-es-rCL/strings.xml b/app/src/main/res/values-es-rCL/strings.xml index f1fec6bad8..f0316fcece 100644 --- a/app/src/main/res/values-es-rCL/strings.xml +++ b/app/src/main/res/values-es-rCL/strings.xml @@ -130,7 +130,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rCO/strings.xml b/app/src/main/res/values-es-rCO/strings.xml index 2eb07098d1..7803f077d7 100644 --- a/app/src/main/res/values-es-rCO/strings.xml +++ b/app/src/main/res/values-es-rCO/strings.xml @@ -150,7 +150,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rCR/strings.xml b/app/src/main/res/values-es-rCR/strings.xml index ff26e28807..723cd72a22 100644 --- a/app/src/main/res/values-es-rCR/strings.xml +++ b/app/src/main/res/values-es-rCR/strings.xml @@ -130,7 +130,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rDO/strings.xml b/app/src/main/res/values-es-rDO/strings.xml index a9a1d1b1a6..42124d3354 100644 --- a/app/src/main/res/values-es-rDO/strings.xml +++ b/app/src/main/res/values-es-rDO/strings.xml @@ -145,7 +145,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rEC/strings.xml b/app/src/main/res/values-es-rEC/strings.xml index d9f383a7af..35931e76a2 100644 --- a/app/src/main/res/values-es-rEC/strings.xml +++ b/app/src/main/res/values-es-rEC/strings.xml @@ -145,7 +145,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rGT/strings.xml b/app/src/main/res/values-es-rGT/strings.xml index 3720ccc1a8..124cbcb3dc 100644 --- a/app/src/main/res/values-es-rGT/strings.xml +++ b/app/src/main/res/values-es-rGT/strings.xml @@ -130,7 +130,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rHN/strings.xml b/app/src/main/res/values-es-rHN/strings.xml index 6dc80507cf..58b30d7ba1 100644 --- a/app/src/main/res/values-es-rHN/strings.xml +++ b/app/src/main/res/values-es-rHN/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 5610e7492c..32ea4c707f 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -175,7 +175,6 @@ Agregar información de la carpeta crea la información de la carpeta Credenciales deshabilitadas - Desconocido Credenciales incorrectas Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer diff --git a/app/src/main/res/values-es-rNI/strings.xml b/app/src/main/res/values-es-rNI/strings.xml index cffc074892..904703c2e7 100644 --- a/app/src/main/res/values-es-rNI/strings.xml +++ b/app/src/main/res/values-es-rNI/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rPA/strings.xml b/app/src/main/res/values-es-rPA/strings.xml index cffc074892..904703c2e7 100644 --- a/app/src/main/res/values-es-rPA/strings.xml +++ b/app/src/main/res/values-es-rPA/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rPE/strings.xml b/app/src/main/res/values-es-rPE/strings.xml index c1afc011fe..b0b9de8e34 100644 --- a/app/src/main/res/values-es-rPE/strings.xml +++ b/app/src/main/res/values-es-rPE/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rPR/strings.xml b/app/src/main/res/values-es-rPR/strings.xml index cffc074892..904703c2e7 100644 --- a/app/src/main/res/values-es-rPR/strings.xml +++ b/app/src/main/res/values-es-rPR/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rPY/strings.xml b/app/src/main/res/values-es-rPY/strings.xml index 07d0fe95ed..6c25303cd2 100644 --- a/app/src/main/res/values-es-rPY/strings.xml +++ b/app/src/main/res/values-es-rPY/strings.xml @@ -115,7 +115,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rSV/strings.xml b/app/src/main/res/values-es-rSV/strings.xml index ff26e28807..723cd72a22 100644 --- a/app/src/main/res/values-es-rSV/strings.xml +++ b/app/src/main/res/values-es-rSV/strings.xml @@ -130,7 +130,6 @@ Crear No fue posible crear la carpeta Crear nueva carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es-rUY/strings.xml b/app/src/main/res/values-es-rUY/strings.xml index 6eb0ec097a..e57aea7f14 100644 --- a/app/src/main/res/values-es-rUY/strings.xml +++ b/app/src/main/res/values-es-rUY/strings.xml @@ -143,7 +143,6 @@ Copiar liga Crear No fue posible crear la carpeta - Desconocido Cerrar sesión ¿Borrar la cuenta %s y borrar todos los archivos localeS?\n\nEl borrado no se puede deshacer Deseleccionar todo diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index cb0dad916c..6b4e6c05b7 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -184,7 +184,6 @@ Credenciales desactivadas Copia de seguridad diaria Datos a respaldar - Desconocido Credenciales incorrectas Eliminar cuenta ¿Eliminar cuenta %s y borrar todos los archivos locales?\n\nEl borrado no se puede deshacer. diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index d029f11c4a..eadfbe5c4d 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -184,7 +184,6 @@ Kredentzialak desgaituta Eguneko babeskopia Babesteko datuak - Ezezaguna Kredentzial okerrak Ezabatu kontua %s kontua kendu eta fitxategi lokal guztiak ezabatu?\n\nBehin ezabatuta ezin da atzera egin. diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 6b39719c1a..ac3ea89b6f 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -174,7 +174,6 @@ اطلاعات پوشه را اضافه کنید ایجاد اطلاعات پوشه اعتبارنامه غیرفعال است - ناشناخته اعتبارنامه نادرست است حذف حساب کاربری برداشتن حساب %s و حذف تمام پرونده‌ّای محلّی؟\n\nحذف قابل بازگردانی نیست. diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index fdb6c5bb90..6f690f4832 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -184,7 +184,6 @@ Kirjautumistiedot poistettu käytöstä Päivittäinen varmuuskopio Varmuuskopioitavat tiedot - Tuntematon Virheelliset kirjautumistiedot Poista tili Poistetaanko tili %s ja kaikki sen paikalliset tiedostot?\n\nPoistamista ei voi perua. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 78c57027a1..cd5d8e1757 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -184,7 +184,6 @@ Informations d\'identification désactivées Sauvegarde journalière Données à sauvegarder - Inconnu Informations d\'identification erronées Supprimer le compte Supprimer le compte %s et supprimer tous les fichiers locaux ? diff --git a/app/src/main/res/values-gd/strings.xml b/app/src/main/res/values-gd/strings.xml index 1a09d91452..4b7b2ad6d1 100644 --- a/app/src/main/res/values-gd/strings.xml +++ b/app/src/main/res/values-gd/strings.xml @@ -169,7 +169,6 @@ Cuir fiosrachadh pasgain ris cruthaichidh seo fiosrachadh pasgain Chaidh an teisteas a chur à comas - Chan eil fhios Teisteas ceàrr Thoir air falbh an cunntas A bheil thu airson cunntas %s a thoirt air falbh ’s na faidhlichean ionadail uile a sguabadh às?\n\Cha ghabh an sguabadh às a neo-dhèanamh. diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index ba6b87bfd3..ee6d227a9d 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -175,7 +175,6 @@ Engadir información do cartafol crear a información do cartafol Credenciais eliminadas - Descoñecido Credenciais incorrectas Eliminar conta Retirar a conta %s e eliminar os ficheiros locais?\n\n Esta eliminación non pode desfacerse. diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 4e1905d2b9..6e1cba8115 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -184,7 +184,6 @@ Vjerodajnice onemogućene Svakodnevno sigurnosno kopiranje Podaci za sigurnosno kopiranje - Nepoznato Netočne vjerodajnice Izbriši račun Želite li ukloniti račun %s i izbrisati sve lokalne datoteke?\n\nBrisanje se ne može poništiti. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 3abab6541b..3c81515488 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -184,7 +184,6 @@ Hitelesítő adatok letiltva Napi biztonsági mentés Mentendő adatok - Ismeretlen Hibás hitelesítési adatok Fiók eltávolítása A(z) %s fiók törlése az összes helyi fájlal együtt?\n\nA törlés nem vonható vissza. diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 0340a8311d..c29f85c4ac 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -178,7 +178,6 @@ Otomatis unggah hanya bekerja dengan baik apabila anda mengeluarkan aplikasi ini Kredensial dimatikan Pencadangan harian Data untuk dicadangkan - Tidak diketahui Kredensial tidak tepat Hapus akun Hapus akun %s dan hapus semua file lokal? Penghapusan tidak dapat dibatalkan. diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index d51f6a346c..508db25a13 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -176,7 +176,6 @@ Bæta við upplýsingum möppu býr til upplýsingar um möppu Auðkenni óvirk - Óþekkt Röng auðkenni Fjarlægja reikning Fjarlægja notandaaðgang %s og eyða öllum staðværum skrám?\n\nEkki er hægt að afturkalla aðgerðina. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index dd61776070..18529b4be4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -183,7 +183,6 @@ Credenziali disabilitate Backup giornaliero Dati di cui eseguire il backup - Sconosciuta Credenziali non corrette Rimuovi account Rimuovere l\'account %s e tutti i file salvati localmente?\n\nIl processo non può essere annullato. diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index b68fe12a03..5f76efe9dc 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -169,7 +169,6 @@ הוספת פרטי תיקייה יוצר פרטי תיקייה פרטי גישה מושבתים - לא ידוע פרטי הגישה שגויים הסרת חשבון להסיר את החשבון %s ולמחוק את כל הקבצים המקומיים?\n\nלא ניתן לבטל מחיקה. diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index fb1d24357a..8b33956a32 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -183,7 +183,6 @@ 資格情報が無効です 毎日のバックアップ バックアップするデータ - 不明 不正な資格情報 アカウント削除 アカウント %s のファイルとアカウントを削除しますか?\n\n削除すると復元はできません。 diff --git a/app/src/main/res/values-ka-rGE/strings.xml b/app/src/main/res/values-ka-rGE/strings.xml index 8afd20df66..3c130629e4 100644 --- a/app/src/main/res/values-ka-rGE/strings.xml +++ b/app/src/main/res/values-ka-rGE/strings.xml @@ -122,7 +122,6 @@ ამჟამად კოპირება/გადატანა დაშიფრულ დირექტორიაში არაა მხარდაჭერილი. შექმნა დირექტორია ვერ შეიქმნა - ამოუცნობი ანგარიშის გაუქმება გავაუქმოთ ანგარიში %s და ყველა ლოკალური ფაილი?\n\nგაუქმება ვერ იქნება უკუბრუნებული. ყველას წაშლა diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d8753f3893..68a50ed7a6 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -183,7 +183,6 @@ 인증 비활성화됨 매일 백업 백업 할 날짜 - 알 수 없음 인증 정보 틀림 계정 삭제 %s 계정 및 모든 로컬 파일을 삭제하시겠습니까\n\n삭제 작업은 취소할 수 없습니다. diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index b71fe0e722..514693a6d4 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -172,7 +172,6 @@ ເພີ່ມຂໍ້ມູນໂຟນເດີ ສ້າງໂຟນເດີຂໍ້ມຸນ ຂໍ້ມູນປະຈໍາຕົວຖືກປິດ - ບໍ່ຮູ້ ການຢັ້ງຢືນຕົວຕົນທີ່ບໍ່ຖືກຕ້ອງ ຍ້າຍບັນຊີ ລຶບບັນຊີ %sແລະ ລຶບຟາຍໃນຊ່ອງເກັບທັງຫມົດ?\n\nDeletion ບໍ່ສາມາດລົບລ້າງໄດ້. diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index cd05bf716e..6cd8f41501 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -184,7 +184,6 @@ Prisijungimo duomenys išjungti Kasdienės atsarginės kopijos Duomenys, kurių atsarginę kopiją daryti - Nežinoma Neteisingi prisijungimo duomenys Šalinti paskyrą Pašalinti paskyrą %s ir ištrinti visus vietinius failus?\n\nIštrynimo nebegalima bus atšaukti. diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 63f8f60745..2740f7d323 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -146,7 +146,6 @@ Pievienot mapes informāciju pievieno mapes informāciju Akreditācijas dati atspējoti - Nezināms Nepareizi akreditācijas dati Noņemt kontu Noņemt kontu %s un izdzēst visas vietēji saglabātās datnes?\n\nDzēšanu nevar atsaukt. diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml index 9a2504538d..d0b9db0269 100644 --- a/app/src/main/res/values-mk/strings.xml +++ b/app/src/main/res/values-mk/strings.xml @@ -176,7 +176,6 @@ Додади информации за папката Акредитивите се оневозможени Дневена резервна копија - Непознат Погрешни акредитиви Отстрани сметка Избриши ја сметката %s и избриши ги локалните датотеки?\n\nПозсле бришењето на датотеките неможат да се вратат. diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index a98cb8d67e..474543bf6e 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -184,7 +184,6 @@ Legitimasjon deaktivert Daglig sikkerhetskopi Data å sikkerhetskopiere - Ukjent Feil legitimasjon Fjern konto Fjern kontoen %s og slett alle lokale filer?\n\nSletting kan ikke angres. diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 58336c603e..08bf64d552 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -29,9 +29,7 @@ #ffffff #121212 - #717171 #000000 - #2D2D2D #818181 #222222 #ffffff @@ -45,8 +43,6 @@ #ffffff #737373 - #2a2a2a - #B3FFFFFF @color/white diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 0882324f23..0110b225b2 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -184,7 +184,6 @@ Inloggegevens uitgeschakeld Dagelijkse back-up Te back-uppen data - Onbekend Ongeldige inloggegevens Account verwijderen Verwijder account %s met alle lokale bestanden? Het verwijderen kan niet worden teruggedraaid. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 42d2b1b278..2e0655b079 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -184,7 +184,6 @@ Poświadczenia wyłączone Codzienna kopia zapasowa Dane dla kopii zapasowej - Nieznane Błedne poświadczenia Usuń konto Usunąć konto %s i wszystkie jego pliki lokalne? Usunięcia nie będzie można cofnąć. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7ce0ad7c18..2b6dca778a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -184,7 +184,6 @@ Credenciais desabilitadas Backup diário Dados para backup - Desconhecido Credenciais incorretas Remover conta Excluir a conta %s e remover todos os arquivos locais?\n\nEsta exclusão não pode ser desfeita. diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 99e2076a14..9912cd2ce7 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -181,7 +181,6 @@ cria informação sobre a pasta Credenciais desativadas Cópia de segurança diária - Desconhecido Credenciais incorretas Remover conta Excluir a conta %s e remover todos os ficheiros locais?\n\nEsta exclusão não pode ser desfeita. diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 3ab975045e..1a3bdbda83 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -184,7 +184,6 @@ Autentificare dezactivată Copie de rezervă zilnică Date pentru copia de rezervă - Necunoscut Date de autentificare incorecte Sterge contul Eliminați contul %s și ștergeți toate fișierele locale?\n\nȘtergerea nu poate fi anulată. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index eaab2f25d3..9e5ebc31bb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -184,7 +184,6 @@ Учётная запись отключена Ежедневное резервное копирование Данные для резервного копирования - Неизвестно Неверные учётные данные Удалить аккаунт Удалить аккаунт %s и все связанные с ним файлы?\n\nУдаление не может быть отменено. diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index af75a6408c..6f9f654e0f 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -176,7 +176,6 @@ Agiunghe informatziones de sa cartella creat informatziones de sa cartella Credentziales disativadas - Non connotu Credentziales isballiadas Boga·nche su contu Bogare su contu %s e cantzellare is documentos locales?\n\nSa cantzelladura non faghet a dd\'annullare. diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml index 8272542de6..39b346e88b 100644 --- a/app/src/main/res/values-sk-rSK/strings.xml +++ b/app/src/main/res/values-sk-rSK/strings.xml @@ -183,7 +183,6 @@ Prihlasovacie údaje zakázané Denná záloha Dáta pre zálohovanie - Neznámy Nesprávne prihlasovacie údaje Odstrániť účet Zmazať účet %s a zmazať všetky lokálne súbory?\n\nZmazanie nebude možné vrátiť späť. diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index ff35ffb5cb..fd5ee43785 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -183,7 +183,6 @@ Poverila so onemogočena Dnevna varnostna kopija Podatki za varnostno kopiranje - Neznano Nepravilna poverila Odstrani račun Ali želite odstraniti račun %s z vsemi krajevnimi datotekami?\n\nBrisanja kasneje ni mogoče razveljaviti. diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index d2d918ce39..310487ed1d 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -160,7 +160,6 @@ Shto informacion për dosjen Krijon informacionin e dosjeve Kredencialet të pa aktivizuara - I panjohur Kredenciele jo të sakta Hiqe llogarinë Fshij llogarinë %s me të gjithë skedarët lokalë?\n\nFshirja nuk mund të zhbëhet. diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index 8722fbce47..0456627f7f 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -146,7 +146,6 @@ Napravi novu prezentaciju Napravi novu tabelu Akreditivi isključeni - Nepoznato Neispravni akreditivi Ukloni nalog Uklonite nalog %s i izbrišite sve lokalne fajlove?\n\nBrisanje ne može da se povrati. diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index ee200f7b9f..f326cf5813 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -167,7 +167,6 @@ Додај информације о фасцикли прави информације о фасцикли Акредитиви искључени - Непознато Неисправни акредитиви Уклони налог Уклонити налог %s и избрисати све локалне фајлове?\n\nБрисање се не може опозвати. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index d2dd5708f4..ee455bfe44 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -184,7 +184,6 @@ Inloggningsuppgifter inaktiverade Daglig säkerhetskopiering Data att säkerhetskopiera - Okänd Felaktiga inloggningsuppgifter Ta bort konto Ta bort konto %s med alla lokala filer?\n\nBorttagning kan inte ångras. diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index cb4323f3cd..1d685b2ecf 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -166,7 +166,6 @@ เพิ่มข้อมูลโฟลเดอร์ สร้างข้อมูลโฟลเดอร์ ข้อมูลประจำตัวถูกปิดใช้งาน - ไม่ทราบ ข้อมูลประจำตัวไม่ถูกต้อง ลบบัญชี ลบบัญชี %s ออก และลบไฟล์ในเครื่องทั้งหมดหรือไม่?\n\nเมื่อลบแล้ว จะไม่สามารถย้อนกลับได้ diff --git a/app/src/main/res/values-tk/strings.xml b/app/src/main/res/values-tk/strings.xml index c0cfe6365f..bdf98a9ba2 100644 --- a/app/src/main/res/values-tk/strings.xml +++ b/app/src/main/res/values-tk/strings.xml @@ -168,7 +168,6 @@ Bukja barada maglumat goşuň bukja barada maglumatlar döredilýär Şahsyýet maglumatlary ýapyldy - Näbelli Nädogry şahsyýet maglumatlary Hasaby aýyryň %sHasaby aýyryň we ähli ýerli faýllary pozuň? \ N \ n Öçürip bolmaýar. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 2631b13d3a..6b900e8924 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -184,7 +184,6 @@ Kimlik doğrulama bilgileri kullanılmıyor Günlük yedek Yedeklenecek veriler - Bilinmiyor Kimlik doğrulama bilgileri hatalı Hesabı kaldır %s hesabı ve tüm yerel dosyalar kaldırılsın mı?\n\nSilme işlemi geri alınamaz. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 4086eee1ab..d4c8e36a48 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -185,7 +185,6 @@ Дані авторизації не активні Щоденне резервне збереження Дані для резервного збереження - Невідомо Неправильні дані авторизації Видалити обліковий запис Видалити обліковий запис %s і знищити всі локальні файли?\n\nВидалення не можна буде відмінити. diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 3323e82e98..20b1568082 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -183,7 +183,6 @@ Đã vô hiệu hóa thông tin đăng nhập Sao lưu hàng ngày Dữ liệu được sao lưu - Không xác định Thông tin đăng nhập không chính xác Xóa tài khoản Xóa tài khoản %s và xóa tất cả các tệp cục bộ?\n\nXóa không thể hoàn tác. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 13a79daea6..c9118b89c3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -183,7 +183,6 @@ 设备凭证已禁用 每日备份 要备份的数据 - 未知 凭据不正确 删除账号 删除账号 %s 并删除所有本地文件吗?\n\n一经删除无法撤销。 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index dfade1b0b6..5900fab3e7 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -184,7 +184,6 @@ 認證方式已取消 每日備份 要備份的數據 - 不詳 不正確的認證方式 刪除賬戶 移除賬號%s並刪除所有近端檔案?\n\n刪除後將無法恢復。 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index bb53be548e..7b32734fea 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -184,7 +184,6 @@ 認證方式已取消 每日備份 要備份的資料 - 未知 不正確的認證方式 刪除帳號 移除帳號 %s 並刪除所有本機檔案?\n\n刪除後將無法復原。 diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 8378ef5bd5..f5d46ac6a7 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -1,16 +1,16 @@ - - @string/pref_behaviour_entries_keep_file - @string/pref_behaviour_entries_move - @string/pref_behaviour_entries_delete_file - + + @string/pref_behaviour_entries_keep_file + @string/pref_behaviour_entries_move + @string/pref_behaviour_entries_delete_file + - - LOCAL_BEHAVIOUR_FORGET - LOCAL_BEHAVIOUR_MOVE - LOCAL_BEHAVIOUR_DELETE - + + LOCAL_BEHAVIOUR_FORGET + LOCAL_BEHAVIOUR_MOVE + LOCAL_BEHAVIOUR_DELETE + @string/pref_instant_name_collision_policy_entries_always_ask @@ -29,4 +29,9 @@ @string/link_share_view_only @string/link_share_editing + + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 20373da3ea..f844b3156f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,5 +1,4 @@ - - - #FFFFFF - #000000 - @android:color/white #666666 diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index 11670f1ea3..af96f9423f 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -20,13 +20,16 @@ 164dp 12sp 20dp - 56dp + 40dp + 56dp + 80dp 40dp 128dp 8dp 3dp 128dp 512 + 28dp 16dp 32dp 8dp @@ -140,4 +143,7 @@ 48dp 24dp 400dp + 24dp + 24dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0fc27a43f4..a696ab21c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -635,7 +635,6 @@ Push notifications currently not available. Fetching most recent version of the file. - Unknown No resized image available. Download full image? @@ -955,8 +954,8 @@ Do not disturb Away Invisible - - 😃 + + 😃 Don\'t clear Today 30 minutes @@ -1041,4 +1040,15 @@ Filename already exists Export Locate folder + Shows one widget from dashboard + Icon of dashboard widget + Refresh content + Icon of widget entry + Choose widget + Reload + Widgets are only available on %1$s 25 or later + Not available + icon for empty list + No items + Check back later or reload. diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 154e467b07..3a973dc787 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,5 +1,4 @@ - - - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000000..8651adcb77 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/app/src/main/res/xml/dashboard_widget_info.xml b/app/src/main/res/xml/dashboard_widget_info.xml new file mode 100644 index 0000000000..9f74561b9f --- /dev/null +++ b/app/src/main/res/xml/dashboard_widget_info.xml @@ -0,0 +1,32 @@ + + + diff --git a/app/src/test/java/com/nextcloud/client/jobs/BackgroundJobFactoryTest.kt b/app/src/test/java/com/nextcloud/client/jobs/BackgroundJobFactoryTest.kt index 62fd204626..86d2cbce78 100644 --- a/app/src/test/java/com/nextcloud/client/jobs/BackgroundJobFactoryTest.kt +++ b/app/src/test/java/com/nextcloud/client/jobs/BackgroundJobFactoryTest.kt @@ -35,9 +35,7 @@ import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.UploadsStorageManager -import com.owncloud.android.utils.theme.ThemeButtonUtils -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeSnackbarUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import org.greenrobot.eventbus.EventBus import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull @@ -46,7 +44,6 @@ import org.junit.Test import org.mockito.Mock import org.mockito.MockitoAnnotations import org.mockito.kotlin.whenever -import javax.inject.Provider class BackgroundJobFactoryTest { @@ -102,13 +99,7 @@ class BackgroundJobFactoryTest { private lateinit var deckApi: DeckApi @Mock - private lateinit var themeColorUtils: ThemeColorUtils - - @Mock - private lateinit var themeSnackbarUtils: ThemeSnackbarUtils - - @Mock - private lateinit var themeButtonUtils: ThemeButtonUtils + private lateinit var viewThemeUtils: ViewThemeUtils private lateinit var factory: BackgroundJobFactory @@ -121,7 +112,7 @@ class BackgroundJobFactoryTest { contentResolver, clock, powerManagementService, - Provider { backgroundJobManager }, + { backgroundJobManager }, deviceInfo, accountManager, resources, @@ -131,9 +122,7 @@ class BackgroundJobFactoryTest { notificationManager, eventBus, deckApi, - themeColorUtils, - themeSnackbarUtils, - themeButtonUtils + { viewThemeUtils } ) } diff --git a/app/src/test/java/com/nextcloud/client/preferences/TestAppPreferences.java b/app/src/test/java/com/nextcloud/client/preferences/TestAppPreferences.java index 56f356861e..b13d3bf4dc 100644 --- a/app/src/test/java/com/nextcloud/client/preferences/TestAppPreferences.java +++ b/app/src/test/java/com/nextcloud/client/preferences/TestAppPreferences.java @@ -3,7 +3,7 @@ package com.nextcloud.client.preferences; import android.content.Context; import android.content.SharedPreferences; -import com.nextcloud.client.account.CurrentAccountProvider; +import com.nextcloud.client.account.UserAccountManager; import org.junit.Before; import org.junit.Test; @@ -128,7 +128,7 @@ public class TestAppPreferences { private SharedPreferences.Editor editor; @Mock - private CurrentAccountProvider accountProvider; + private UserAccountManager userAccountManager; private AppPreferencesImpl appPreferences; @@ -137,7 +137,7 @@ public class TestAppPreferences { MockitoAnnotations.initMocks(this); when(editor.remove(anyString())).thenReturn(editor); when(sharedPreferences.edit()).thenReturn(editor); - appPreferences = new AppPreferencesImpl(testContext, sharedPreferences, accountProvider); + appPreferences = new AppPreferencesImpl(testContext, sharedPreferences, userAccountManager); } @Test diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt index ab66039494..dc114ae5e1 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/GalleryAdapterTest.kt @@ -30,8 +30,7 @@ import com.owncloud.android.datamodel.GalleryItems import com.owncloud.android.datamodel.OCFile import com.owncloud.android.ui.activity.ComponentsGetter import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface -import com.owncloud.android.utils.theme.ThemeColorUtils -import com.owncloud.android.utils.theme.ThemeDrawableUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import junit.framework.Assert.assertEquals import org.junit.After import org.junit.Before @@ -61,10 +60,7 @@ class GalleryAdapterTest { lateinit var storageManager: FileDataStorageManager @Mock - lateinit var themeColorUtils: ThemeColorUtils - - @Mock - lateinit var themeDrawableUtils: ThemeDrawableUtils + lateinit var viewThemeUtils: ViewThemeUtils private lateinit var mocks: AutoCloseable @@ -88,8 +84,7 @@ class GalleryAdapterTest { ocFileListFragmentInterface, preferences, transferServiceGetter, - themeColorUtils, - themeDrawableUtils + viewThemeUtils ) val list = listOf( diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/ShareeListAdapterTest.kt b/app/src/test/java/com/owncloud/android/ui/adapter/ShareeListAdapterTest.kt index dffd5e1169..cef8d08d4f 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/ShareeListAdapterTest.kt +++ b/app/src/test/java/com/owncloud/android/ui/adapter/ShareeListAdapterTest.kt @@ -27,8 +27,7 @@ import com.nextcloud.client.account.AnonymousUser import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.ui.activity.FileActivity -import com.owncloud.android.utils.theme.ThemeAvatarUtils -import com.owncloud.android.utils.theme.ThemeColorUtils +import com.owncloud.android.utils.theme.ViewThemeUtils import org.junit.Assert import org.junit.Test import org.mockito.Mock @@ -43,10 +42,7 @@ class ShareeListAdapterTest { private val fileActivity: FileActivity? = null @Mock - private lateinit var themeColorUtils: ThemeColorUtils - - @Mock - private lateinit var themeAvatarUtils: ThemeAvatarUtils + private lateinit var viewThemeUtils: ViewThemeUtils private val orderedShares = listOf( OCShare("/1").apply { @@ -91,8 +87,7 @@ class ShareeListAdapterTest { null, user.accountName, user, - themeColorUtils, - themeAvatarUtils + viewThemeUtils ) sut.sortShares() diff --git a/app/src/test/java/com/owncloud/android/ui/adapter/UserListAdapterTest.java b/app/src/test/java/com/owncloud/android/ui/adapter/UserListAdapterTest.java index 79546d1a2c..bef7121988 100644 --- a/app/src/test/java/com/owncloud/android/ui/adapter/UserListAdapterTest.java +++ b/app/src/test/java/com/owncloud/android/ui/adapter/UserListAdapterTest.java @@ -22,8 +22,7 @@ package com.owncloud.android.ui.adapter; import com.owncloud.android.R; import com.owncloud.android.ui.activity.ManageAccountsActivity; -import com.owncloud.android.utils.theme.ThemeColorUtils; -import com.owncloud.android.utils.theme.ThemeDrawableUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import org.junit.Before; import org.junit.Test; @@ -46,10 +45,7 @@ public class UserListAdapterTest { private ManageAccountsActivity manageAccountsActivity; @Mock - private ThemeColorUtils themeColorUtils; - - @Mock - private ThemeDrawableUtils themeDrawableUtils; + private ViewThemeUtils viewThemeUtils; /** * Setting up and mocking the manageAccountsActivity class, and then mocking the method calls in the construction of @@ -73,8 +69,8 @@ public class UserListAdapterTest { null, true, true, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); assertEquals(0, userListAdapter.getItemCount()); } @@ -93,8 +89,8 @@ public class UserListAdapterTest { null, true, true, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); assertEquals(2, userListAdapter.getItemCount()); } @@ -115,8 +111,8 @@ public class UserListAdapterTest { null, true, true, - themeColorUtils, - themeDrawableUtils); + true, + viewThemeUtils); UserListItem userListItem1 = new UserListItem(); UserListItem userListItem2 = new UserListItem(); diff --git a/drawable_resources/dashboard.svg b/drawable_resources/dashboard.svg new file mode 100644 index 0000000000..655c57ba3d --- /dev/null +++ b/drawable_resources/dashboard.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index bf24c5db3f..4bc2fbc3bd 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 85 warnings + Lint Report: 84 warnings diff --git a/settings.gradle b/settings.gradle index 40b70bd250..bb095760cc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,9 @@ rootProject.name = 'Nextcloud' include ':app' + +//includeBuild('../android-common') { +// dependencySubstitution { +// substitute module('com.github.nextcloud.android-common:ui') using project(':ui') +// } +//} diff --git a/spotbugs-filter.xml b/spotbugs-filter.xml index 0f19982980..b250271fc8 100644 --- a/spotbugs-filter.xml +++ b/spotbugs-filter.xml @@ -23,7 +23,10 @@ - + + + +