diff --git a/.idea/copyright/IONOS_HiDrive_Next.xml b/.idea/copyright/IONOS_HiDrive_Next.xml new file mode 100644 index 000000000000..d313733e68e6 --- /dev/null +++ b/.idea/copyright/IONOS_HiDrive_Next.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml index bc106e52608a..2e31899f7ffd 100644 --- a/.idea/copyright/profiles_settings.xml +++ b/.idea/copyright/profiles_settings.xml @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 2e1f6f9ec897..e8125fd2a2aa 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,8 @@ buildscript { classpath "org.jacoco:org.jacoco.core:$jacoco_version" classpath "org.jacoco:org.jacoco.report:$jacoco_version" classpath "org.jacoco:org.jacoco.agent:$jacoco_version" + classpath 'com.google.gms:google-services:4.4.2' + classpath "com.google.firebase:firebase-crashlytics-gradle:3.0.2" } } @@ -43,6 +45,7 @@ apply plugin: 'pmd' apply from: "$rootProject.projectDir/jacoco.gradle" apply plugin: 'com.github.spotbugs' apply plugin: 'io.gitlab.arturbosch.detekt' +apply plugin: 'com.google.firebase.crashlytics' // needed to make renovate run without shot, as shot requires Android SDK // https://github.com/pedrovgs/Shot/issues/300 @@ -51,6 +54,9 @@ if (shotTest) { } apply plugin: 'com.google.devtools.ksp' +if (getGradle().getStartParameter().getTaskRequests().toString().contains("Gplay")){ + apply plugin: 'com.google.gms.google-services' +} println "Gradle uses Java ${Jvm.current()}" @@ -163,8 +169,11 @@ android { } gplay { - applicationId 'com.nextcloud.client' + applicationId "com.ionos.hidrivenext" dimension "default" + versionCode 3 + isDefault = true + resConfigs "en", "de", "es", "fr", "nl" } huawei { @@ -322,6 +331,7 @@ dependencies { gplayImplementation project(':appscan') huaweiImplementation project(':appscan') qaImplementation project(':appscan') + implementation project(':scanbot') spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0' spotbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.6.9' @@ -370,6 +380,9 @@ dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14' } + implementation reactivex_rxjava2 + implementation reactivex_rxandroid2 + // dependencies for local unit tests testImplementation 'junit:junit:4.13.2' testImplementation "org.mockito:mockito-core:$mockitoVersion" @@ -430,6 +443,10 @@ dependencies { // splash screen dependency ref: https://developer.android.com/develop/ui/views/launch/splash-screen/migrate implementation 'androidx.core:core-splashscreen:1.0.1' + + implementation(platform("com.google.firebase:firebase-bom:33.7.0")) + implementation "com.google.firebase:firebase-analytics" + implementation "com.google.firebase:firebase-crashlytics" } configurations.configureEach { diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 34de04e2556d..5fee8a23bbf0 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -15,7 +15,7 @@ @@ -30,13 +30,13 @@ + tools:node="remove" /> + tools:node="remove" /> + tools:node="remove" /> * SPDX-FileCopyrightText: 2023 Nextcloud GmbH - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: AGPL-3.0-or-later */ package com.nextcloud.client.di +import com.ionos.scanbot.availability.Availability +import com.ionos.scanbot.di.qualifiers.Scanbot +import com.ionos.scanbot.di.qualifiers.ScanbotLicense import com.nextcloud.appscan.ScanPageContract import com.nextcloud.client.documentscan.AppScanOptionalFeature import dagger.Module @@ -17,9 +21,13 @@ import dagger.Reusable internal class VariantModule { @Provides @Reusable - fun scanOptionalFeature(): AppScanOptionalFeature { + fun scanOptionalFeature( + @Scanbot featureAvailability: Availability, + @ScanbotLicense licenseAvailability: Availability + ): AppScanOptionalFeature { return object : AppScanOptionalFeature() { override fun getScanContract() = ScanPageContract() + override val isAvailable: Boolean = featureAvailability.available() && licenseAvailability.available() } } } diff --git a/app/src/gplay/release/google-services.json b/app/src/gplay/release/google-services.json new file mode 100644 index 000000000000..99f046dd7692 --- /dev/null +++ b/app/src/gplay/release/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "", + "project_id": "", + "storage_bucket": "" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "", + "android_client_info": { + "package_name": "com.ionos.hidrivenext" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/gplay/res/animator/progress_bar_login_indeterminate.xml b/app/src/gplay/res/animator/progress_bar_login_indeterminate.xml new file mode 100644 index 000000000000..fd660c547af9 --- /dev/null +++ b/app/src/gplay/res/animator/progress_bar_login_indeterminate.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/gplay/res/color-night/drawer_item_shape_color.xml b/app/src/gplay/res/color-night/drawer_item_shape_color.xml new file mode 100644 index 000000000000..a4d31dfa8a72 --- /dev/null +++ b/app/src/gplay/res/color-night/drawer_item_shape_color.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/color/drawer_item_shape_color.xml b/app/src/gplay/res/color/drawer_item_shape_color.xml new file mode 100644 index 000000000000..a4d31dfa8a72 --- /dev/null +++ b/app/src/gplay/res/color/drawer_item_shape_color.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/color/filled_button_bg_color.xml b/app/src/gplay/res/color/filled_button_bg_color.xml new file mode 100644 index 000000000000..518c975d874c --- /dev/null +++ b/app/src/gplay/res/color/filled_button_bg_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/color/filled_button_text_color.xml b/app/src/gplay/res/color/filled_button_text_color.xml new file mode 100644 index 000000000000..6eef0fe45d18 --- /dev/null +++ b/app/src/gplay/res/color/filled_button_text_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/color/outlined_button_bg_color.xml b/app/src/gplay/res/color/outlined_button_bg_color.xml new file mode 100644 index 000000000000..3f66ee2be899 --- /dev/null +++ b/app/src/gplay/res/color/outlined_button_bg_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/color/outlined_button_stroke_color.xml b/app/src/gplay/res/color/outlined_button_stroke_color.xml new file mode 100644 index 000000000000..0c25161bc46c --- /dev/null +++ b/app/src/gplay/res/color/outlined_button_stroke_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/color/outlined_button_text_color.xml b/app/src/gplay/res/color/outlined_button_text_color.xml new file mode 100644 index 000000000000..2140ebe47a18 --- /dev/null +++ b/app/src/gplay/res/color/outlined_button_text_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/color/text_button_text_color.xml b/app/src/gplay/res/color/text_button_text_color.xml new file mode 100644 index 000000000000..c40c98ad77f3 --- /dev/null +++ b/app/src/gplay/res/color/text_button_text_color.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable-night/favorite.xml b/app/src/gplay/res/drawable-night/favorite.xml new file mode 100644 index 000000000000..f2728f1758d5 --- /dev/null +++ b/app/src/gplay/res/drawable-night/favorite.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/app/src/gplay/res/drawable-night/nextcloud_logo.xml b/app/src/gplay/res/drawable-night/nextcloud_logo.xml new file mode 100644 index 000000000000..939c59c3e3a2 --- /dev/null +++ b/app/src/gplay/res/drawable-night/nextcloud_logo.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable-night/shared_via_link.xml b/app/src/gplay/res/drawable-night/shared_via_link.xml new file mode 100644 index 000000000000..f4ef3c4ff1cc --- /dev/null +++ b/app/src/gplay/res/drawable-night/shared_via_link.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/app/src/gplay/res/drawable-night/shared_via_users.xml b/app/src/gplay/res/drawable-night/shared_via_users.xml new file mode 100644 index 000000000000..e0389e0ee4b3 --- /dev/null +++ b/app/src/gplay/res/drawable-night/shared_via_users.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/account_circle_white.xml b/app/src/gplay/res/drawable/account_circle_white.xml new file mode 100644 index 000000000000..e8ea2101d106 --- /dev/null +++ b/app/src/gplay/res/drawable/account_circle_white.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/all_files.xml b/app/src/gplay/res/drawable/all_files.xml new file mode 100644 index 000000000000..9efb2dcd0327 --- /dev/null +++ b/app/src/gplay/res/drawable/all_files.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/bottom_sheet_drag_handle.xml b/app/src/gplay/res/drawable/bottom_sheet_drag_handle.xml new file mode 100644 index 000000000000..e060526252b1 --- /dev/null +++ b/app/src/gplay/res/drawable/bottom_sheet_drag_handle.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/src/gplay/res/drawable/dialog_background.xml b/app/src/gplay/res/drawable/dialog_background.xml new file mode 100644 index 000000000000..6f14d4c3f227 --- /dev/null +++ b/app/src/gplay/res/drawable/dialog_background.xml @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/dialog_item_background.xml b/app/src/gplay/res/drawable/dialog_item_background.xml new file mode 100644 index 000000000000..cbcdd3ff5263 --- /dev/null +++ b/app/src/gplay/res/drawable/dialog_item_background.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/e2e_border.xml b/app/src/gplay/res/drawable/e2e_border.xml new file mode 100644 index 000000000000..a545c168e793 --- /dev/null +++ b/app/src/gplay/res/drawable/e2e_border.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/exo_divider.xml b/app/src/gplay/res/drawable/exo_divider.xml new file mode 100644 index 000000000000..205032f4f73d --- /dev/null +++ b/app/src/gplay/res/drawable/exo_divider.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_ic_check.xml b/app/src/gplay/res/drawable/exo_ic_check.xml new file mode 100644 index 000000000000..d045c84f5db5 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_ic_check.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_audiotrack.xml b/app/src/gplay/res/drawable/exo_styled_controls_audiotrack.xml new file mode 100644 index 000000000000..fd50f84d0482 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_audiotrack.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_pause.xml b/app/src/gplay/res/drawable/exo_styled_controls_pause.xml new file mode 100644 index 000000000000..c45c39df05da --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_pause.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_play.xml b/app/src/gplay/res/drawable/exo_styled_controls_play.xml new file mode 100644 index 000000000000..1956ab230365 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_play.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_settings.xml b/app/src/gplay/res/drawable/exo_styled_controls_settings.xml new file mode 100644 index 000000000000..d0a127203c85 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_settings.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_simple_fastforward.xml b/app/src/gplay/res/drawable/exo_styled_controls_simple_fastforward.xml new file mode 100644 index 000000000000..11002787d609 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_simple_fastforward.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_simple_rewind.xml b/app/src/gplay/res/drawable/exo_styled_controls_simple_rewind.xml new file mode 100644 index 000000000000..c7d2782ea707 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_simple_rewind.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_styled_controls_speed.xml b/app/src/gplay/res/drawable/exo_styled_controls_speed.xml new file mode 100644 index 000000000000..e10f5e2223e9 --- /dev/null +++ b/app/src/gplay/res/drawable/exo_styled_controls_speed.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/exo_thumb.xml b/app/src/gplay/res/drawable/exo_thumb.xml new file mode 100644 index 000000000000..d31859726d0a --- /dev/null +++ b/app/src/gplay/res/drawable/exo_thumb.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/favorite.xml b/app/src/gplay/res/drawable/favorite.xml new file mode 100644 index 000000000000..44a725f11469 --- /dev/null +++ b/app/src/gplay/res/drawable/favorite.xml @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/app/src/gplay/res/drawable/file.xml b/app/src/gplay/res/drawable/file.xml new file mode 100644 index 000000000000..bb46adbe85de --- /dev/null +++ b/app/src/gplay/res/drawable/file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/file_calendar.xml b/app/src/gplay/res/drawable/file_calendar.xml new file mode 100644 index 000000000000..d8b720a581e1 --- /dev/null +++ b/app/src/gplay/res/drawable/file_calendar.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/file_details_search_background.xml b/app/src/gplay/res/drawable/file_details_search_background.xml new file mode 100644 index 000000000000..3fa292870817 --- /dev/null +++ b/app/src/gplay/res/drawable/file_details_search_background.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/file_image.xml b/app/src/gplay/res/drawable/file_image.xml new file mode 100644 index 000000000000..aaee3cf2eba8 --- /dev/null +++ b/app/src/gplay/res/drawable/file_image.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/file_multiple.xml b/app/src/gplay/res/drawable/file_multiple.xml new file mode 100644 index 000000000000..942c9373d4bc --- /dev/null +++ b/app/src/gplay/res/drawable/file_multiple.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/filelist_action_icon_background.xml b/app/src/gplay/res/drawable/filelist_action_icon_background.xml new file mode 100644 index 000000000000..ad4d33647d47 --- /dev/null +++ b/app/src/gplay/res/drawable/filelist_action_icon_background.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/folder.xml b/app/src/gplay/res/drawable/folder.xml new file mode 100644 index 000000000000..8b4fc8a42890 --- /dev/null +++ b/app/src/gplay/res/drawable/folder.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/folder_star_32dp.xml b/app/src/gplay/res/drawable/folder_star_32dp.xml new file mode 100644 index 000000000000..8b4fc8a42890 --- /dev/null +++ b/app/src/gplay/res/drawable/folder_star_32dp.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/grid_mode_item_background.xml b/app/src/gplay/res/drawable/grid_mode_item_background.xml new file mode 100644 index 000000000000..c3bb6301c093 --- /dev/null +++ b/app/src/gplay/res/drawable/grid_mode_item_background.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/grid_mode_item_outline.xml b/app/src/gplay/res/drawable/grid_mode_item_outline.xml new file mode 100644 index 000000000000..670be17089d1 --- /dev/null +++ b/app/src/gplay/res/drawable/grid_mode_item_outline.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/grid_mode_more_button_background.xml b/app/src/gplay/res/drawable/grid_mode_more_button_background.xml new file mode 100644 index 000000000000..3dd44347922f --- /dev/null +++ b/app/src/gplay/res/drawable/grid_mode_more_button_background.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/grid_mode_selected_item_background.xml b/app/src/gplay/res/drawable/grid_mode_selected_item_background.xml new file mode 100644 index 000000000000..756aa8df241b --- /dev/null +++ b/app/src/gplay/res/drawable/grid_mode_selected_item_background.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_action_create_dir.xml b/app/src/gplay/res/drawable/ic_action_create_dir.xml new file mode 100644 index 000000000000..2141f7c78e49 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_action_create_dir.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_action_upload.xml b/app/src/gplay/res/drawable/ic_action_upload.xml new file mode 100644 index 000000000000..c8a9e0631b0b --- /dev/null +++ b/app/src/gplay/res/drawable/ic_action_upload.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_activity.xml b/app/src/gplay/res/drawable/ic_activity.xml new file mode 100644 index 000000000000..2cf83e115e53 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_activity.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_alphabetical_asc.xml b/app/src/gplay/res/drawable/ic_alphabetical_asc.xml new file mode 100644 index 000000000000..39545cafc5fc --- /dev/null +++ b/app/src/gplay/res/drawable/ic_alphabetical_asc.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_alphabetical_desc.xml b/app/src/gplay/res/drawable/ic_alphabetical_desc.xml new file mode 100644 index 000000000000..f6c98c61d5f6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_alphabetical_desc.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_arrow_back.xml b/app/src/gplay/res/drawable/ic_arrow_back.xml new file mode 100644 index 000000000000..114ef8a5760e --- /dev/null +++ b/app/src/gplay/res/drawable/ic_arrow_back.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_assistant.xml b/app/src/gplay/res/drawable/ic_assistant.xml new file mode 100644 index 000000000000..314febca6a85 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_assistant.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_camera.xml b/app/src/gplay/res/drawable/ic_camera.xml new file mode 100644 index 000000000000..eaaaecd77eb6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_camera.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_checkbox_blank_outline.xml b/app/src/gplay/res/drawable/ic_checkbox_blank_outline.xml new file mode 100644 index 000000000000..acbdc3c8bb72 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_checkbox_blank_outline.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_checkbox_marked.xml b/app/src/gplay/res/drawable/ic_checkbox_marked.xml new file mode 100644 index 000000000000..d249debaeaab --- /dev/null +++ b/app/src/gplay/res/drawable/ic_checkbox_marked.xml @@ -0,0 +1,27 @@ + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_close_search.xml b/app/src/gplay/res/drawable/ic_close_search.xml new file mode 100644 index 000000000000..f5be8d6d699d --- /dev/null +++ b/app/src/gplay/res/drawable/ic_close_search.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_cloud.xml b/app/src/gplay/res/drawable/ic_cloud.xml new file mode 100644 index 000000000000..1fadad4368de --- /dev/null +++ b/app/src/gplay/res/drawable/ic_cloud.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_cloud_download.xml b/app/src/gplay/res/drawable/ic_cloud_download.xml new file mode 100644 index 000000000000..37592e253cd6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_cloud_download.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_cloud_sync_off.xml b/app/src/gplay/res/drawable/ic_cloud_sync_off.xml new file mode 100644 index 000000000000..4da7ffbdf252 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_cloud_sync_off.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_cloud_sync_on.xml b/app/src/gplay/res/drawable/ic_cloud_sync_on.xml new file mode 100644 index 000000000000..5677bff01515 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_cloud_sync_on.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_cloud_upload.xml b/app/src/gplay/res/drawable/ic_cloud_upload.xml new file mode 100644 index 000000000000..c4bc7f3dd6ba --- /dev/null +++ b/app/src/gplay/res/drawable/ic_cloud_upload.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_contact_book.xml b/app/src/gplay/res/drawable/ic_contact_book.xml new file mode 100644 index 000000000000..587b00881832 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_contact_book.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_content_copy.xml b/app/src/gplay/res/drawable/ic_content_copy.xml new file mode 100644 index 000000000000..3cfc1e42d971 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_content_copy.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_delete.xml b/app/src/gplay/res/drawable/ic_delete.xml new file mode 100644 index 000000000000..8a0b2f618a58 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_delete.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_dots_vertical.xml b/app/src/gplay/res/drawable/ic_dots_vertical.xml new file mode 100644 index 000000000000..e572128d3612 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_dots_vertical.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_edit.xml b/app/src/gplay/res/drawable/ic_edit.xml new file mode 100644 index 000000000000..b70c7eae487c --- /dev/null +++ b/app/src/gplay/res/drawable/ic_edit.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_email.xml b/app/src/gplay/res/drawable/ic_email.xml new file mode 100644 index 000000000000..5c1a5a36f8da --- /dev/null +++ b/app/src/gplay/res/drawable/ic_email.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_cancel_sync.xml b/app/src/gplay/res/drawable/ic_file_action_cancel_sync.xml new file mode 100644 index 000000000000..0a9173c21d08 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_cancel_sync.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_download_file.xml b/app/src/gplay/res/drawable/ic_file_action_download_file.xml new file mode 100644 index 000000000000..9f5e50a293db --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_download_file.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_edit.xml b/app/src/gplay/res/drawable/ic_file_action_edit.xml new file mode 100644 index 000000000000..43233ac3db1d --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_edit.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_export_file.xml b/app/src/gplay/res/drawable/ic_file_action_export_file.xml new file mode 100644 index 000000000000..d331d6fb1b57 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_export_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_favorite.xml b/app/src/gplay/res/drawable/ic_file_action_favorite.xml new file mode 100644 index 000000000000..f03c59e85bf1 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_favorite.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_lock_file.xml b/app/src/gplay/res/drawable/ic_file_action_lock_file.xml new file mode 100644 index 000000000000..f83bf38fd62d --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_lock_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_move_or_copy.xml b/app/src/gplay/res/drawable/ic_file_action_move_or_copy.xml new file mode 100644 index 000000000000..1d9b33e52e55 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_move_or_copy.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_open_file_with.xml b/app/src/gplay/res/drawable/ic_file_action_open_file_with.xml new file mode 100644 index 000000000000..ebd25250a8ec --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_open_file_with.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_pin_to_homescreen.xml b/app/src/gplay/res/drawable/ic_file_action_pin_to_homescreen.xml new file mode 100644 index 000000000000..12bad2c11102 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_pin_to_homescreen.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_remove_file.xml b/app/src/gplay/res/drawable/ic_file_action_remove_file.xml new file mode 100644 index 000000000000..8a0b2f618a58 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_remove_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_rename_file.xml b/app/src/gplay/res/drawable/ic_file_action_rename_file.xml new file mode 100644 index 000000000000..e2a4df854a82 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_rename_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_see_details.xml b/app/src/gplay/res/drawable/ic_file_action_see_details.xml new file mode 100644 index 000000000000..62f45aa6f038 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_see_details.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_select_all.xml b/app/src/gplay/res/drawable/ic_file_action_select_all.xml new file mode 100644 index 000000000000..a286b9168a6e --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_select_all.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_select_none.xml b/app/src/gplay/res/drawable/ic_file_action_select_none.xml new file mode 100644 index 000000000000..929269719e69 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_select_none.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_set_as_wallpaper.xml b/app/src/gplay/res/drawable/ic_file_action_set_as_wallpaper.xml new file mode 100644 index 000000000000..fdaa13d8c77d --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_set_as_wallpaper.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_set_encrypted.xml b/app/src/gplay/res/drawable/ic_file_action_set_encrypted.xml new file mode 100644 index 000000000000..ca99659b4629 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_set_encrypted.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_share_file.xml b/app/src/gplay/res/drawable/ic_file_action_share_file.xml new file mode 100644 index 000000000000..a0e14edfa8b2 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_share_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_stream_media.xml b/app/src/gplay/res/drawable/ic_file_action_stream_media.xml new file mode 100644 index 000000000000..9e4d0662e523 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_stream_media.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_sync_file.xml b/app/src/gplay/res/drawable/ic_file_action_sync_file.xml new file mode 100644 index 000000000000..297aa442036f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_sync_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_unlock_file.xml b/app/src/gplay/res/drawable/ic_file_action_unlock_file.xml new file mode 100644 index 000000000000..d4724ca67180 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_unlock_file.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_unset_encrypted.xml b/app/src/gplay/res/drawable/ic_file_action_unset_encrypted.xml new file mode 100644 index 000000000000..20a8f656fd71 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_unset_encrypted.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_file_action_unset_favorite.xml b/app/src/gplay/res/drawable/ic_file_action_unset_favorite.xml new file mode 100644 index 000000000000..f38d5c4ea3da --- /dev/null +++ b/app/src/gplay/res/drawable/ic_file_action_unset_favorite.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_account_group.xml b/app/src/gplay/res/drawable/ic_folder_overlay_account_group.xml new file mode 100644 index 000000000000..05e232d6895f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_account_group.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_external.xml b/app/src/gplay/res/drawable/ic_folder_overlay_external.xml new file mode 100644 index 000000000000..7eb67c1c67cb --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_external.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_key.xml b/app/src/gplay/res/drawable/ic_folder_overlay_key.xml new file mode 100644 index 000000000000..181769358a26 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_key.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_link.xml b/app/src/gplay/res/drawable/ic_folder_overlay_link.xml new file mode 100644 index 000000000000..05e232d6895f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_link.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_lock.xml b/app/src/gplay/res/drawable/ic_folder_overlay_lock.xml new file mode 100644 index 000000000000..db30297451b6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_lock.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_share.xml b/app/src/gplay/res/drawable/ic_folder_overlay_share.xml new file mode 100644 index 000000000000..05e232d6895f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_share.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_folder_overlay_upload.xml b/app/src/gplay/res/drawable/ic_folder_overlay_upload.xml new file mode 100644 index 000000000000..afe3192f83aa --- /dev/null +++ b/app/src/gplay/res/drawable/ic_folder_overlay_upload.xml @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_gallery_set_media_folder.xml b/app/src/gplay/res/drawable/ic_gallery_set_media_folder.xml new file mode 100644 index 000000000000..fdaa13d8c77d --- /dev/null +++ b/app/src/gplay/res/drawable/ic_gallery_set_media_folder.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_gallery_show_photos.xml b/app/src/gplay/res/drawable/ic_gallery_show_photos.xml new file mode 100644 index 000000000000..eaaaecd77eb6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_gallery_show_photos.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_gallery_show_videos.xml b/app/src/gplay/res/drawable/ic_gallery_show_videos.xml new file mode 100644 index 000000000000..a8ea6b923ae0 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_gallery_show_videos.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_gallery_tick.xml b/app/src/gplay/res/drawable/ic_gallery_tick.xml new file mode 100644 index 000000000000..05a9c15ca270 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_gallery_tick.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_grid_mode_more.xml b/app/src/gplay/res/drawable/ic_grid_mode_more.xml new file mode 100644 index 000000000000..9d9291500985 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_grid_mode_more.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_history.xml b/app/src/gplay/res/drawable/ic_history.xml new file mode 100644 index 000000000000..82b62c934363 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_history.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_import.xml b/app/src/gplay/res/drawable/ic_import.xml new file mode 100644 index 000000000000..b7523313a2c1 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_import.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_launcher_foreground.xml b/app/src/gplay/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000000..7d75ec0175be --- /dev/null +++ b/app/src/gplay/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_link.xml b/app/src/gplay/res/drawable/ic_link.xml new file mode 100644 index 000000000000..b1666422bcc6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_link.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_list_empty_create_folder.xml b/app/src/gplay/res/drawable/ic_list_empty_create_folder.xml new file mode 100644 index 000000000000..2af06159b73c --- /dev/null +++ b/app/src/gplay/res/drawable/ic_list_empty_create_folder.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_list_empty_error.xml b/app/src/gplay/res/drawable/ic_list_empty_error.xml new file mode 100644 index 000000000000..4b64a4e49553 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_list_empty_error.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_list_empty_folder.xml b/app/src/gplay/res/drawable/ic_list_empty_folder.xml new file mode 100644 index 000000000000..bbeb3f1d05ee --- /dev/null +++ b/app/src/gplay/res/drawable/ic_list_empty_folder.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_list_empty_recent.xml b/app/src/gplay/res/drawable/ic_list_empty_recent.xml new file mode 100644 index 000000000000..676879e62d6e --- /dev/null +++ b/app/src/gplay/res/drawable/ic_list_empty_recent.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_list_empty_shared.xml b/app/src/gplay/res/drawable/ic_list_empty_shared.xml new file mode 100644 index 000000000000..5cf82c43f9f6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_list_empty_shared.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_menu.xml b/app/src/gplay/res/drawable/ic_menu.xml new file mode 100644 index 000000000000..d3ae8c8b3080 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_menu.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_modification_asc.xml b/app/src/gplay/res/drawable/ic_modification_asc.xml new file mode 100644 index 000000000000..19f367facb48 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_modification_asc.xml @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_modification_desc.xml b/app/src/gplay/res/drawable/ic_modification_desc.xml new file mode 100644 index 000000000000..58c619363535 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_modification_desc.xml @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_pause.xml b/app/src/gplay/res/drawable/ic_pause.xml new file mode 100644 index 000000000000..af11ea628327 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_pause.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/drawable/ic_play.xml b/app/src/gplay/res/drawable/ic_play.xml new file mode 100644 index 000000000000..d151770705cf --- /dev/null +++ b/app/src/gplay/res/drawable/ic_play.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/drawable/ic_plus.xml b/app/src/gplay/res/drawable/ic_plus.xml new file mode 100644 index 000000000000..1990e792ad8f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_plus.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_progress_bar_login_indeterminate.xml b/app/src/gplay/res/drawable/ic_progress_bar_login_indeterminate.xml new file mode 100644 index 000000000000..0a5a500b19f7 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_progress_bar_login_indeterminate.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/gplay/res/drawable/ic_scan_document.xml b/app/src/gplay/res/drawable/ic_scan_document.xml new file mode 100644 index 000000000000..8799c9510fbb --- /dev/null +++ b/app/src/gplay/res/drawable/ic_scan_document.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_search.xml b/app/src/gplay/res/drawable/ic_search.xml new file mode 100644 index 000000000000..f6d35d2f2bcc --- /dev/null +++ b/app/src/gplay/res/drawable/ic_search.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_search_grey.xml b/app/src/gplay/res/drawable/ic_search_grey.xml new file mode 100644 index 000000000000..87e41fad695a --- /dev/null +++ b/app/src/gplay/res/drawable/ic_search_grey.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_select_all.xml b/app/src/gplay/res/drawable/ic_select_all.xml new file mode 100644 index 000000000000..50db787d70ae --- /dev/null +++ b/app/src/gplay/res/drawable/ic_select_all.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_share.xml b/app/src/gplay/res/drawable/ic_share.xml new file mode 100644 index 000000000000..5cf82c43f9f6 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_share.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_share_settings.xml b/app/src/gplay/res/drawable/ic_share_settings.xml new file mode 100644 index 000000000000..91a6d5e62bbd --- /dev/null +++ b/app/src/gplay/res/drawable/ic_share_settings.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_size_asc.xml b/app/src/gplay/res/drawable/ic_size_asc.xml new file mode 100644 index 000000000000..08e0b390792f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_size_asc.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_size_desc.xml b/app/src/gplay/res/drawable/ic_size_desc.xml new file mode 100644 index 000000000000..d0ffd2c9d99e --- /dev/null +++ b/app/src/gplay/res/drawable/ic_size_desc.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_synced.xml b/app/src/gplay/res/drawable/ic_synced.xml new file mode 100644 index 000000000000..31b565901f3b --- /dev/null +++ b/app/src/gplay/res/drawable/ic_synced.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/ic_tick.xml b/app/src/gplay/res/drawable/ic_tick.xml new file mode 100644 index 000000000000..f4716e25109c --- /dev/null +++ b/app/src/gplay/res/drawable/ic_tick.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_unshare.xml b/app/src/gplay/res/drawable/ic_unshare.xml new file mode 100644 index 000000000000..0fa90363eb4a --- /dev/null +++ b/app/src/gplay/res/drawable/ic_unshare.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_unshared.xml b/app/src/gplay/res/drawable/ic_unshared.xml new file mode 100644 index 000000000000..e11da31a265e --- /dev/null +++ b/app/src/gplay/res/drawable/ic_unshared.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_user.xml b/app/src/gplay/res/drawable/ic_user.xml new file mode 100644 index 000000000000..6517166eeba1 --- /dev/null +++ b/app/src/gplay/res/drawable/ic_user.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_view_list.xml b/app/src/gplay/res/drawable/ic_view_list.xml new file mode 100644 index 000000000000..3a287644bd8f --- /dev/null +++ b/app/src/gplay/res/drawable/ic_view_list.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ic_view_module.xml b/app/src/gplay/res/drawable/ic_view_module.xml new file mode 100644 index 000000000000..8e96d7dfb9bb --- /dev/null +++ b/app/src/gplay/res/drawable/ic_view_module.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/image_32dp.xml b/app/src/gplay/res/drawable/image_32dp.xml new file mode 100644 index 000000000000..13a7fb43c0f2 --- /dev/null +++ b/app/src/gplay/res/drawable/image_32dp.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/ionos_logo.xml b/app/src/gplay/res/drawable/ionos_logo.xml new file mode 100644 index 000000000000..9f971f82dba3 --- /dev/null +++ b/app/src/gplay/res/drawable/ionos_logo.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/logo.xml b/app/src/gplay/res/drawable/logo.xml new file mode 100644 index 000000000000..9f971f82dba3 --- /dev/null +++ b/app/src/gplay/res/drawable/logo.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/nav_favorites.xml b/app/src/gplay/res/drawable/nav_favorites.xml new file mode 100644 index 000000000000..f03c59e85bf1 --- /dev/null +++ b/app/src/gplay/res/drawable/nav_favorites.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nav_notifications.xml b/app/src/gplay/res/drawable/nav_notifications.xml new file mode 100644 index 000000000000..f8c12d5af7dc --- /dev/null +++ b/app/src/gplay/res/drawable/nav_notifications.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/gplay/res/drawable/nav_on_device.xml b/app/src/gplay/res/drawable/nav_on_device.xml new file mode 100644 index 000000000000..902842d03802 --- /dev/null +++ b/app/src/gplay/res/drawable/nav_on_device.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nav_photos.xml b/app/src/gplay/res/drawable/nav_photos.xml new file mode 100644 index 000000000000..fdaa13d8c77d --- /dev/null +++ b/app/src/gplay/res/drawable/nav_photos.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nav_settings.xml b/app/src/gplay/res/drawable/nav_settings.xml new file mode 100644 index 000000000000..dfa36583d70f --- /dev/null +++ b/app/src/gplay/res/drawable/nav_settings.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nav_shared.xml b/app/src/gplay/res/drawable/nav_shared.xml new file mode 100644 index 000000000000..d136bc23398e --- /dev/null +++ b/app/src/gplay/res/drawable/nav_shared.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nav_trashbin.xml b/app/src/gplay/res/drawable/nav_trashbin.xml new file mode 100644 index 000000000000..75e40f031021 --- /dev/null +++ b/app/src/gplay/res/drawable/nav_trashbin.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/nextcloud_logo.xml b/app/src/gplay/res/drawable/nextcloud_logo.xml new file mode 100644 index 000000000000..41f4c5d33874 --- /dev/null +++ b/app/src/gplay/res/drawable/nextcloud_logo.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/notification_icon.xml b/app/src/gplay/res/drawable/notification_icon.xml new file mode 100644 index 000000000000..6c1ccab18953 --- /dev/null +++ b/app/src/gplay/res/drawable/notification_icon.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/app/src/gplay/res/drawable/notifications_icon.xml b/app/src/gplay/res/drawable/notifications_icon.xml new file mode 100644 index 000000000000..7fbc42b42e90 --- /dev/null +++ b/app/src/gplay/res/drawable/notifications_icon.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/progress_bar_login_indeterminate.xml b/app/src/gplay/res/drawable/progress_bar_login_indeterminate.xml new file mode 100644 index 000000000000..01762da59db2 --- /dev/null +++ b/app/src/gplay/res/drawable/progress_bar_login_indeterminate.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/shared_via_link.xml b/app/src/gplay/res/drawable/shared_via_link.xml new file mode 100644 index 000000000000..f4ef3c4ff1cc --- /dev/null +++ b/app/src/gplay/res/drawable/shared_via_link.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/app/src/gplay/res/drawable/shared_via_users.xml b/app/src/gplay/res/drawable/shared_via_users.xml new file mode 100644 index 000000000000..e0389e0ee4b3 --- /dev/null +++ b/app/src/gplay/res/drawable/shared_via_users.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/app/src/gplay/res/drawable/uploads.xml b/app/src/gplay/res/drawable/uploads.xml new file mode 100644 index 000000000000..c26710c81044 --- /dev/null +++ b/app/src/gplay/res/drawable/uploads.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/drawable/video_32dp.xml b/app/src/gplay/res/drawable/video_32dp.xml new file mode 100644 index 000000000000..3fb34ed2c2f1 --- /dev/null +++ b/app/src/gplay/res/drawable/video_32dp.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/gplay/res/layout/account_setup.xml b/app/src/gplay/res/layout/account_setup.xml new file mode 100644 index 000000000000..b4bcbe1aad04 --- /dev/null +++ b/app/src/gplay/res/layout/account_setup.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/account_setup_webview.xml b/app/src/gplay/res/layout/account_setup_webview.xml new file mode 100644 index 000000000000..cf50f7403935 --- /dev/null +++ b/app/src/gplay/res/layout/account_setup_webview.xml @@ -0,0 +1,32 @@ + + + + + + + + + diff --git a/app/src/gplay/res/layout/activity_preview_media.xml b/app/src/gplay/res/layout/activity_preview_media.xml new file mode 100644 index 000000000000..ad88c96e744c --- /dev/null +++ b/app/src/gplay/res/layout/activity_preview_media.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/activity_splash.xml b/app/src/gplay/res/layout/activity_splash.xml new file mode 100644 index 000000000000..a26af2ef1c45 --- /dev/null +++ b/app/src/gplay/res/layout/activity_splash.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/backup_fragment.xml b/app/src/gplay/res/layout/backup_fragment.xml new file mode 100644 index 000000000000..40db4e6c3385 --- /dev/null +++ b/app/src/gplay/res/layout/backup_fragment.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/deep_link_login.xml b/app/src/gplay/res/layout/deep_link_login.xml new file mode 100644 index 000000000000..1dbf1c43d6fa --- /dev/null +++ b/app/src/gplay/res/layout/deep_link_login.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/drawer.xml b/app/src/gplay/res/layout/drawer.xml new file mode 100644 index 000000000000..c739841894f0 --- /dev/null +++ b/app/src/gplay/res/layout/drawer.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/empty_list_media.xml b/app/src/gplay/res/layout/empty_list_media.xml new file mode 100644 index 000000000000..9c6e8c95fc45 --- /dev/null +++ b/app/src/gplay/res/layout/empty_list_media.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/exo_player_control_view.xml b/app/src/gplay/res/layout/exo_player_control_view.xml new file mode 100644 index 000000000000..3f457f3a5563 --- /dev/null +++ b/app/src/gplay/res/layout/exo_player_control_view.xml @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/exo_player_view.xml b/app/src/gplay/res/layout/exo_player_view.xml new file mode 100644 index 000000000000..930b014b1d30 --- /dev/null +++ b/app/src/gplay/res/layout/exo_player_view.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_actions_bottom_sheet.xml b/app/src/gplay/res/layout/file_actions_bottom_sheet.xml new file mode 100644 index 000000000000..c3e243d8225e --- /dev/null +++ b/app/src/gplay/res/layout/file_actions_bottom_sheet.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_actions_bottom_sheet_item.xml b/app/src/gplay/res/layout/file_actions_bottom_sheet_item.xml new file mode 100644 index 000000000000..290f012e9ce0 --- /dev/null +++ b/app/src/gplay/res/layout/file_actions_bottom_sheet_item.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_details_fragment.xml b/app/src/gplay/res/layout/file_details_fragment.xml new file mode 100644 index 000000000000..ed791047783e --- /dev/null +++ b/app/src/gplay/res/layout/file_details_fragment.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_details_share_link_share_item.xml b/app/src/gplay/res/layout/file_details_share_link_share_item.xml new file mode 100644 index 000000000000..d307f152bc15 --- /dev/null +++ b/app/src/gplay/res/layout/file_details_share_link_share_item.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_details_sharing_fragment.xml b/app/src/gplay/res/layout/file_details_sharing_fragment.xml new file mode 100644 index 000000000000..4f01fdafa858 --- /dev/null +++ b/app/src/gplay/res/layout/file_details_sharing_fragment.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml b/app/src/gplay/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml new file mode 100644 index 000000000000..b49d76853225 --- /dev/null +++ b/app/src/gplay/res/layout/file_details_sharing_menu_bottom_sheet_fragment.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/fragment_gallery_bottom_sheet.xml b/app/src/gplay/res/layout/fragment_gallery_bottom_sheet.xml new file mode 100644 index 000000000000..139a9a827c6b --- /dev/null +++ b/app/src/gplay/res/layout/fragment_gallery_bottom_sheet.xml @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/grid_item.xml b/app/src/gplay/res/layout/grid_item.xml new file mode 100644 index 000000000000..1d0db0e0aab1 --- /dev/null +++ b/app/src/gplay/res/layout/grid_item.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/info_box.xml b/app/src/gplay/res/layout/info_box.xml new file mode 100644 index 000000000000..40d99656dd68 --- /dev/null +++ b/app/src/gplay/res/layout/info_box.xml @@ -0,0 +1,36 @@ + + + + + + + diff --git a/app/src/gplay/res/layout/item_quick_share_permissions.xml b/app/src/gplay/res/layout/item_quick_share_permissions.xml new file mode 100644 index 000000000000..410088009941 --- /dev/null +++ b/app/src/gplay/res/layout/item_quick_share_permissions.xml @@ -0,0 +1,44 @@ + + + + + + + + + diff --git a/app/src/gplay/res/layout/list_item.xml b/app/src/gplay/res/layout/list_item.xml new file mode 100644 index 000000000000..d4e17e6c8811 --- /dev/null +++ b/app/src/gplay/res/layout/list_item.xml @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/login_flow_info_layout_v2.xml b/app/src/gplay/res/layout/login_flow_info_layout_v2.xml new file mode 100644 index 000000000000..3227876ee40e --- /dev/null +++ b/app/src/gplay/res/layout/login_flow_info_layout_v2.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/media_control.xml b/app/src/gplay/res/layout/media_control.xml new file mode 100644 index 000000000000..2b13b15d87b3 --- /dev/null +++ b/app/src/gplay/res/layout/media_control.xml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/quick_sharing_permissions_bottom_sheet_fragment.xml b/app/src/gplay/res/layout/quick_sharing_permissions_bottom_sheet_fragment.xml new file mode 100644 index 000000000000..ae1fd24ba225 --- /dev/null +++ b/app/src/gplay/res/layout/quick_sharing_permissions_bottom_sheet_fragment.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/gplay/res/layout/settings_preference_first_group.xml b/app/src/gplay/res/layout/settings_preference_first_group.xml new file mode 100644 index 000000000000..f207114a078e --- /dev/null +++ b/app/src/gplay/res/layout/settings_preference_first_group.xml @@ -0,0 +1,26 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/settings_preference_group.xml b/app/src/gplay/res/layout/settings_preference_group.xml new file mode 100644 index 000000000000..56d0dd055f0e --- /dev/null +++ b/app/src/gplay/res/layout/settings_preference_group.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/settings_preference_list_item.xml b/app/src/gplay/res/layout/settings_preference_list_item.xml new file mode 100644 index 000000000000..5fddbb9bf057 --- /dev/null +++ b/app/src/gplay/res/layout/settings_preference_list_item.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/app/src/gplay/res/layout/settings_preference_switcher.xml b/app/src/gplay/res/layout/settings_preference_switcher.xml new file mode 100644 index 000000000000..81b7886dd1fd --- /dev/null +++ b/app/src/gplay/res/layout/settings_preference_switcher.xml @@ -0,0 +1,53 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/settings_privacy_switchers.xml b/app/src/gplay/res/layout/settings_privacy_switchers.xml new file mode 100644 index 000000000000..297c6bfceefc --- /dev/null +++ b/app/src/gplay/res/layout/settings_privacy_switchers.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml b/app/src/gplay/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml new file mode 100644 index 000000000000..197853d4bc9e --- /dev/null +++ b/app/src/gplay/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/simple_spinner_item.xml b/app/src/gplay/res/layout/simple_spinner_item.xml new file mode 100644 index 000000000000..4b6e91765dd6 --- /dev/null +++ b/app/src/gplay/res/layout/simple_spinner_item.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/gplay/res/layout/sorting_order_fragment.xml b/app/src/gplay/res/layout/sorting_order_fragment.xml new file mode 100644 index 000000000000..ad8ff4cd8e72 --- /dev/null +++ b/app/src/gplay/res/layout/sorting_order_fragment.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/synced_folders_item_header.xml b/app/src/gplay/res/layout/synced_folders_item_header.xml new file mode 100644 index 000000000000..14d99248b903 --- /dev/null +++ b/app/src/gplay/res/layout/synced_folders_item_header.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/toolbar_standard.xml b/app/src/gplay/res/layout/toolbar_standard.xml new file mode 100644 index 000000000000..914580a1d79c --- /dev/null +++ b/app/src/gplay/res/layout/toolbar_standard.xml @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/layout/view_authorization_method.xml b/app/src/gplay/res/layout/view_authorization_method.xml new file mode 100644 index 000000000000..85d8ec412ce3 --- /dev/null +++ b/app/src/gplay/res/layout/view_authorization_method.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/layout/view_login_background.xml b/app/src/gplay/res/layout/view_login_background.xml new file mode 100644 index 000000000000..80064d2ab3c1 --- /dev/null +++ b/app/src/gplay/res/layout/view_login_background.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/menu/partial_drawer_entries.xml b/app/src/gplay/res/menu/partial_drawer_entries.xml new file mode 100644 index 000000000000..9e9afddc62ce --- /dev/null +++ b/app/src/gplay/res/menu/partial_drawer_entries.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000000..a1f8fa17e3c4 --- /dev/null +++ b/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000000..448b38f276ae --- /dev/null +++ b/app/src/gplay/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/gplay/res/mipmap-hdpi/ic_launcher.webp b/app/src/gplay/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000000..063c51d877a2 Binary files /dev/null and b/app/src/gplay/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/gplay/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/gplay/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000000..da712edf87b0 Binary files /dev/null and b/app/src/gplay/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/gplay/res/mipmap-mdpi/ic_launcher.webp b/app/src/gplay/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000000..3fe3cbdfb17d Binary files /dev/null and b/app/src/gplay/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/gplay/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/gplay/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000000..eefd99007825 Binary files /dev/null and b/app/src/gplay/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/gplay/res/mipmap-xhdpi/ic_launcher.webp b/app/src/gplay/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000000..7f731095ee14 Binary files /dev/null and b/app/src/gplay/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/gplay/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/gplay/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000000..d3dc506789c7 Binary files /dev/null and b/app/src/gplay/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/gplay/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/gplay/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000000..4972ec7f3318 Binary files /dev/null and b/app/src/gplay/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/gplay/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/gplay/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000000..885d2b49ac23 Binary files /dev/null and b/app/src/gplay/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000000..2648a2d213db Binary files /dev/null and b/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000000..c8a15cadff46 Binary files /dev/null and b/app/src/gplay/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/gplay/res/values-de/setup.xml b/app/src/gplay/res/values-de/setup.xml new file mode 100644 index 000000000000..c7ef8f525d85 --- /dev/null +++ b/app/src/gplay/res/values-de/setup.xml @@ -0,0 +1,13 @@ + + + + + + https://wl.hidrive.com/easy/0142 + https://wl.hidrive.com/easy/0092 + diff --git a/app/src/gplay/res/values-de/string.xml b/app/src/gplay/res/values-de/string.xml new file mode 100644 index 000000000000..903098581320 --- /dev/null +++ b/app/src/gplay/res/values-de/string.xml @@ -0,0 +1,24 @@ + + + + + + + Willkommen beim Cloud-Speicher + Login + Sie müssen sich über den Browser einloggen + Abbrechen + Wiederholen + + + Filtern + + + Verwendeter Speicher + + \ No newline at end of file diff --git a/app/src/gplay/res/values-es/setup.xml b/app/src/gplay/res/values-es/setup.xml new file mode 100644 index 000000000000..6b47802d9ef2 --- /dev/null +++ b/app/src/gplay/res/values-es/setup.xml @@ -0,0 +1,13 @@ + + + + + + https://wl.hidrive.com/easy/0152 + https://wl.hidrive.com/easy/0112 + diff --git a/app/src/gplay/res/values-es/string.xml b/app/src/gplay/res/values-es/string.xml new file mode 100644 index 000000000000..5c436328ec11 --- /dev/null +++ b/app/src/gplay/res/values-es/string.xml @@ -0,0 +1,24 @@ + + + + + + + Bienvenido/a al almacenamiento en la nube + Iniciar sesión + Tienes que iniciar sesión en el navegador. + Cancelar + Volver a intentar + + + Filtro + + + Memoria utilizada + + \ No newline at end of file diff --git a/app/src/gplay/res/values-fr/setup.xml b/app/src/gplay/res/values-fr/setup.xml new file mode 100644 index 000000000000..e33dc6854637 --- /dev/null +++ b/app/src/gplay/res/values-fr/setup.xml @@ -0,0 +1,13 @@ + + + + + + https://wl.hidrive.com/easy/0122 + https://wl.hidrive.com/easy/0082 + diff --git a/app/src/gplay/res/values-fr/string.xml b/app/src/gplay/res/values-fr/string.xml new file mode 100644 index 000000000000..48196d5ae24b --- /dev/null +++ b/app/src/gplay/res/values-fr/string.xml @@ -0,0 +1,24 @@ + + + + + + + Bienvenue sur votre cloud + Connexion + Un navigateur s\'ouvre pour le login + Annuler + Répéter + + + Filtre + + + Stockage occupé + + \ No newline at end of file diff --git a/app/src/gplay/res/values-land/dimen.xml b/app/src/gplay/res/values-land/dimen.xml new file mode 100644 index 000000000000..62bf3d0ab28b --- /dev/null +++ b/app/src/gplay/res/values-land/dimen.xml @@ -0,0 +1,15 @@ + + + + + + 0.05 + 0.4 + 0.65 + + \ No newline at end of file diff --git a/app/src/gplay/res/values-large/dimen.xml b/app/src/gplay/res/values-large/dimen.xml new file mode 100644 index 000000000000..687b1eedea7e --- /dev/null +++ b/app/src/gplay/res/values-large/dimen.xml @@ -0,0 +1,24 @@ + + + + + + + 36dp + 48dp + 36dp + 12dp + 48dp + 12dp + 12dp + 48dp + 8dp + 16sp + 14sp + + \ No newline at end of file diff --git a/app/src/gplay/res/values-large/dims.xml b/app/src/gplay/res/values-large/dims.xml new file mode 100644 index 000000000000..bcdabf5ee21a --- /dev/null +++ b/app/src/gplay/res/values-large/dims.xml @@ -0,0 +1,15 @@ + + + + + 16dp + 56dp + 72dp + 8dp + 80dp + diff --git a/app/src/gplay/res/values-night/colors.xml b/app/src/gplay/res/values-night/colors.xml new file mode 100644 index 000000000000..0fe29f4f1467 --- /dev/null +++ b/app/src/gplay/res/values-night/colors.xml @@ -0,0 +1,131 @@ + + + + + @color/ionos_default_text_color + @color/metallic_silver + @color/midnight_blue2 + @color/ionos_toolbar_color + @color/navy + @color/navy + @color/ionos_default_icon_color + + @color/navy + + @color/dark_slate_grey + @color/dark_slate_grey + @color/dark_slate_grey + @color/deep_koamaru + @color/jungle_mist + + @color/midnight_blue2 + @color/ghost_white + @color/ghost_white + @color/geyser + @color/curious_blue + @color/orange + + @color/dodger_blue + @color/royal_blue + @color/dark_slate_grey + + @color/white + @color/white + @color/dusk + + @color/transparent + @color/ghost_white + @color/transparent + @color/ghost_white + @color/ghost_white + @color/dusk + @color/ghost_white + @color/madison + @color/dusk + @color/curious_blue + @color/cornflower + @color/dusk + + @color/transparent_ghost_white + + @color/slate_grey + + @color/curious_blue + @color/curious_blue + @color/curious_blue + + @color/dark_slate_grey + @color/white_smoke + @color/white_smoke + + @color/ghost_white + @color/navy + @color/royal_blue + + @color/deep_koamaru + @color/metallic_silver + + @color/midnight_blue2 + @color/dusk + + @color/midnight_blue2 + @color/curious_blue + @color/dodger_blue + @color/gull_grayapprox + + @color/curious_blue + @color/curious_blue + @color/midnight_blue2 + @color/curious_blue + @color/geyser + @color/metallic_silver + @color/dusk + + @color/curious_blue + @color/royal_blue + @color/white + @color/curious_blue + @color/geyser + @color/dusk + @color/curious_blue + + @color/ionos_default_text_color + + @color/bg_default + @color/bg_default + @color/transparent + @color/appbar + + @color/ghost_white + @color/curious_blue + @color/slate_grey + @color/slate_grey + @color/ghost_white + @color/dodger_blue + + @color/navy + @color/curious_blue + + + @color/white_smoke + @color/dusk + @color/dusk + + @color/curious_blue + @color/white + + @color/dodger_blue + + @color/curious_blue + @color/white + + @color/ghost_white + @color/ghost_white + @color/gull_grayapprox + @color/ghost_white + diff --git a/app/src/gplay/res/values-nl/string.xml b/app/src/gplay/res/values-nl/string.xml new file mode 100644 index 000000000000..c2ba63152289 --- /dev/null +++ b/app/src/gplay/res/values-nl/string.xml @@ -0,0 +1,24 @@ + + + + + + + Welkom bij je cloud storage + Login + Je moet inloggen via je browser + Annuleren + Opnieuw proberen + + + Filteren + + + Opslag in gebruik + + \ No newline at end of file diff --git a/app/src/gplay/res/values-v27/styles.xml b/app/src/gplay/res/values-v27/styles.xml new file mode 100644 index 000000000000..436a33c63d75 --- /dev/null +++ b/app/src/gplay/res/values-v27/styles.xml @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/app/src/gplay/res/values/colors.xml b/app/src/gplay/res/values/colors.xml new file mode 100644 index 000000000000..1b6de3edc210 --- /dev/null +++ b/app/src/gplay/res/values/colors.xml @@ -0,0 +1,144 @@ + + + + + @color/ionos_default_text_color + @color/dusk + @color/white + @color/ionos_toolbar_color + @color/ghost_white + @color/white_smoke + @color/ionos_default_icon_color + + @color/bg_default + @color/bg_default + + @color/ghost_white + + @color/ionos_navigation_bar_background + @color/navigation_bar_background_color + @color/ghost_white + @color/lavender_mist + @color/white + + @color/ionos_navigation_bar_background + @color/ghost_white + @color/navy + @color/navy + @color/dusk + @color/dodger_blue + @color/chocolate + + @color/madison + @color/dodger_blue + @color/gull_grayapprox + + @color/white + @color/white + @color/geyser + + @color/transparent + @color/navy + @color/transparent + @color/madison + @color/navy + @color/gull_grayapprox + @color/madison + @color/white + @color/gull_grayapprox + @color/dodger_blue + @color/royal_blue + @color/gull_grayapprox + + @color/lavender_mist + + @color/slate_grey + + @color/geyser + @color/geyser + @color/metallic_silver + @color/white + @color/dodger_blue + @color/dodger_blue + + @color/bg_default + + @color/bg_default + @color/text_color + @color/text_color + @color/geyser + @color/dodger_blue + + @color/ghost_white + @color/dusk + @color/dusk + + @color/midnight_blue2 + @color/ghost_white + @color/cornflower + + @color/geyser + @color/navy + + @color/white + @color/dusk + + @color/white + @color/dodger_blue + @color/royal_blue + @color/gull_grayapprox + + @color/dodger_blue + @color/dodger_blue + @color/ghost_white + @color/dodger_blue + @color/navy + @color/dusk + @color/lavender_mist + + @color/white + @color/lavender_mist + @color/dodger_blue + @color/dodger_blue + @color/geyser + @color/geyser + @color/dodger_blue + + @color/ionos_default_text_color + + @color/navy + @color/dodger_blue + @color/slate_grey + @color/slate_grey + @color/navy + @color/lavender_mist + + @color/lavender_mist + @color/dodger_blue + + + @color/ghost_white + @color/dusk + @color/dusk + + + @color/ghost_white + + @color/dodger_blue + @color/white + + @color/dodger_blue + @color/white + + @color/semitransparent_black + + @color/deep_koamaru + @color/dusk + @color/marble_blue + @color/dusk + diff --git a/app/src/gplay/res/values/dimen.xml b/app/src/gplay/res/values/dimen.xml new file mode 100644 index 000000000000..d994cff22f1c --- /dev/null +++ b/app/src/gplay/res/values/dimen.xml @@ -0,0 +1,42 @@ + + + + + + + 0.2 + 0.4 + 0.8 + + + 8dp + 16dp + 24dp + 8dp + 16dp + 8dp + 8dp + 16dp + 8dp + 16sp + 14sp + + + 40dp + 44dp + 52dp + 32dp + 96dp + 22dp + 6dp + 24dp + 24dp + + + + \ No newline at end of file diff --git a/app/src/gplay/res/values/dims.xml b/app/src/gplay/res/values/dims.xml new file mode 100644 index 000000000000..fb6ebed93916 --- /dev/null +++ b/app/src/gplay/res/values/dims.xml @@ -0,0 +1,53 @@ + + + + + 8dp + 56dp + 32dp + 4dp + 80dp + + 16sp + 12sp + 24sp + + 24dp + 24dp + 24dp + 48dp + 12dp + 12dp + 16dp + 16dp + 12dp + + 24dp + 12dp + 12dp + 8dp + 12dp + 12dp + + 12dp + + 16dp + + 32dp + 4dp + 5dp + + 1dp + 8dp + 14sp + 16dp + + 1000000dp + + 1 + diff --git a/app/src/gplay/res/values/ic_launcher_background.xml b/app/src/gplay/res/values/ic_launcher_background.xml new file mode 100644 index 000000000000..28feb1972667 --- /dev/null +++ b/app/src/gplay/res/values/ic_launcher_background.xml @@ -0,0 +1,11 @@ + + + + + #003D8F + \ No newline at end of file diff --git a/app/src/gplay/res/values/setup.xml b/app/src/gplay/res/values/setup.xml index 83fadc4e35d1..07d26ef17174 100644 --- a/app/src/gplay/res/values/setup.xml +++ b/app/src/gplay/res/values/setup.xml @@ -17,6 +17,48 @@ AIzaSyAWIyOcLafaFp8PFL61h64cy1NNZW2cU_s nextcloud-a7dea.appspot.com nextcloud-a7dea + + + IONOS HiDrive Next + com.ionos.hidrivenext + com.ionos.hidrivenext.provider + com.ionos.hidrivenext.providers.UsersAndGroupsSearchProvider + com.ionos.hidrivenext.providers.UsersAndGroupsSearchProvider.action.SHARE_WITH + com.ionos.hidrivenext.documents + com.ionos.hidrivenext.files + com.ionos.hidrivenext.providers.imageCache + ionos.db + ionos + ionos + IONOS HiDrive Next + Mozilla/5.0 (Android) IONOS HiDrive Next/%1$s%2$s + false + + + https://storage.ionos.fr/login/v2 + + + false + + + true + false + false + + + false + true + true + true + true + true + true + https://wl.hidrive.com/easy/0132 + https://wl.hidrive.com/easy/0192 + + https://wl.hidrive.com/easy/0102 + https://wl.hidrive.com/easy/0162 + https://wl.hidrive.com/easy/0182 diff --git a/app/src/gplay/res/values/string.xml b/app/src/gplay/res/values/string.xml new file mode 100644 index 000000000000..c5655b2d2a4b --- /dev/null +++ b/app/src/gplay/res/values/string.xml @@ -0,0 +1,24 @@ + + + + + + + Welcome to the cloud storage + Log In + You need to login over browser + Cancel + Retry + + + Filter + + + Storage used + + \ No newline at end of file diff --git a/app/src/gplay/res/values/styles.xml b/app/src/gplay/res/values/styles.xml new file mode 100644 index 000000000000..63ba1e967f10 --- /dev/null +++ b/app/src/gplay/res/values/styles.xml @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/gplay/res/xml/preferences.xml b/app/src/gplay/res/xml/preferences.xml new file mode 100644 index 000000000000..16006980e441 --- /dev/null +++ b/app/src/gplay/res/xml/preferences.xml @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 73493014a302..6fa6305f4df1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,7 +7,8 @@ ~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only --> + xmlns:tools="http://schemas.android.com/tools" + xmlns:app="http://schemas.android.com/apk/res-auto"> @@ -130,6 +131,11 @@ + + @@ -283,6 +289,7 @@ android:exported="false" /> @@ -351,13 +358,19 @@ + android:theme="@style/Theme.ownCloud.PreviewImage" /> + + + + + ' where other options is not applicable +* */ +annotation class IonosCustomization(val value: String = "") \ No newline at end of file diff --git a/app/src/main/java/com/ionos/authorization_method/AuthorizationMethodActivity.kt b/app/src/main/java/com/ionos/authorization_method/AuthorizationMethodActivity.kt new file mode 100644 index 000000000000..732965836922 --- /dev/null +++ b/app/src/main/java/com/ionos/authorization_method/AuthorizationMethodActivity.kt @@ -0,0 +1,43 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.authorization_method + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import com.owncloud.android.authentication.AuthenticatorActivity +import com.owncloud.android.databinding.ViewAuthorizationMethodBinding + +class AuthorizationMethodActivity : AppCompatActivity() { + + companion object { + @JvmStatic + fun createInstance(context: Context) = Intent(context, AuthorizationMethodActivity::class.java) + } + + private val viewBinding by lazy { ViewAuthorizationMethodBinding.inflate(layoutInflater) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(viewBinding.root) + + initListeners() + } + + private fun initListeners() { + viewBinding.bLogin.setOnClickListener { login() } + } + + private fun login() { + val intent = Intent(this, AuthenticatorActivity::class.java).apply { + putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, true) + } + startActivity(intent); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/di/StratoModule.kt b/app/src/main/java/com/ionos/di/StratoModule.kt new file mode 100644 index 000000000000..92def864016f --- /dev/null +++ b/app/src/main/java/com/ionos/di/StratoModule.kt @@ -0,0 +1,30 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.di + +import com.ionos.analycis.AnalyticsManager +import com.ionos.privacy.DataProtectionActivity +import com.ionos.analycis.FirebaseAnalyticsManager +import com.ionos.privacy.PrivacySettingsActivity +import com.ionos.scanbot.di.NCScanbotModule +import dagger.Binds +import dagger.Module +import dagger.android.ContributesAndroidInjector + +@Module(includes = [NCScanbotModule::class]) +abstract class StratoModule { + + @ContributesAndroidInjector + abstract fun dataProtectionActivity(): DataProtectionActivity + + @ContributesAndroidInjector + abstract fun privacySettingsActivity(): PrivacySettingsActivity + + @Binds + abstract fun analyticsManager(firebaseAnalyticsManager: FirebaseAnalyticsManager): AnalyticsManager +} diff --git a/app/src/main/java/com/ionos/privacy/DataProtectionActivity.kt b/app/src/main/java/com/ionos/privacy/DataProtectionActivity.kt new file mode 100644 index 000000000000..91181ff42e69 --- /dev/null +++ b/app/src/main/java/com/ionos/privacy/DataProtectionActivity.kt @@ -0,0 +1,148 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.privacy + +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.text.method.LinkMovementMethod +import androidx.activity.SystemBarStyle +import androidx.activity.addCallback +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.ContextCompat +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import com.ionos.utils.context.isDarkMode +import com.ionos.utils.text.convertAnnotatedTextToLinks +import com.nextcloud.utils.extensions.getParcelableArgument +import com.owncloud.android.R +import com.owncloud.android.databinding.ActivityDataProtectionBinding +import com.owncloud.android.ui.activity.BaseActivity +import com.owncloud.android.ui.activity.ExternalSiteWebView +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +class DataProtectionActivity : BaseActivity() { + + @Inject + lateinit var viewModelFactory: DataProtectionViewModel.Factory + + private val viewModel by viewModels { viewModelFactory } + + private val binding by lazy { ActivityDataProtectionBinding.inflate(layoutInflater) } + + private val detailPageOnBackPressedCallback by lazy { + onBackPressedDispatcher.addCallback(this) { viewModel.onDetailPageBackButtonClick() } + } + + override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge(SystemBarStyle.dark(Color.TRANSPARENT), SystemBarStyle.dark(Color.TRANSPARENT)) + super.onCreate(savedInstanceState) + setContentView(binding.root) + + val descriptionText = getText(R.string.ionos_data_protection_description).convertAnnotatedTextToLinks( + linkColor = ContextCompat.getColor(this, R.color.curious_blue), + linkUnderline = false, + linkHandler = ::handleLink, + ) + + binding.overviewPage.descriptionTextView.text = descriptionText + binding.overviewPage.descriptionTextView.movementMethod = LinkMovementMethod.getInstance() + + binding.overviewPage.agreeButton.setOnClickListener { viewModel.onAgreeButtonClick() } + binding.overviewPage.settingsButton.setOnClickListener { viewModel.onSettingsButtonClick() } + binding.detailPage.toolbar.setNavigationOnClickListener { viewModel.onDetailPageBackButtonClick() } + binding.detailPage.saveButton.setOnClickListener { viewModel.onSaveButtonClick() } + binding.detailPage.switchers.analyticsSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.onAnalyticsCheckedChange(isChecked) + } + + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets -> + val insetsType = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + val insets = windowInsets.getInsets(insetsType) + binding.overviewPage.root.setPadding(insets.left, insets.top, insets.right, insets.bottom) + binding.detailPage.root.setPadding(insets.left, insets.top, insets.right, insets.bottom) + WindowInsetsCompat.CONSUMED + } + + viewModel.stateFlow + .flowWithLifecycle(lifecycle) + .onEach(::updateState) + .launchIn(lifecycleScope) + } + + override fun isDefaultWindowInsetsHandlingEnabled() = false + + private fun handleLink(type: String) { + when (type) { + INFORMATION_LINK -> openPrivacyPolicyScreen() + REJECT_LINK -> viewModel.onRejectLinkClick() + else -> throw IllegalArgumentException("Unknown link type: $type") + } + } + + private fun openPrivacyPolicyScreen() { + val externalWebViewIntent = Intent(this, ExternalSiteWebView::class.java) + externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_TITLE, getString(R.string.privacy)) + externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_URL, getString(R.string.privacy_url)) + externalWebViewIntent.putExtra(ExternalSiteWebView.EXTRA_SHOW_SIDEBAR, false) + startActivity(externalWebViewIntent) + } + + private fun updateState(state: DataProtectionViewModel.State) { + if (binding.viewSwitcher.displayedChild != state.page.index) { + binding.viewSwitcher.displayedChild = state.page.index + } + if (state.page == DataProtectionViewModel.Page.OVERVIEW) { + delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_YES + setSystemBarsAppearance(false) + detailPageOnBackPressedCallback.isEnabled = false + } else { + delegate.localNightMode = AppCompatDelegate.MODE_NIGHT_UNSPECIFIED + setSystemBarsAppearance(!isDarkMode()) + detailPageOnBackPressedCallback.isEnabled = true + } + if (binding.detailPage.switchers.analyticsSwitch.isChecked != state.isAnalyticsEnabled) { + binding.detailPage.switchers.analyticsSwitch.isChecked = state.isAnalyticsEnabled + } + if (state.isProcessed) { + intent.getParcelableArgument(TARGET_SCREEN_INTENT_KEY, Intent::class.java)?.let(::startActivity) + finish() + } + } + + private fun setSystemBarsAppearance(isLight: Boolean) { + val controller = WindowInsetsControllerCompat(window, window.decorView) + controller.isAppearanceLightStatusBars = isLight + controller.isAppearanceLightNavigationBars = isLight + } + + companion object { + private const val TARGET_SCREEN_INTENT_KEY = "target_screen_intent" + private const val INFORMATION_LINK = "information_link" + private const val REJECT_LINK = "reject_link" + + @JvmStatic + fun createIntent(context: Context): Intent { + return Intent(context, DataProtectionActivity::class.java) + } + + @JvmStatic + fun createIntent(context: Context, targetScreenIntent: Intent): Intent { + return Intent(context, DataProtectionActivity::class.java) + .putExtra(TARGET_SCREEN_INTENT_KEY, targetScreenIntent) + } + } +} diff --git a/app/src/main/java/com/ionos/privacy/DataProtectionViewModel.kt b/app/src/main/java/com/ionos/privacy/DataProtectionViewModel.kt new file mode 100644 index 000000000000..281561bbd54a --- /dev/null +++ b/app/src/main/java/com/ionos/privacy/DataProtectionViewModel.kt @@ -0,0 +1,81 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.privacy + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.ionos.analycis.AnalyticsManager +import com.nextcloud.client.account.UserAccountManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject +import javax.inject.Provider + +class DataProtectionViewModel @Inject constructor( + private val analyticsManager: AnalyticsManager, + private val privacyPreferences: PrivacyPreferences, + private val userAccountManager: UserAccountManager, +) : ViewModel() { + + private var _stateFlow = MutableStateFlow(createInitialState()) + val stateFlow = _stateFlow.asStateFlow() + + fun onAgreeButtonClick() { + save(isAnalyticsEnabled = true) + } + + fun onRejectLinkClick() { + save(isAnalyticsEnabled = false) + } + + fun onSettingsButtonClick() { + _stateFlow.update { it.copy(page = Page.DETAIL) } + } + + fun onDetailPageBackButtonClick() { + _stateFlow.update { it.copy(page = Page.OVERVIEW) } + } + + fun onAnalyticsCheckedChange(isChecked: Boolean) { + _stateFlow.update { it.copy(isAnalyticsEnabled = isChecked) } + } + + fun onSaveButtonClick() { + save(stateFlow.value.isAnalyticsEnabled) + } + + private fun save(isAnalyticsEnabled: Boolean) { + analyticsManager.setEnabled(isAnalyticsEnabled) + privacyPreferences.setAnalyticsEnabled(isAnalyticsEnabled) + privacyPreferences.setDataProtectionProcessed(userAccountManager.currentOwnCloudAccount?.name) + _stateFlow.update { it.copy(isProcessed = true) } + } + + enum class Page(val index: Int) { + OVERVIEW(0), + DETAIL(1), + } + + private fun createInitialState(): State = State(isAnalyticsEnabled = privacyPreferences.isAnalyticsEnabled()) + + data class State( + val page: Page = Page.OVERVIEW, + val isAnalyticsEnabled: Boolean = false, + val isProcessed: Boolean = false, + ) + + class Factory @Inject constructor( + private val viewModelProvider: Provider, + ) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + return viewModelProvider.get() as T + } + } +} diff --git a/app/src/main/java/com/ionos/privacy/PrivacyPreferences.kt b/app/src/main/java/com/ionos/privacy/PrivacyPreferences.kt new file mode 100644 index 000000000000..1dc35f7c7567 --- /dev/null +++ b/app/src/main/java/com/ionos/privacy/PrivacyPreferences.kt @@ -0,0 +1,59 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.privacy + +import android.content.Context +import javax.inject.Inject + +class PrivacyPreferences @Inject constructor( + private val context: Context, +) { + private val sharedPreferences by lazy { context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE) } + + fun isDataProtectionProcessed(accountName: String?): Boolean = + getAccountsWithProcessedDataProtection().contains(accountName) + + fun setDataProtectionProcessed(accountName: String?) { + accountName?.let { + sharedPreferences + .edit() + .putStringSet(DATA_PROTECTION_PROCESSED_KEY, getAccountsWithProcessedDataProtection() + accountName) + .apply() + } + } + + fun removeDataProtectionProcessed(accountName: String) { + mutableSetOf(*getAccountsWithProcessedDataProtection().toTypedArray()) + .apply { remove(accountName) } + .let { accountsWithProcessedDataProtection -> + sharedPreferences + .edit() + .putStringSet(DATA_PROTECTION_PROCESSED_KEY, accountsWithProcessedDataProtection) + .apply() + } + } + + private fun getAccountsWithProcessedDataProtection(): Set = + sharedPreferences + .getStringSet(DATA_PROTECTION_PROCESSED_KEY, emptySet()) + ?: emptySet() + + fun isAnalyticsEnabled(): Boolean { + return sharedPreferences.getBoolean(ANALYTICS_ENABLED_KEY, false) + } + + fun setAnalyticsEnabled(value: Boolean) { + sharedPreferences.edit().putBoolean(ANALYTICS_ENABLED_KEY, value).apply() + } + + companion object { + private const val FILE_NAME = "privacy_preferences" + private const val DATA_PROTECTION_PROCESSED_KEY = "data_protection_processed" + private const val ANALYTICS_ENABLED_KEY = "analytics_enabled" + } +} diff --git a/app/src/main/java/com/ionos/privacy/PrivacySettingsActivity.kt b/app/src/main/java/com/ionos/privacy/PrivacySettingsActivity.kt new file mode 100644 index 000000000000..6c30c208ce8a --- /dev/null +++ b/app/src/main/java/com/ionos/privacy/PrivacySettingsActivity.kt @@ -0,0 +1,81 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.privacy + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.activity.viewModels +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import com.owncloud.android.databinding.ActivityPrivacySettingsBinding +import com.owncloud.android.ui.activity.BaseActivity +import com.owncloud.android.utils.theme.ViewThemeUtils +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +class PrivacySettingsActivity : BaseActivity() { + + @Inject + lateinit var viewModelFactory: PrivacySettingsViewModel.Factory + + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + + private val viewModel by viewModels { viewModelFactory } + + private val binding by lazy { ActivityPrivacySettingsBinding.inflate(layoutInflater) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(binding.root) + + viewThemeUtils.ionos.platform.themeSystemBars(this); + + binding.toolbar.setNavigationOnClickListener { onBackPressedDispatcher.onBackPressed() } + binding.switchers.analyticsSwitch.setOnCheckedChangeListener { _, isChecked -> + viewModel.onAnalyticsCheckedChange(isChecked) + } + + ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets -> + val insetsType = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + val insets = windowInsets.getInsets(insetsType) + binding.root.setPadding(insets.left, insets.top, insets.right, insets.bottom) + WindowInsetsCompat.CONSUMED + } + + viewModel.stateFlow + .flowWithLifecycle(lifecycle) + .onEach(::updateState) + .launchIn(lifecycleScope) + } + + override fun isDefaultWindowInsetsHandlingEnabled() = false + + override fun onStart() { + super.onStart() + viewModel.onStart() + } + + private fun updateState(state: PrivacySettingsViewModel.State) { + if (binding.switchers.analyticsSwitch.isChecked != state.isAnalyticsEnabled) { + binding.switchers.analyticsSwitch.isChecked = state.isAnalyticsEnabled + } + } + + companion object { + + @JvmStatic + fun createIntent(context: Context): Intent { + return Intent(context, PrivacySettingsActivity::class.java) + } + } +} diff --git a/app/src/main/java/com/ionos/privacy/PrivacySettingsViewModel.kt b/app/src/main/java/com/ionos/privacy/PrivacySettingsViewModel.kt new file mode 100644 index 000000000000..c2c5606bcaf0 --- /dev/null +++ b/app/src/main/java/com/ionos/privacy/PrivacySettingsViewModel.kt @@ -0,0 +1,50 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.privacy + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import com.ionos.analycis.AnalyticsManager +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject +import javax.inject.Provider + +class PrivacySettingsViewModel @Inject constructor( + private val analyticsManager: AnalyticsManager, + private val privacyPreferences: PrivacyPreferences, +) : ViewModel() { + + private var _stateFlow = MutableStateFlow(State()) + val stateFlow = _stateFlow.asStateFlow() + + fun onStart() { + val isAnalyticsEnabled = privacyPreferences.isAnalyticsEnabled() + _stateFlow.update { it.copy(isAnalyticsEnabled = isAnalyticsEnabled) } + } + + fun onAnalyticsCheckedChange(isChecked: Boolean) { + _stateFlow.update { it.copy(isAnalyticsEnabled = isChecked) } + analyticsManager.setEnabled(isChecked) + privacyPreferences.setAnalyticsEnabled(isChecked) + } + + data class State( + val isAnalyticsEnabled: Boolean = false, + ) + + class Factory @Inject constructor( + private val viewModelProvider: Provider, + ) : ViewModelProvider.Factory { + + override fun create(modelClass: Class): T { + return viewModelProvider.get() as T + } + } +} diff --git a/app/src/main/java/com/ionos/scanbot/di/NCScanbotModule.kt b/app/src/main/java/com/ionos/scanbot/di/NCScanbotModule.kt new file mode 100644 index 000000000000..9bd8d3cafe6d --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/di/NCScanbotModule.kt @@ -0,0 +1,46 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.di + +import com.ionos.scanbot.image_loader.ImageLoader +import com.ionos.scanbot.image_loading.ImageLoaderImpl +import com.ionos.scanbot.license.LoadScanbotLicense +import com.ionos.scanbot.license.LoadScanbotLicenseImpl +import com.ionos.scanbot.logger.ScanbotLogger +import com.ionos.scanbot.screens.save.SelectDirectoryContract +import com.ionos.scanbot.upload.ScanbotUploader +import com.ionos.scanbot.upload.SelectDirectoryContractImpl +import com.ionos.scanbot.upload.use_case.Uploader +import com.ionos.scanbot.util.GetLocalFreeSpace +import com.ionos.scanbot.util.logger.Logger +import com.ionos.scanbot.utils.GetLocalFreeSpaceImpl +import dagger.Binds +import dagger.Module + +@Module(includes = [ScanbotModule::class]) +abstract class NCScanbotModule { + + @Binds + abstract fun bindLoadLicense(loadScanbotLicense: LoadScanbotLicenseImpl): LoadScanbotLicense + + @Binds + abstract fun bindImageLoader(imageLoader: ImageLoaderImpl): ImageLoader + + @Binds + abstract fun bindUploader(uploader: ScanbotUploader): Uploader + + @Binds + abstract fun bindLogger(logger: ScanbotLogger): Logger + + @Binds + abstract fun bindSelectDirectoryContract(contract: SelectDirectoryContractImpl): SelectDirectoryContract + + @Binds + abstract fun bindGetLocalFreeSpaceImpl(getLocalFreeSpaceImpl: GetLocalFreeSpaceImpl): GetLocalFreeSpace + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/image_loading/ImageLoaderImpl.kt b/app/src/main/java/com/ionos/scanbot/image_loading/ImageLoaderImpl.kt new file mode 100644 index 000000000000..59a932a196b4 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/image_loading/ImageLoaderImpl.kt @@ -0,0 +1,22 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.image_loading + +import com.ionos.scanbot.image_loader.ImageLoader +import com.ionos.scanbot.image_loader.ImageRequestBuilder +import java.io.File +import javax.inject.Inject + +class ImageLoaderImpl @Inject constructor( +) : ImageLoader { + + override fun load(file: File): ImageRequestBuilder { + return ImageRequestBuilderImpl(file) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/image_loading/ImageRequestBuilderImpl.kt b/app/src/main/java/com/ionos/scanbot/image_loading/ImageRequestBuilderImpl.kt new file mode 100644 index 000000000000..26b345f12574 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/image_loading/ImageRequestBuilderImpl.kt @@ -0,0 +1,41 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.image_loading + +import android.widget.ImageView +import com.bumptech.glide.Glide +import com.ionos.scanbot.image_loader.ImageLoaderOptions +import com.ionos.scanbot.image_loader.ImageRequestBuilder +import com.ionos.scanbot.image_loader.ScaleType +import java.io.File + +class ImageRequestBuilderImpl( + private val file: File, +) : ImageRequestBuilder { + + private var options: ImageLoaderOptions? = null + + override fun options(options: ImageLoaderOptions): ImageRequestBuilder { + this.options = options + return this + } + + override fun into(target: ImageView) { + Glide.with(target.context) + .load(file) + .run { + when (options?.scaleType) { + ScaleType.CENTER_CROP -> centerCrop() + ScaleType.CENTER_INSIDE -> fitCenter() + else -> this + } + } + .signature(ObjectKey(file.lastModified())) + .into(target) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/image_loading/ObjectKey.java b/app/src/main/java/com/ionos/scanbot/image_loading/ObjectKey.java new file mode 100644 index 000000000000..de9b1fec7535 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/image_loading/ObjectKey.java @@ -0,0 +1,49 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.image_loading; + +import com.bumptech.glide.load.Key; + +import java.nio.charset.Charset; +import java.security.MessageDigest; + +import androidx.annotation.NonNull; + +public final class ObjectKey implements Key { + private static final Charset CHARSET = Charset.forName(STRING_CHARSET_NAME); + + private final Object object; + + public ObjectKey(@NonNull Object object) { + this.object = object; + } + + @Override + public String toString() { + return "ObjectKey{" + "object=" + object + '}'; + } + + @Override + public boolean equals(Object o) { + if (o instanceof ObjectKey) { + ObjectKey other = (ObjectKey) o; + return object.equals(other.object); + } + return false; + } + + @Override + public int hashCode() { + return object.hashCode(); + } + + @Override + public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { + messageDigest.update(object.toString().getBytes(CHARSET)); + } +} diff --git a/app/src/main/java/com/ionos/scanbot/license/DownloadLicenseRemoteOperation.kt b/app/src/main/java/com/ionos/scanbot/license/DownloadLicenseRemoteOperation.kt new file mode 100644 index 000000000000..3f7e8dc70476 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/license/DownloadLicenseRemoteOperation.kt @@ -0,0 +1,59 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.license + +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.operations.RemoteOperation +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import org.apache.commons.httpclient.methods.GetMethod + +class DownloadLicenseRemoteOperation( + private val licenseKeyUrl: String, +) : RemoteOperation() { + + var license: String? = null + private set + + override fun run(client: OwnCloudClient?): RemoteOperationResult { + return try { + if (client == null) throw IllegalArgumentException("Client should not be null") + + val getMethod = GetMethod(licenseKeyUrl) + + license = downloadFile(client, getMethod) + RemoteOperationResult(true, getMethod) + } catch (e: Exception) { + RemoteOperationResult(e) + } + } + + private fun downloadFile( + client: OwnCloudClient, + getMethod: GetMethod, + ): String? { + try { + val status = client.executeMethod(getMethod) + if (isSuccess(status)) { + val bytes = getMethod.responseBodyAsStream + .use { + it.readBytes() + } + + return LicenseResponseTransformer().transform(bytes) + } + } finally { + getMethod.releaseConnection() + } + + return null + } + + private fun isSuccess(status: Int): Boolean { + return status == 200 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/license/LicenseResponseTransformer.kt b/app/src/main/java/com/ionos/scanbot/license/LicenseResponseTransformer.kt new file mode 100644 index 000000000000..f262e46872bf --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/license/LicenseResponseTransformer.kt @@ -0,0 +1,43 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.license + +/** + * User: Dima Muravyov + * Date: 06.02.2020 + */ +internal class LicenseResponseTransformer { + + companion object { + private const val SEPARATOR = "\"" + private const val ESCAPED_NEW_LINE = "\\n" + private const val NEW_LINE = "\n" + } + + fun transform(bytes: ByteArray): String? { + val inlinedResponse = String(bytes) + + var scanbotLicenseKey = "" + var startIndex = inlinedResponse.indexOf(SEPARATOR) + while (startIndex != -1) { + val endIndex = inlinedResponse.indexOf(SEPARATOR, startIndex + 1) + if (endIndex == -1) { + scanbotLicenseKey = "" + break + } + + scanbotLicenseKey += inlinedResponse.substring(startIndex + 1, endIndex) + + startIndex = inlinedResponse.indexOf(SEPARATOR, endIndex + 1) + } + + scanbotLicenseKey = scanbotLicenseKey.replace(ESCAPED_NEW_LINE, NEW_LINE) + + return if (scanbotLicenseKey.isNotBlank()) scanbotLicenseKey else null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/license/LoadScanbotLicenseImpl.kt b/app/src/main/java/com/ionos/scanbot/license/LoadScanbotLicenseImpl.kt new file mode 100644 index 000000000000..f36783fe41c9 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/license/LoadScanbotLicenseImpl.kt @@ -0,0 +1,42 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.license + +import android.content.Context +import androidx.work.Constraints +import androidx.work.ExistingWorkPolicy +import androidx.work.NetworkType +import androidx.work.OneTimeWorkRequest +import androidx.work.OutOfQuotaPolicy +import androidx.work.WorkManager +import javax.inject.Inject + +class LoadScanbotLicenseImpl @Inject constructor( + context: Context, +) : LoadScanbotLicense { + + private val workManager by lazy { WorkManager.getInstance(context) } + + override fun invoke() { + val request = + OneTimeWorkRequest.Builder(ScanbotLicenseDownloadWorker::class.java) + .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .build() + + workManager.enqueueUniqueWork( + ScanbotLicenseDownloadWorker.SCANBOT_LICENSE_DOWNLOAD_WORKER, + ExistingWorkPolicy.KEEP, + request + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseDownloadWorker.kt b/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseDownloadWorker.kt new file mode 100644 index 000000000000..ca85c02f274c --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseDownloadWorker.kt @@ -0,0 +1,86 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.license + +import android.content.Context +import android.content.pm.ServiceInfo +import android.os.Build +import androidx.work.ForegroundInfo +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.ionos.scanbot.initializer.TryToInitScanbotSdk +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.jobs.download.DownloadNotificationManager +import com.owncloud.android.R +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import com.owncloud.android.utils.theme.ViewThemeUtils +import java.security.SecureRandom + +class ScanbotLicenseDownloadWorker( + licenseUrl: String, + viewThemeUtils: ViewThemeUtils, + private val accountManager: UserAccountManager, + private val licenseKeyStore: LicenseKeyStore, + private val tryToInitScanbotSdk: TryToInitScanbotSdk, + private val context: Context, + params: WorkerParameters, +): Worker(context, params){ + + companion object { + const val SCANBOT_LICENSE_DOWNLOAD_WORKER = "SCANBOT_LICENSE_DOWNLOAD_WORKER" + } + + private val operation = DownloadLicenseRemoteOperation(licenseUrl) + private var notificationManager = DownloadNotificationManager( + SecureRandom().nextInt(), + context, + viewThemeUtils + ) + + override fun doWork(): Result { + return try { + val ocAccount = accountManager.user.toOwnCloudAccount() + val downloadClient = + OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount, context) + + val result = operation.execute(downloadClient) + + if (result.isSuccess) { + operation.license?.let { + licenseKeyStore.saveLicenseKey(it) + tryToInitScanbotSdk(it) + } + Result.success() + } + else Result.retry() + }catch (e: Exception){ + Result.failure() + } + } + + override fun getForegroundInfo(): ForegroundInfo { + notificationManager.notificationBuilder.run { + setProgress(100, 0, true) + setContentTitle(context.getString(R.string.downloader_download_in_progress_ticker)) + } + + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){ + ForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + ) + } else{ + ForegroundInfo( + notificationManager.getId(), + notificationManager.getNotification(), + ) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseJobFactory.kt b/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseJobFactory.kt new file mode 100644 index 000000000000..b5ddc52b7892 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/license/ScanbotLicenseJobFactory.kt @@ -0,0 +1,39 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.license + +import android.content.Context +import androidx.work.WorkerParameters +import com.ionos.scanbot.di.qualifiers.ScanbotLicenseKeyUrl +import com.ionos.scanbot.initializer.TryToInitScanbotSdk +import com.nextcloud.client.account.UserAccountManager +import com.owncloud.android.utils.theme.ViewThemeUtils +import javax.inject.Inject +import javax.inject.Provider + +class ScanbotLicenseJobFactory @Inject constructor( + @ScanbotLicenseKeyUrl private val scanbotLicenseUrl: String, + private val accountManager: UserAccountManager, + private val licenseKeyStore: LicenseKeyStore, + private val tryToInitScanbotSdk: TryToInitScanbotSdk, + private val viewThemeUtils: Provider, +) { + + fun create(context: Context, params: WorkerParameters): ScanbotLicenseDownloadWorker { + return ScanbotLicenseDownloadWorker( + scanbotLicenseUrl, + viewThemeUtils.get(), + accountManager, + licenseKeyStore, + tryToInitScanbotSdk, + context, + params + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/logger/ScanbotLogger.kt b/app/src/main/java/com/ionos/scanbot/logger/ScanbotLogger.kt new file mode 100644 index 000000000000..46c7a67f2de4 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/logger/ScanbotLogger.kt @@ -0,0 +1,28 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.logger + +import com.ionos.scanbot.util.logger.Logger +import javax.inject.Inject +import com.nextcloud.client.logger.Logger as NextCloudLogger + +class ScanbotLogger @Inject constructor( + private val nextCloudLogger: NextCloudLogger +) : Logger { + + companion object { + private const val GLOBAL_TAG = "ScanbotModule" + } + + override fun logE(message: String, t: Throwable?) { + t?.let { + nextCloudLogger.e(GLOBAL_TAG, message, it) + } ?: nextCloudLogger.e(GLOBAL_TAG, message) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/upload/ScanbotUploader.kt b/app/src/main/java/com/ionos/scanbot/upload/ScanbotUploader.kt new file mode 100644 index 000000000000..6ddebd69a5a1 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/upload/ScanbotUploader.kt @@ -0,0 +1,39 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.upload + +import com.ionos.scanbot.upload.use_case.Uploader +import com.nextcloud.client.account.CurrentAccountProvider +import com.nextcloud.client.jobs.upload.FileUploadHelper +import com.nextcloud.client.jobs.upload.FileUploadWorker +import com.owncloud.android.files.services.NameCollisionPolicy +import com.owncloud.android.operations.UploadFileOperation +import java.io.File +import javax.inject.Inject + +class ScanbotUploader @Inject constructor( + private val currentAccountProvider: CurrentAccountProvider +): Uploader { + override fun upload(uploadFolder: String, pageList: List) { + val uploadPaths = pageList.map { + File(uploadFolder, File(it).name).path + }.toTypedArray() + + FileUploadHelper.instance().uploadNewFiles( + currentAccountProvider.user, + pageList.toTypedArray(), + uploadPaths, + FileUploadWorker.LOCAL_BEHAVIOUR_DELETE, + true, + UploadFileOperation.CREATED_BY_USER, + false, + false, + NameCollisionPolicy.RENAME + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/upload/SelectDirectoryContractImpl.kt b/app/src/main/java/com/ionos/scanbot/upload/SelectDirectoryContractImpl.kt new file mode 100644 index 000000000000..6fa9e08699d0 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/upload/SelectDirectoryContractImpl.kt @@ -0,0 +1,42 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.upload + +import android.app.Activity +import android.content.Context +import android.content.Intent +import com.ionos.scanbot.screens.save.SelectDirectoryContract +import com.ionos.scanbot.upload.target.RemoteUploadTarget +import com.nextcloud.utils.extensions.getParcelableArgument +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.ui.activity.FolderPickerActivity +import javax.inject.Inject + +class SelectDirectoryContractImpl @Inject constructor( +) : SelectDirectoryContract() { + + override fun createIntent(context: Context, input: Unit): Intent { + return Intent(context, FolderPickerActivity::class.java) + .apply { + putExtra(FolderPickerActivity.EXTRA_ACTION, FolderPickerActivity.CHOOSE_LOCATION) + } + } + + override fun parseResult(resultCode: Int, intent: Intent?): SelectDirectoryResult { + if (resultCode != Activity.RESULT_OK || intent == null || FolderPickerActivity.EXTRA_FOLDER == null) + return SelectDirectoryResult.Canceled + + return intent.getParcelableArgument(FolderPickerActivity.EXTRA_FOLDER, OCFile::class.java) + ?.remotePath?.let { + SelectDirectoryResult.Success( + RemoteUploadTarget(it) + ) + } ?: SelectDirectoryResult.Canceled + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/upload/target/RemoteUploadTarget.kt b/app/src/main/java/com/ionos/scanbot/upload/target/RemoteUploadTarget.kt new file mode 100644 index 000000000000..4d1474a8ef7e --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/upload/target/RemoteUploadTarget.kt @@ -0,0 +1,14 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.upload.target + +import com.ionos.scanbot.upload.target_provider.UploadTarget + +class RemoteUploadTarget( + override val uploadPath: String +) : UploadTarget \ No newline at end of file diff --git a/app/src/main/java/com/ionos/scanbot/utils/GetLocalFreeSpaceImpl.kt b/app/src/main/java/com/ionos/scanbot/utils/GetLocalFreeSpaceImpl.kt new file mode 100644 index 000000000000..337a612f9d04 --- /dev/null +++ b/app/src/main/java/com/ionos/scanbot/utils/GetLocalFreeSpaceImpl.kt @@ -0,0 +1,18 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.scanbot.utils + +import com.ionos.scanbot.util.GetLocalFreeSpace +import com.owncloud.android.utils.FileStorageUtils +import io.reactivex.Single +import javax.inject.Inject + +class GetLocalFreeSpaceImpl @Inject constructor() : GetLocalFreeSpace { + override fun invoke(): Single = + Single.fromCallable { FileStorageUtils.getUsableSpace() } +} \ No newline at end of file diff --git a/app/src/main/java/com/ionos/utils/IonosBuildHelper.kt b/app/src/main/java/com/ionos/utils/IonosBuildHelper.kt new file mode 100644 index 000000000000..d3d966957008 --- /dev/null +++ b/app/src/main/java/com/ionos/utils/IonosBuildHelper.kt @@ -0,0 +1,20 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO AG. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.ionos.utils + +import com.owncloud.android.BuildConfig + +object IonosBuildHelper { + + private const val IONOS_APPLICATION_ID = "com.ionos.hidrivenext" + + @JvmStatic + fun isIonosBuild(): Boolean { + return IONOS_APPLICATION_ID == BuildConfig.APPLICATION_ID + } +} diff --git a/app/src/main/java/com/ionos/utils/context/ContextUtils.kt b/app/src/main/java/com/ionos/utils/context/ContextUtils.kt new file mode 100644 index 000000000000..4b68b515e863 --- /dev/null +++ b/app/src/main/java/com/ionos/utils/context/ContextUtils.kt @@ -0,0 +1,18 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +@file:JvmName("ContextUtils") + +package com.ionos.utils.context + +import android.content.Context +import android.content.res.Configuration + +fun Context.isDarkMode(): Boolean { + val uiMode = resources.configuration.uiMode + return (uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES +} diff --git a/app/src/main/java/com/ionos/utils/text/CharSequenceUtils.kt b/app/src/main/java/com/ionos/utils/text/CharSequenceUtils.kt new file mode 100644 index 000000000000..c83acfa7965a --- /dev/null +++ b/app/src/main/java/com/ionos/utils/text/CharSequenceUtils.kt @@ -0,0 +1,46 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +@file:JvmName("CharSequenceUtils") + +package com.ionos.utils.text + +import android.text.Annotation +import android.text.SpannableString +import android.text.Spanned +import android.text.TextPaint +import android.text.style.ClickableSpan +import android.view.View + +fun CharSequence.convertAnnotatedTextToLinks( + linkColor: Int, + linkUnderline: Boolean, + linkHandler: (type: String) -> Unit, +): SpannableString { + val spannableString = SpannableString(this) + val annotations = spannableString.getSpans(0, spannableString.length, Annotation::class.java) + + annotations.forEach { annotation -> + val start = spannableString.getSpanStart(annotation) + val end = spannableString.getSpanEnd(annotation) + + val clickableSpan = object : ClickableSpan() { + override fun updateDrawState(paint: TextPaint) { + paint.color = linkColor + paint.isUnderlineText = linkUnderline + } + + override fun onClick(widget: View) { + linkHandler.invoke(annotation.value) + } + } + + spannableString.setSpan(clickableSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) + } + + return spannableString +} diff --git a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java index 2bcc027631a4..4d373fbf1332 100644 --- a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java +++ b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java @@ -19,6 +19,8 @@ import android.preference.PreferenceManager; import android.text.TextUtils; +import com.ionos.annotation.IonosCustomization; +import com.ionos.authorization_method.AuthorizationMethodActivity; import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.common.NextcloudClient; import com.nextcloud.utils.extensions.AccountExtensionsKt; @@ -452,12 +454,13 @@ private String getAccountType() { } @Override + @IonosCustomization public void startAccountCreation(final Activity activity) { // skipping AuthenticatorActivity redirection when user is on Launcher or FirstRun Activity if (activity instanceof LauncherActivity || activity instanceof FirstRunActivity) return; - Intent intent = new Intent(context, AuthenticatorActivity.class); + Intent intent = AuthorizationMethodActivity.createInstance(context); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); diff --git a/app/src/main/java/com/nextcloud/client/di/AppComponent.java b/app/src/main/java/com/nextcloud/client/di/AppComponent.java index 27e69184437c..41520339179a 100644 --- a/app/src/main/java/com/nextcloud/client/di/AppComponent.java +++ b/app/src/main/java/com/nextcloud/client/di/AppComponent.java @@ -9,6 +9,8 @@ import android.app.Application; +import com.ionos.di.StratoModule; +import com.ionos.scanbot.di.ScanbotComponent; import com.nextcloud.appReview.InAppReviewModule; import com.nextcloud.client.appinfo.AppInfoModule; import com.nextcloud.client.database.DatabaseModule; @@ -50,6 +52,7 @@ DatabaseModule.class, DispatcherModule.class, VariantModule.class, + StratoModule.class, }) @Singleton public interface AppComponent { @@ -69,6 +72,8 @@ public interface AppComponent { void inject(ProgressIndicator progressIndicator); + ScanbotComponent scanbotComponent(); + @Component.Builder interface Builder { @BindsInstance diff --git a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt index 21d6279b9ecb..2cffe684a28f 100644 --- a/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt +++ b/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt @@ -17,6 +17,7 @@ import androidx.core.view.MenuProvider import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.client.di.ViewModelFactory import com.nextcloud.client.logger.Logger @@ -143,6 +144,7 @@ class DocumentScanActivity : ToolbarActivity(), Injectable { } } + @IonosCustomization private fun showExportDialog() { val dialogBinding = DialogScanExportTypeBinding.inflate(layoutInflater) @@ -155,7 +157,7 @@ class DocumentScanActivity : ToolbarActivity(), Injectable { } .setOnCancelListener { viewModel.onExportCanceled() } .also { - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this@DocumentScanActivity, it) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(this@DocumentScanActivity, it) } .create() diff --git a/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt b/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt index 39692a56aabe..6c2241c4e474 100644 --- a/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt +++ b/app/src/main/java/com/nextcloud/client/editimage/EditImageActivity.kt @@ -15,10 +15,12 @@ import android.view.Menu import android.view.MenuItem import android.view.View import androidx.appcompat.content.res.AppCompatResources +import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import com.canhub.cropper.CropImageView +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.client.jobs.upload.FileUploadHelper import com.nextcloud.client.jobs.upload.FileUploadWorker @@ -32,7 +34,9 @@ import com.owncloud.android.operations.UploadFileOperation import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeType +import com.owncloud.android.utils.theme.ViewThemeUtils import java.io.File +import javax.inject.Inject class EditImageActivity : FileActivity(), @@ -45,6 +49,9 @@ class EditImageActivity : private lateinit var file: OCFile private lateinit var format: Bitmap.CompressFormat + @Inject + lateinit var viewThemeUtils: ViewThemeUtils + companion object { const val EXTRA_FILE = "FILE" const val OPEN_IMAGE_EDITOR = "OPEN_IMAGE_EDITOR" @@ -63,6 +70,7 @@ class EditImageActivity : } } + @IonosCustomization override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -81,7 +89,7 @@ class EditImageActivity : val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView) windowInsetsController.hide(WindowInsetsCompat.Type.statusBars()) - window.navigationBarColor = getColor(R.color.black) + viewThemeUtils.ionos.platform.themeSystemBars(this,getColor(R.color.edit_image_background)) setupCropper() } diff --git a/app/src/main/java/com/nextcloud/client/jobs/AccountRemovalWork.kt b/app/src/main/java/com/nextcloud/client/jobs/AccountRemovalWork.kt index ebcb5f7dd4d3..408a13575bfc 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/AccountRemovalWork.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/AccountRemovalWork.kt @@ -17,6 +17,7 @@ import android.text.TextUtils import androidx.work.Worker import androidx.work.WorkerParameters import com.google.gson.Gson +import com.ionos.privacy.PrivacyPreferences import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.Clock @@ -58,7 +59,8 @@ class AccountRemovalWork( private val clock: Clock, private val eventBus: EventBus, private val preferences: AppPreferences, - private val syncedFolderProvider: SyncedFolderProvider + private val syncedFolderProvider: SyncedFolderProvider, + private val privacyPreferences: PrivacyPreferences, ) : Worker(context, params) { companion object { @@ -112,6 +114,8 @@ class AccountRemovalWork( preferences.currentAccountName = "" } + privacyPreferences.removeDataProtectionProcessed(accountName) + // remove all files storageManager.removeLocalFiles(user, storageManager) 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 1a8d0df4d294..86da348fd8f4 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt @@ -15,6 +15,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.ListenableWorker import androidx.work.WorkerFactory import androidx.work.WorkerParameters +import com.ionos.privacy.PrivacyPreferences import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.Clock import com.nextcloud.client.device.DeviceInfo @@ -32,6 +33,8 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.utils.theme.ViewThemeUtils +import com.ionos.scanbot.license.ScanbotLicenseDownloadWorker +import com.ionos.scanbot.license.ScanbotLicenseJobFactory import org.greenrobot.eventbus.EventBus import javax.inject.Inject import javax.inject.Provider @@ -61,7 +64,9 @@ class BackgroundJobFactory @Inject constructor( private val viewThemeUtils: Provider, private val localBroadcastManager: Provider, private val generatePdfUseCase: GeneratePDFUseCase, - private val syncedFolderProvider: SyncedFolderProvider + private val syncedFolderProvider: SyncedFolderProvider, + private val scanbotLicenseJobFactory: ScanbotLicenseJobFactory, + private val privacyPreferences: PrivacyPreferences, ) : WorkerFactory() { @SuppressLint("NewApi") @@ -93,6 +98,7 @@ class BackgroundJobFactory @Inject constructor( FilesExportWork::class -> createFilesExportWork(context, workerParameters) FileUploadWorker::class -> createFilesUploadWorker(context, workerParameters) FileDownloadWorker::class -> createFilesDownloadWorker(context, workerParameters) + ScanbotLicenseDownloadWorker::class -> scanbotLicenseJobFactory.create(context, workerParameters) GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters) HealthStatusWork::class -> createHealthStatusWork(context, workerParameters) TestJob::class -> createTestJob(context, workerParameters) @@ -232,7 +238,8 @@ class BackgroundJobFactory @Inject constructor( clock, eventBus, preferences, - syncedFolderProvider + syncedFolderProvider, + privacyPreferences, ) } 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 642d22ba0fcc..9f0688af128f 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 @@ -16,6 +16,7 @@ import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.ViewModelFactory import com.owncloud.android.R import com.owncloud.android.databinding.LogsActivityBinding @@ -75,12 +76,12 @@ class LogsActivity : ToolbarActivity() { } } + @IonosCustomization 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) - viewThemeUtils.androidx.themeToolbarSearchView(this) } return super.onCreateOptionsMenu(menu) } diff --git a/app/src/main/java/com/nextcloud/client/media/Player.kt b/app/src/main/java/com/nextcloud/client/media/Player.kt index 8990fcdcca04..befcd7280a23 100644 --- a/app/src/main/java/com/nextcloud/client/media/Player.kt +++ b/app/src/main/java/com/nextcloud/client/media/Player.kt @@ -261,9 +261,7 @@ internal class Player( } override fun seekTo(pos: Int) { - if (stateMachine.isInState(State.PLAYING)) { - mediaPlayer?.seekTo(pos) - } + mediaPlayer?.seekTo(pos) } override fun getCurrentPosition(): Int { 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 f953a799735a..1a8dc1f63839 100644 --- a/app/src/main/java/com/nextcloud/client/media/PlayerService.kt +++ b/app/src/main/java/com/nextcloud/client/media/PlayerService.kt @@ -7,8 +7,11 @@ package com.nextcloud.client.media import android.app.PendingIntent +import android.app.PendingIntent.FLAG_IMMUTABLE import android.app.Service import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT +import android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP import android.media.AudioManager import android.os.Build import android.os.Bundle @@ -17,6 +20,7 @@ import android.widget.MediaController import android.widget.Toast import androidx.core.app.NotificationCompat import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.network.ClientFactory import com.nextcloud.utils.ForegroundServiceHelper @@ -174,9 +178,14 @@ class PlayerService : Service() { stopServiceAndRemoveNotification(file) } + @IonosCustomization("clickable notification") private fun startForeground(currentFile: OCFile) { val ticker = String.format(getString(R.string.media_notif_ticker), getString(R.string.app_name)) val content = getString(R.string.media_state_playing, currentFile.getFileName()) + val intent = Intent(this, PreviewMediaActivity::class.java) + .apply { + flags = FLAG_ACTIVITY_REORDER_TO_FRONT or FLAG_ACTIVITY_SINGLE_TOP + } notificationBuilder.run { setSmallIcon(R.drawable.ic_play_arrow) @@ -184,6 +193,9 @@ class PlayerService : Service() { setOngoing(true) setContentTitle(ticker) setContentText(content) + setContentIntent( + PendingIntent.getActivity(mContext, 0, intent, FLAG_IMMUTABLE) + ) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_MEDIA) 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 75d50b9b4a2e..88d000cd0f01 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java +++ b/app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java @@ -17,11 +17,13 @@ import com.google.common.reflect.TypeToken; import com.google.gson.Gson; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.appReview.AppReviewShownModel; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.account.UserAccountManagerImpl; import com.nextcloud.client.jobs.LogEntry; +import com.owncloud.android.R; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -482,14 +484,9 @@ public void setUploaderBehaviour(int uploaderBehaviour) { * @return grid columns grid columns */ @Override + @IonosCustomization public float getGridColumns() { - float columns = preferences.getFloat(AUTO_PREF__GRID_COLUMNS, DEFAULT_GRID_COLUMN); - - if (columns < 0) { - return DEFAULT_GRID_COLUMN; - } else { - return columns; - } + return context.getResources().getInteger(R.integer.grid_mode_column_count); } /** @@ -498,8 +495,9 @@ public float getGridColumns() { * @param gridColumns the uploader behavior */ @Override + @IonosCustomization public void setGridColumns(float gridColumns) { - preferences.edit().putFloat(AUTO_PREF__GRID_COLUMNS, gridColumns).apply(); + // Do nothing } @Override diff --git a/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt b/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt index edf674d988ba..d1b491cae307 100644 --- a/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt @@ -20,6 +20,7 @@ import android.widget.ImageView import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -72,6 +73,7 @@ class ChooseAccountDialogFragment : } @SuppressLint("InflateParams") + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { _binding = DialogChooseAccountBinding.inflate(layoutInflater) dialogView = binding.root @@ -79,11 +81,12 @@ class ChooseAccountDialogFragment : val builder = MaterialAlertDialogBuilder(requireContext()) .setView(binding.root) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) return builder.create() } + @IonosCustomization("Hide account id") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) accountManager = (activity as BaseActivity).userAccountManager @@ -104,6 +107,7 @@ class ChooseAccountDialogFragment : binding.currentAccount.userName.text = user.toOwnCloudAccount().displayName binding.currentAccount.ticker.visibility = View.GONE binding.currentAccount.account.text = user.accountName + binding.currentAccount.account.visibility = View.GONE // Defining user right indicator val icon = viewThemeUtils.platform.tintPrimaryDrawable(requireContext(), R.drawable.ic_check_circle) @@ -169,16 +173,17 @@ class ChooseAccountDialogFragment : } } + @IonosCustomization private fun themeViews() { viewThemeUtils.platform.themeDialogDivider(binding.separatorLine) - viewThemeUtils.platform.themeDialog(binding.root) + viewThemeUtils.ionos.platform.themeDialog(binding.root) viewThemeUtils.material.colorMaterialTextButton(binding.setStatus) - viewThemeUtils.dialog.colorDialogMenuText(binding.setStatus) + viewThemeUtils.ionos.dialog.colorDialogMenuText(binding.setStatus) viewThemeUtils.material.colorMaterialTextButton(binding.addAccount) - viewThemeUtils.dialog.colorDialogMenuText(binding.addAccount) + viewThemeUtils.ionos.dialog.colorDialogMenuText(binding.addAccount) viewThemeUtils.material.colorMaterialTextButton(binding.manageAccounts) - viewThemeUtils.dialog.colorDialogMenuText(binding.manageAccounts) + viewThemeUtils.ionos.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 9ea25e5caca9..60ad4a5af07b 100644 --- a/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt +++ b/app/src/main/java/com/nextcloud/ui/SetStatusDialogFragment.kt @@ -30,6 +30,7 @@ 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.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.AsyncRunner @@ -124,16 +125,18 @@ class SetStatusDialogFragment : } @SuppressLint("InflateParams") + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = DialogSetStatusBinding.inflate(layoutInflater) val builder = MaterialAlertDialogBuilder(requireContext()).setView(binding.root) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.statusView.context, builder) return builder.create() } + @IonosCustomization() @SuppressLint("DefaultLocale") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -196,11 +199,11 @@ class SetStatusDialogFragment : } } - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.clearStatus) - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(binding.setStatus) - viewThemeUtils.material.colorTextInputLayout(binding.customStatusInputContainer) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(binding.clearStatus) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(binding.setStatus) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.customStatusInputContainer) - viewThemeUtils.platform.themeDialog(binding.root) + viewThemeUtils.ionos.platform.themeDialog(binding.root) } private fun updateCurrentStatusViews(it: Status) { diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt index 5ed6042149cf..83b093b77ff3 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileAction.kt @@ -10,49 +10,51 @@ package com.nextcloud.ui.fileactions import androidx.annotation.DrawableRes import androidx.annotation.IdRes import androidx.annotation.StringRes +import com.ionos.annotation.IonosCustomization import com.owncloud.android.R +@IonosCustomization("Custom icons") enum class FileAction(@IdRes val id: Int, @StringRes val title: Int, @DrawableRes val icon: Int? = null) { // selection - SELECT_ALL(R.id.action_select_all_action_menu, R.string.select_all, R.drawable.ic_select_all), - SELECT_NONE(R.id.action_deselect_all_action_menu, R.string.deselect_all, R.drawable.ic_select_none), + SELECT_ALL(R.id.action_select_all_action_menu, R.string.select_all, R.drawable.ic_file_action_select_all), + SELECT_NONE(R.id.action_deselect_all_action_menu, R.string.deselect_all, R.drawable.ic_file_action_select_none), // generic file actions - EDIT(R.id.action_edit, R.string.action_edit, R.drawable.ic_edit), - SEE_DETAILS(R.id.action_see_details, R.string.actionbar_see_details, R.drawable.ic_information_outline), - REMOVE_FILE(R.id.action_remove_file, R.string.common_remove, R.drawable.ic_delete), + EDIT(R.id.action_edit, R.string.action_edit, R.drawable.ic_file_action_edit), + SEE_DETAILS(R.id.action_see_details, R.string.actionbar_see_details, R.drawable.ic_file_action_see_details), + REMOVE_FILE(R.id.action_remove_file, R.string.common_remove, R.drawable.ic_file_action_remove_file), // File moving - RENAME_FILE(R.id.action_rename_file, R.string.common_rename, R.drawable.ic_rename), - MOVE_OR_COPY(R.id.action_move_or_copy, R.string.actionbar_move_or_copy, R.drawable.ic_external), + RENAME_FILE(R.id.action_rename_file, R.string.common_rename, R.drawable.ic_file_action_rename_file), + MOVE_OR_COPY(R.id.action_move_or_copy, R.string.actionbar_move_or_copy, R.drawable.ic_file_action_move_or_copy), // favorites - FAVORITE(R.id.action_favorite, R.string.favorite, R.drawable.ic_star), - UNSET_FAVORITE(R.id.action_unset_favorite, R.string.unset_favorite, R.drawable.ic_star_outline), + FAVORITE(R.id.action_favorite, R.string.favorite, R.drawable.ic_file_action_favorite), + UNSET_FAVORITE(R.id.action_unset_favorite, R.string.unset_favorite, R.drawable.ic_file_action_unset_favorite), // Uploads and downloads - DOWNLOAD_FILE(R.id.action_download_file, R.string.filedetails_download, R.drawable.ic_cloud_download), - SYNC_FILE(R.id.action_sync_file, R.string.filedetails_sync_file, R.drawable.ic_cloud_sync_on), - CANCEL_SYNC(R.id.action_cancel_sync, R.string.common_cancel_sync, R.drawable.ic_cloud_sync_off), + DOWNLOAD_FILE(R.id.action_download_file, R.string.filedetails_download, R.drawable.ic_file_action_download_file), + SYNC_FILE(R.id.action_sync_file, R.string.filedetails_sync_file, R.drawable.ic_file_action_sync_file), + CANCEL_SYNC(R.id.action_cancel_sync, R.string.common_cancel_sync, R.drawable.ic_file_action_cancel_sync), // File sharing - EXPORT_FILE(R.id.action_export_file, R.string.filedetails_export, R.drawable.ic_export), - SEND_SHARE_FILE(R.id.action_send_share_file, R.string.action_send_share, R.drawable.ic_share), - SEND_FILE(R.id.action_send_file, R.string.common_send, R.drawable.ic_share), - OPEN_FILE_WITH(R.id.action_open_file_with, R.string.actionbar_open_with, R.drawable.ic_external), - STREAM_MEDIA(R.id.action_stream_media, R.string.stream, R.drawable.ic_play_arrow), - SET_AS_WALLPAPER(R.id.action_set_as_wallpaper, R.string.set_picture_as, R.drawable.ic_wallpaper), + EXPORT_FILE(R.id.action_export_file, R.string.filedetails_export, R.drawable.ic_file_action_export_file), + SEND_SHARE_FILE(R.id.action_send_share_file, R.string.action_send_share, R.drawable.ic_file_action_share_file), + SEND_FILE(R.id.action_send_file, R.string.common_send, R.drawable.ic_file_action_share_file), + OPEN_FILE_WITH(R.id.action_open_file_with, R.string.actionbar_open_with, R.drawable.ic_file_action_open_file_with), + STREAM_MEDIA(R.id.action_stream_media, R.string.stream, R.drawable.ic_file_action_stream_media), + SET_AS_WALLPAPER(R.id.action_set_as_wallpaper, R.string.set_picture_as, R.drawable.ic_file_action_set_as_wallpaper), // Encryption - SET_ENCRYPTED(R.id.action_encrypted, R.string.encrypted, R.drawable.ic_encrypt), - UNSET_ENCRYPTED(R.id.action_unset_encrypted, R.string.unset_encrypted, R.drawable.ic_decrypt), + SET_ENCRYPTED(R.id.action_encrypted, R.string.encrypted, R.drawable.ic_file_action_set_encrypted), + UNSET_ENCRYPTED(R.id.action_unset_encrypted, R.string.unset_encrypted, R.drawable.ic_file_action_unset_encrypted), // locks - UNLOCK_FILE(R.id.action_unlock_file, R.string.unlock_file, R.drawable.ic_lock_open_white), - LOCK_FILE(R.id.action_lock_file, R.string.lock_file, R.drawable.ic_lock), + UNLOCK_FILE(R.id.action_unlock_file, R.string.unlock_file, R.drawable.ic_file_action_unlock_file), + LOCK_FILE(R.id.action_lock_file, R.string.lock_file, R.drawable.ic_file_action_lock_file), // Shortcuts - PIN_TO_HOMESCREEN(R.id.action_pin_to_homescreen, R.string.pin_home, R.drawable.add_to_home_screen), + PIN_TO_HOMESCREEN(R.id.action_pin_to_homescreen, R.string.pin_home, R.drawable.ic_file_action_pin_to_homescreen), // Retry for offline operation RETRY(R.id.action_retry, R.string.retry, R.drawable.ic_retry); diff --git a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt index 1269459f2a94..c70db50f06a8 100644 --- a/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt +++ b/app/src/main/java/com/nextcloud/ui/fileactions/FileActionsBottomSheet.kt @@ -18,7 +18,6 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.annotation.IdRes -import androidx.appcompat.content.res.AppCompatResources import androidx.core.os.bundleOf import androidx.core.view.isEmpty import androidx.core.view.isVisible @@ -29,6 +28,7 @@ import androidx.lifecycle.ViewModelProvider import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable @@ -94,7 +94,7 @@ class FileActionsBottomSheet : BottomSheetDialogFragment(), Injectable { bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED bottomSheetDialog.behavior.skipCollapsed = true - viewThemeUtils.platform.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) + viewThemeUtils.ionos.platform.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) return binding.root } @@ -145,11 +145,9 @@ class FileActionsBottomSheet : BottomSheetDialogFragment(), Injectable { } } + @IonosCustomization("Set thumbnail drawable without tint") private fun setMultipleFilesThumbnail() { - context?.let { - val drawable = viewThemeUtils.platform.tintDrawable(it, R.drawable.file_multiple, ColorRole.PRIMARY) - binding.thumbnailLayout.thumbnail.setImageDrawable(drawable) - } + binding.thumbnailLayout.thumbnail.setImageResource(R.drawable.file_multiple) } override fun onDestroyView() { @@ -270,6 +268,7 @@ class FileActionsBottomSheet : BottomSheetDialogFragment(), Injectable { binding.title.text = resources.getQuantityString(R.plurals.file_list__footer__file, fileCount, fileCount) } + @IonosCustomization("Set icon drawable without tint") private fun inflateActionView(action: FileAction): View { val itemBinding = FileActionsBottomSheetItemBinding.inflate(layoutInflater, binding.fileActionsList, false) .apply { @@ -278,12 +277,7 @@ class FileActionsBottomSheet : BottomSheetDialogFragment(), Injectable { } text.setText(action.title) if (action.icon != null) { - val drawable = - viewThemeUtils.platform.tintDrawable( - requireContext(), - AppCompatResources.getDrawable(requireContext(), action.icon)!! - ) - icon.setImageDrawable(drawable) + icon.setImageResource(action.icon) } } return itemBinding.root diff --git a/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt b/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt index b39b3f812299..677b4c3a7456 100644 --- a/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt +++ b/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt @@ -16,14 +16,16 @@ import android.text.TextUtils import android.view.View import androidx.annotation.VisibleForTesting import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen +import com.ionos.annotation.IonosCustomization +import com.ionos.privacy.DataProtectionActivity +import com.ionos.privacy.PrivacyPreferences +import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.utils.mdm.MDMConfig import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.databinding.ActivitySplashBinding import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.activity.FileDisplayActivity -import com.owncloud.android.ui.activity.SettingsActivity import javax.inject.Inject class LauncherActivity : BaseActivity() { @@ -33,6 +35,9 @@ class LauncherActivity : BaseActivity() { @Inject lateinit var appPreferences: AppPreferences + @Inject + lateinit var privacyPreferences: PrivacyPreferences + override fun onCreate(savedInstanceState: Bundle?) { // Mandatory to call this before super method to show system launch screen for api level 31+ installSplashScreen() @@ -46,6 +51,9 @@ class LauncherActivity : BaseActivity() { scheduleSplashScreen() } + @IonosCustomization("Remove window insets paddings") + override fun isDefaultWindowInsetsHandlingEnabled() = false + @VisibleForTesting fun setSplashTitles(boldText: String, normalText: String) { binding.splashScreenBold.visibility = View.VISIBLE @@ -64,13 +72,15 @@ class LauncherActivity : BaseActivity() { } } + @IonosCustomization private fun scheduleSplashScreen() { Handler(Looper.getMainLooper()).postDelayed({ if (user.isPresent) { - if (MDMConfig.enforceProtection(this) && appPreferences.lockPreference == SettingsActivity.LOCK_NONE) { - startActivity(Intent(this, SettingsActivity::class.java)) + val intent = Intent(this, FileDisplayActivity::class.java) + if (privacyPreferences.isDataProtectionProcessed(userAccountManager.currentOwnCloudAccount?.name)) { + startActivity(intent) } else { - startActivity(Intent(this, FileDisplayActivity::class.java)) + startActivity(DataProtectionActivity.createIntent(this, intent)) } } else { startActivity(Intent(this, AuthenticatorActivity::class.java)) diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index 95ffbcd0a614..a201e0e27ad7 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -39,6 +39,9 @@ import android.view.WindowManager; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.ionos.analycis.AnalyticsManager; +import com.ionos.annotation.IonosCustomization; +import com.ionos.privacy.PrivacyPreferences; import com.nextcloud.appReview.InAppReviewHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; @@ -89,6 +92,9 @@ import com.owncloud.android.utils.ReceiversHelper; import com.owncloud.android.utils.SecurityUtils; import com.owncloud.android.utils.theme.ViewThemeUtils; +import com.ionos.scanbot.di.ScanbotComponent; +import com.ionos.scanbot.di.ScanbotComponentProvider; +import com.ionos.scanbot.initializer.ScanbotInitializer; import org.conscrypt.Conscrypt; import org.greenrobot.eventbus.EventBus; @@ -128,7 +134,8 @@ * Main Application of the project. * Contains methods to build the "static" strings. These strings were before constants in different classes. */ -public class MainApp extends Application implements HasAndroidInjector, NetworkChangeListener { +@IonosCustomization("ScanbotComponentProvider") +public class MainApp extends Application implements HasAndroidInjector, NetworkChangeListener, ScanbotComponentProvider { public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_28; public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_18; @@ -145,6 +152,12 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC @Inject protected AppPreferences preferences; + @Inject + protected PrivacyPreferences privacyPreferences; + + @Inject + protected AnalyticsManager analyticsManager; + @Inject protected DispatchingAndroidInjector dispatchingAndroidInjector; @@ -157,6 +170,9 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC @Inject protected OnboardingService onboarding; + @Inject + ScanbotInitializer scanbotInitializer; + @Inject ConnectivityService connectivityService; @@ -201,6 +217,8 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC private static AppComponent appComponent; + private ScanbotComponent scanbotComponent; + private NetworkChangeReceiver networkChangeReceiver; /** @@ -298,6 +316,7 @@ public static AppComponent getAppComponent() { @SuppressFBWarnings("ST") + @IonosCustomization("Scanbot, show hidden files") @Override public void onCreate() { enableStrictMode(); @@ -379,6 +398,11 @@ public void onCreate() { } registerGlobalPassCodeProtection(); + + scanbotInitializer.initialize(); + preferences.setShowHiddenFilesEnabled(true); + analyticsManager.setEnabled(privacyPreferences.isAnalyticsEnabled()); + networkChangeReceiver = new NetworkChangeReceiver(this, connectivityService); registerNetworkChangeReceiver(); @@ -434,6 +458,14 @@ public static boolean isClientBrandedPlus() { } }; + @Override + public ScanbotComponent getScanbotComponent() { + if (this.scanbotComponent == null) { + this.scanbotComponent = appComponent.scanbotComponent(); + } + return this.scanbotComponent; + } + private void setProxyConfig() { if (!isClientBrandedPlus()) { Log_OC.d(TAG, "Proxy configuration cannot be set. Client is not branded plus."); 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 d3c33f5d45db..c88c34d7693a 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -37,7 +37,6 @@ import android.webkit.URLUtil; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.LinearLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; @@ -48,7 +47,10 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import com.ionos.annotation.IonosCustomization; import com.google.gson.reflect.TypeToken; +import com.ionos.privacy.DataProtectionActivity; +import com.ionos.privacy.PrivacyPreferences; import com.nextcloud.android.common.ui.color.ColorUtil; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; @@ -57,7 +59,6 @@ import com.nextcloud.client.di.Injectable; import com.nextcloud.client.network.ClientFactory; import com.nextcloud.client.onboarding.FirstRunActivity; -import com.nextcloud.client.onboarding.OnboardingService; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.common.PlainClient; import com.nextcloud.operations.PostMethod; @@ -91,8 +92,6 @@ import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.ui.activity.SettingsActivity; -import com.owncloud.android.ui.dialog.IndeterminateProgressDialog; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener; import com.owncloud.android.utils.DisplayUtils; @@ -106,7 +105,6 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Locale; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -215,7 +213,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity @Inject UserAccountManager accountManager; @Inject AppPreferences preferences; - @Inject OnboardingService onboarding; + @Inject PrivacyPreferences privacyPreferences; @Inject DeviceInfo deviceInfo; @Inject PassCodeManager passCodeManager; @Inject ViewThemeUtils.Factory viewThemeUtilsFactory; @@ -239,16 +237,13 @@ public AccountSetupBinding getAccountSetupBinding() { * IMPORTANT ENTRY POINT 1: activity is shown to the user */ @Override + @IonosCustomization protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground(); - viewThemeUtils.platform.colorStatusBar(this, getResources().getColor(R.color.primary)); Uri data = getIntent().getData(); boolean directLogin = data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme)); - if (savedInstanceState == null && !directLogin) { - onboarding.launchFirstRunIfNeeded(this); - } onlyAdd = getIntent().getBooleanExtra(KEY_ONLY_ADD, false) || checkIfViaSSO(getIntent()); @@ -284,6 +279,10 @@ protected void onCreate(Bundle savedInstanceState) { mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG); } + if (directLogin) { + return; + } + boolean webViewLoginMethod = false; String webloginUrl = null; @@ -296,7 +295,7 @@ protected void onCreate(Bundle savedInstanceState) { if (!TextUtils.isEmpty(webloginUrl)) { webViewLoginMethod = true; - } else if (getIntent().getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) { + } else if (getIntent().getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, true)) { webViewLoginMethod = true; webloginUrl = getString(R.string.provider_registration_server); } else if (!TextUtils.isEmpty(getResources().getString(R.string.webview_login_url))) { @@ -310,6 +309,7 @@ protected void onCreate(Bundle savedInstanceState) { accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater()); setContentView(accountSetupWebviewBinding.getRoot()); anonymouslyPostLoginRequest(webloginUrl); + initCancelButton(); } else { accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater()); setContentView(accountSetupBinding.getRoot()); @@ -332,6 +332,17 @@ protected void onCreate(Bundle savedInstanceState) { ProcessLifecycleOwner.get().getLifecycle().addObserver(lifecycleEventObserver); } + @IonosCustomization + private void initCancelButton() { + MaterialButton cancelButton = accountSetupWebviewBinding.loginFlowV2.cancelButton; + + cancelButton.setOnClickListener(v -> { + loginFlowExecutorService.shutdown(); + ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver); + finish(); + }); + } + private void showEnforcedServers() { showAuthStatus(); accountSetupBinding.hostUrlFrame.setVisibility(View.GONE); @@ -651,6 +662,7 @@ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { * AndroidManifest.xml file. */ @Override + @IonosCustomization protected void onNewIntent(Intent intent) { super.onNewIntent(intent); Log_OC.d(TAG, "onNewIntent()"); @@ -676,7 +688,7 @@ protected void onNewIntent(Intent intent) { } } - if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) { + if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, true)) { accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater()); setContentView(accountSetupWebviewBinding.getRoot()); anonymouslyPostLoginRequest(getString(R.string.provider_registration_server)); @@ -799,13 +811,11 @@ private void checkOcServer() { * Tests the credentials entered by the user performing a check of existence on the root folder of the ownCloud * server. */ + @IonosCustomization private void checkBasicAuthorization(@Nullable String webViewUsername, @Nullable String webViewPassword) { - // be gentle with the user - IndeterminateProgressDialog dialog = IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, - true); - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - ft.add(dialog, WAIT_DIALOG_TAG); - ft.commitAllowingStateLoss(); + if (accountSetupWebviewBinding != null) { + accountSetupWebviewBinding.loginFlowV2.tvAuthorizationDescription.setText(R.string.auth_trying_to_login); + } // validate credentials accessing the root folder OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBasicCredentials(webViewUsername, @@ -920,12 +930,11 @@ private void onGetServerInfoFinish(RemoteOperationResult result) { } // region LoginInfoView + @IonosCustomization private void initLoginInfoView() { - LinearLayout loginFlowLayout = accountSetupWebviewBinding.loginFlowV2.getRoot(); - MaterialButton cancelButton = accountSetupWebviewBinding.loginFlowV2.cancelButton; - loginFlowLayout.setVisibility(View.VISIBLE); + MaterialButton retryButton = accountSetupWebviewBinding.loginFlowV2.bRetry; - cancelButton.setOnClickListener(v -> { + retryButton.setOnClickListener(v -> { loginFlowExecutorService.shutdown(); ProcessLifecycleOwner.get().getLifecycle().removeObserver(lifecycleEventObserver); recreate(); @@ -1187,17 +1196,19 @@ public void onAuthenticatorTaskCallback(RemoteOperationResult result) } } + @IonosCustomization private void endSuccess() { if (!onlyAdd) { - if (MDMConfig.INSTANCE.enforceProtection(this) && Objects.equals(preferences.getLockPreference(), SettingsActivity.LOCK_NONE)) { - Intent i = new Intent(this, SettingsActivity.class); - startActivity(i); - } else { - Intent i = new Intent(this, FileDisplayActivity.class); - i.setAction(FileDisplayActivity.RESTART); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); + Intent i = new Intent(this, FileDisplayActivity.class); + i.setAction(FileDisplayActivity.RESTART); + String accountName = accountManager.getCurrentOwnCloudAccount() != null + ? accountManager.getCurrentOwnCloudAccount().getName() + : null; + if (!privacyPreferences.isDataProtectionProcessed(accountName)) { + i = DataProtectionActivity.createIntent(this, i); } + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(i); } finish(); 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 3f74f9fee43a..7d31778cea91 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/app/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -34,6 +34,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.network.ConnectivityService; import com.owncloud.android.MainApp; @@ -609,6 +610,7 @@ protected Bitmap doInBackground(ThumbnailGenerationTaskObject... params) { return thumbnail; } + @IonosCustomization protected void onPostExecute(Bitmap bitmap) { if (bitmap != null && mImageViewReference != null) { final ImageView imageView = mImageViewReference.get(); @@ -624,11 +626,7 @@ protected void onPostExecute(Bitmap bitmap) { tagId = String.valueOf(((TrashbinFile) mFile).getRemoteId()); } if (String.valueOf(imageView.getTag()).equals(tagId)) { - if (gridViewEnabled) { - BitmapUtils.setRoundedBitmapForGridMode(bitmap, imageView); - } else { - BitmapUtils.setRoundedBitmap(bitmap, imageView); - } + imageView.setImageBitmap(bitmap); } } diff --git a/app/src/main/java/com/owncloud/android/media/MediaControlView.kt b/app/src/main/java/com/owncloud/android/media/MediaControlView.kt index 217c1c153501..28da66d75632 100644 --- a/app/src/main/java/com/owncloud/android/media/MediaControlView.kt +++ b/app/src/main/java/com/owncloud/android/media/MediaControlView.kt @@ -22,11 +22,14 @@ import android.view.LayoutInflater import android.view.View import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityNodeInfo +import android.widget.ImageButton import android.widget.LinearLayout import android.widget.SeekBar import android.widget.SeekBar.OnSeekBarChangeListener import androidx.core.content.ContextCompat import androidx.media3.common.Player +import com.google.android.material.button.MaterialButton +import com.ionos.annotation.IonosCustomization import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.MediaControlBinding @@ -73,6 +76,7 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : } @Suppress("MagicNumber") + @IonosCustomization("Removed theming") private fun initControllerView() { binding.playBtn.requestFocus() @@ -81,17 +85,10 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : binding.rewindBtn.setOnClickListener(this) binding.progressBar.run { - viewThemeUtils.platform.themeHorizontalSeekBar(this) setMax(1000) } binding.progressBar.setOnSeekBarChangeListener(this) - - viewThemeUtils.material.run { - colorMaterialButtonPrimaryTonal(binding.rewindBtn) - colorMaterialButtonPrimaryTonal(binding.playBtn) - colorMaterialButtonPrimaryTonal(binding.forwardBtn) - } } /** @@ -222,18 +219,25 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : } } + @IonosCustomization("ImageButton support") fun updatePausePlay() { - binding.playBtn.icon = ContextCompat.getDrawable( - context, - // use isPlaying instead of playWhenReady - // it represents only the play/pause state - // which is needed to show play/pause icons + val iconResource = if (playerControl?.isPlaying == true) { R.drawable.ic_pause } else { R.drawable.ic_play } - ) + val playBtn: View = binding.playBtn + + if (playBtn is MaterialButton){ + playBtn.icon = ContextCompat.getDrawable( + context, + iconResource + ) + } else if(playBtn is ImageButton){ + playBtn.setImageResource(iconResource) + } + binding.forwardBtn.visibility = if (playerControl?.isCommandAvailable(Player.COMMAND_SEEK_FORWARD) == true) { VISIBLE } else { @@ -269,6 +273,7 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : } @Suppress("MagicNumber") + @IonosCustomization("changed forward to 5 sec") override fun onClick(v: View) { playerControl?.let { playerControl -> val playing = playerControl.playWhenReady @@ -280,7 +285,8 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : } R.id.rewindBtn -> { - playerControl.seekBack() + val pos = playerControl.currentPosition + playerControl.seekTo(pos - 5000) if (!playing) { playerControl.pause() // necessary in some 2.3.x devices } @@ -288,7 +294,8 @@ class MediaControlView(context: Context, attrs: AttributeSet?) : } R.id.forwardBtn -> { - playerControl.seekForward() + val pos = playerControl.currentPosition + playerControl.seekTo(pos + 5000) if (!playing) { playerControl.pause() // necessary in some 2.3.x devices } diff --git a/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java b/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java index fc4c05dd4b77..2466858da3ea 100644 --- a/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java +++ b/app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java @@ -27,6 +27,8 @@ import android.util.Log; import android.widget.Toast; +import com.ionos.annotation.IonosCustomization; +import com.ionos.utils.IonosBuildHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.owncloud.android.R; @@ -376,6 +378,7 @@ public int update(@NonNull Uri uri, ContentValues values, String selection, Stri @Nullable @Override @SuppressFBWarnings("IOI_USE_OF_FILE_STREAM_CONSTRUCTORS") // TODO remove with API26 + @IonosCustomization public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(getContext()); @@ -396,7 +399,9 @@ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) thr Bitmap avatarBitmap = ThumbnailsCacheManager.getBitmapFromDiskCache(avatarKey); - if (avatarBitmap == null) { + if (avatarBitmap == null && IonosBuildHelper.isIonosBuild()) { + avatarBitmap = BitmapUtils.drawableToBitmap(getContext().getDrawable(R.drawable.account_circle_white)); + } else if (avatarBitmap == null) { float avatarRadius = getContext().getResources().getDimension(R.dimen.list_item_avatar_icon_radius); avatarBitmap = BitmapUtils.drawableToBitmap(TextDrawable.createNamedAvatar(displayName, avatarRadius)); } diff --git a/app/src/main/java/com/owncloud/android/ui/RoundedCornersConstraintLayout.kt b/app/src/main/java/com/owncloud/android/ui/RoundedCornersConstraintLayout.kt new file mode 100644 index 000000000000..6574db7cdfed --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/RoundedCornersConstraintLayout.kt @@ -0,0 +1,25 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.ui + +import android.content.Context +import android.util.AttributeSet +import androidx.constraintlayout.widget.ConstraintLayout +import com.owncloud.android.R + +class RoundedCornersConstraintLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : ConstraintLayout(context, attrs, defStyleAttr) { + + init { + setBackgroundResource(R.drawable.rounded_rect_4dp) + clipToOutline = true + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/SquareFrameLayout.kt b/app/src/main/java/com/owncloud/android/ui/SquareFrameLayout.kt new file mode 100644 index 000000000000..4f12f95adcb0 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/SquareFrameLayout.kt @@ -0,0 +1,23 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.ui + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout + +class SquareFrameLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : FrameLayout(context, attrs, defStyleAttr) { + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, widthMeasureSpec) + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java index af85b9ebeb16..e74418503b8f 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java @@ -13,6 +13,7 @@ import android.os.Build; import android.os.Bundle; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -68,10 +69,11 @@ public UserAccountManager getUserAccountManager() { } @Override + @IonosCustomization("Window insets handling") protected void onCreate(@Nullable Bundle savedInstanceState) { boolean isApiLevel35OrHigher = (Build.VERSION.SDK_INT >= 35); - if (isApiLevel35OrHigher) { + if (isApiLevel35OrHigher && isDefaultWindowInsetsHandlingEnabled()) { enableEdgeToEdge(); WindowExtensionsKt.addSystemBarPaddings(getWindow()); } @@ -85,6 +87,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { } } + @IonosCustomization("Window insets handling") + protected boolean isDefaultWindowInsetsHandlingEnabled() { + return true; + } + private void enableEdgeToEdge() { final var style = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT); EdgeToEdge.enable(this, style, style); 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 3e02c21624a7..f307337b1ba5 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 @@ -14,6 +14,8 @@ import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -50,11 +52,12 @@ import com.google.android.material.button.MaterialButton; import com.google.android.material.navigation.NavigationView; import com.google.android.material.progressindicator.LinearProgressIndicator; +import com.ionos.annotation.IonosCustomization; +import com.ionos.authorization_method.AuthorizationMethodActivity; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.files.DeepLinkConstants; import com.nextcloud.client.network.ClientFactory; -import com.nextcloud.client.onboarding.FirstRunActivity; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.common.NextcloudClient; import com.nextcloud.ui.ChooseAccountDialogFragment; @@ -103,6 +106,7 @@ 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.ViewThemeUtils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -119,7 +123,9 @@ import androidx.annotation.IdRes; import androidx.annotation.NonNull; +import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.content.res.AppCompatResources; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; @@ -287,8 +293,9 @@ private void handleBottomNavigationViewClicks() { /** * initializes and sets up the drawer toggle. */ + @IonosCustomization private void setupDrawerToggle() { - mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) { + mDrawerToggle = new AnimatedDrawerListener(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close, viewThemeUtils) { private boolean isMenuItemChecked = false; @Override @@ -331,12 +338,69 @@ public void onDrawerOpened(View drawerView) { mDrawerLayout.addDrawerListener(mDrawerToggle); mDrawerToggle.setDrawerIndicatorEnabled(true); mDrawerToggle.setDrawerSlideAnimationEnabled(true); - Drawable backArrow = ResourcesCompat.getDrawable(getResources(), - R.drawable.ic_arrow_back, - null); + Drawable drawerIndicator = AppCompatResources.getDrawable(this, R.drawable.ic_menu); + mDrawerToggle.setDrawerArrowDrawable(new SingleStateDrawerArrowDrawable(this, drawerIndicator)); + mDrawerToggle.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + } + + @IonosCustomization + private class AnimatedDrawerListener extends ActionBarDrawerToggle { + private static final float CHANGE_GAIN = 0.1f; + + private final Activity activity; + private final ViewThemeUtils viewThemeUtils; + private final ValueAnimator valueAnimator; + + AnimatedDrawerListener(Activity activity, + DrawerLayout drawerLayout, + @StringRes int openDrawerContentDescRes, + @StringRes int closeDrawerContentDescRes, + ViewThemeUtils viewThemeUtils + ) { + super(activity, drawerLayout, openDrawerContentDescRes, closeDrawerContentDescRes); + + this.activity = activity; + this.viewThemeUtils = viewThemeUtils; + this.valueAnimator = createValueAnimator(); + } + + private ValueAnimator createValueAnimator() { + int colorFrom = this.activity.getResources().getColor(R.color.bg_default); + int colorTo = getOpenedDrawerColor(); + return ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); + } + + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + super.onDrawerSlide(drawerView, slideOffset); + + if (shouldUpdateSystemBarColor(slideOffset)) { + this.valueAnimator.setCurrentFraction(slideOffset); + this.viewThemeUtils.ionos.platform.themeSystemBars(this.activity, (int) this.valueAnimator.getAnimatedValue()); + } + } + + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + + this.viewThemeUtils.ionos.platform.themeSystemBars(this.activity, getOpenedDrawerColor()); + } + + @Override + public void onDrawerClosed(View drawerView) { + super.onDrawerClosed(drawerView); + + this.viewThemeUtils.ionos.platform.themeSystemBars(this.activity); + } + + private boolean shouldUpdateSystemBarColor(float slideOffset) { + float delta = Math.abs(slideOffset - this.valueAnimator.getAnimatedFraction()); + return delta > CHANGE_GAIN; + } - if (backArrow != null) { - viewThemeUtils.platform.tintToolbarArrowDrawable(this, mDrawerToggle, backArrow); + private int getOpenedDrawerColor() { + return getResources().getColor(R.color.drawer_header_background); } } @@ -547,6 +611,7 @@ private void filterDrawerMenu(final Menu menu, @NonNull final User user) { DrawerMenuUtil.removeMenuItem(menu, R.id.nav_community, !getResources().getBoolean(R.bool.participate_enabled)); DrawerMenuUtil.removeMenuItem(menu, R.id.nav_shared, !getResources().getBoolean(R.bool.shared_enabled)); DrawerMenuUtil.removeMenuItem(menu, R.id.nav_logout, !getResources().getBoolean(R.bool.show_drawer_logout)); + DrawerMenuUtil.removePersonalFiles(menu); } @Subscribe(threadMode = ThreadMode.MAIN) @@ -659,10 +724,10 @@ public void openManageAccounts() { startActivityForResult(manageAccountsIntent, ACTION_MANAGE_ACCOUNTS); } + @IonosCustomization public void openAddAccount() { if (MDMConfig.INSTANCE.showIntro(this)) { - Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class); - firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true); + Intent firstRunIntent = AuthorizationMethodActivity.createInstance(getApplicationContext()); startActivity(firstRunIntent); } else { startAccountCreation(); @@ -840,6 +905,7 @@ private void showQuota(boolean showQuota) { * @param relative the percentage of space already used * @param quotaValue {@link GetUserInfoRemoteOperation#SPACE_UNLIMITED} or other to determinate state */ + @IonosCustomization private void setQuotaInformation(long usedSpace, long totalSpace, int relative, long quotaValue) { if (GetUserInfoRemoteOperation.SPACE_UNLIMITED == quotaValue) { mQuotaTextPercentage.setText(String.format( @@ -855,10 +921,9 @@ private void setQuotaInformation(long usedSpace, long totalSpace, int relative, mQuotaProgressBar.setProgress(relative); if (relative < RELATIVE_THRESHOLD_WARNING) { - viewThemeUtils.material.colorProgressBar(mQuotaProgressBar); + mQuotaProgressBar.setIndicatorColor(getResources().getColor(R.color.sidemenu_progress_bar_color, getTheme())); } else { - viewThemeUtils.material.colorProgressBar(mQuotaProgressBar, - getResources().getColor(R.color.infolevel_warning, getTheme())); + mQuotaProgressBar.setIndicatorColor(getResources().getColor(R.color.sidemenu_warn_progress_bar_color, getTheme())); } updateQuotaLink(); @@ -939,12 +1004,12 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) { * Sets the menu item as checked in both the drawer and bottom navigation views, if applicable. */ @SuppressFBWarnings("RV") + @IonosCustomization("Removed server styles for the drawer") public void setNavigationViewItemChecked() { if (drawerNavigationView != null) { MenuItem menuItem = drawerNavigationView.getMenu().findItem(menuItemId); if (menuItem != null && !menuItem.isChecked()) { - viewThemeUtils.platform.colorNavigationView(drawerNavigationView); menuItem.setChecked(true); } } 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 5ca616c337d6..94752e2de696 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 @@ -88,7 +88,7 @@ public void onUrlLoaded(String loadedUrl) { R.string.timeout_richDocuments, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.common_cancel, v -> closeView()); - viewThemeUtils.material.themeSnackbar(snackbar); + viewThemeUtils.ionos.material.themeSnackbar(snackbar); setLoadingSnackbar(snackbar); snackbar.show(); } 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 dad57adc3398..b8c519bd6802 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 @@ -22,6 +22,7 @@ import android.webkit.WebView; import android.widget.ProgressBar; +import com.ionos.annotation.IonosCustomization; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.ExternalsiteWebviewBinding; @@ -54,6 +55,7 @@ public class ExternalSiteWebView extends FileActivity { String url; @Override + @IonosCustomization protected final void onCreate(Bundle savedInstanceState) { Log_OC.v(TAG, "onCreate() start"); bindView(); @@ -78,6 +80,8 @@ protected final void onCreate(Bundle savedInstanceState) { setContentView(getRootView()); postOnCreate(); + + viewThemeUtils.ionos.platform.themeSystemBars(this); } protected void postOnCreate() { 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 e263d54fc0af..90471cd614e3 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 @@ -32,6 +32,7 @@ import android.text.TextUtils; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.jobs.BackgroundJobManager; @@ -452,6 +453,7 @@ protected void requestCredentialsUpdate(Account account) { new CheckRemoteWipeTask(backgroundJobManager, account, new WeakReference<>(this)).execute(); } + @IonosCustomization public void performCredentialsUpdate(Account account, Context context) { try { /// step 1 - invalidate credentials of current account @@ -477,6 +479,8 @@ public void performCredentialsUpdate(Account account, Context context) { AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN); updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivityForResult(updateAccountCredentials, REQUEST_CODE__UPDATE_CREDENTIALS); } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) { DisplayUtils.showSnackMessage(this, R.string.auth_account_does_not_exist); @@ -715,7 +719,7 @@ public static void copyAndShareFileLink(FileActivity activity, 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)); - viewThemeUtils.material.themeSnackbar(snackbar); + viewThemeUtils.ionos.material.themeSnackbar(snackbar); snackbar.show(); } } @@ -785,7 +789,7 @@ private void onUpdateShareInformation(RemoteOperationResult result, @StringRes i snackbar = Snackbar.make(sharingFragment.getView(), result.getMessage(), Snackbar.LENGTH_LONG); } - viewThemeUtils.material.themeSnackbar(snackbar); + viewThemeUtils.ionos.material.themeSnackbar(snackbar); snackbar.show(); } } @@ -862,7 +866,7 @@ private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation ope operation, getResources()), Snackbar.LENGTH_LONG); - viewThemeUtils.material.themeSnackbar(snackbar); + viewThemeUtils.ionos.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 d802d36a8703..9f07422456ab 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 @@ -47,6 +47,7 @@ import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.appReview.InAppReviewHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.appinfo.AppInfo; @@ -414,6 +415,7 @@ private void initTaskRetainerFragment() { } // else, Fragment already created and retained across configuration change } + @IonosCustomization private void checkStoragePath() { String newStorage = Environment.getExternalStorageDirectory().getAbsolutePath(); String storagePath = preferences.getStoragePath(newStorage); @@ -430,7 +432,7 @@ private void checkStoragePath() { .setPositiveButton(R.string.dialog_close, (dialog, which) -> dialog.dismiss()) .setIcon(R.drawable.ic_settings); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); builder.create().show(); } catch (WindowManager.BadTokenException e) { @@ -458,6 +460,7 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) { } @Override + @IonosCustomization("Hide account id") protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); @@ -483,7 +486,7 @@ protected void onPostCreate(Bundle savedInstanceState) { onOpenFileIntent(getIntent()); } else if (RESTART.equals(getIntent().getAction())) { // most likely switched to different account - DisplayUtils.showSnackMessage(this, String.format(getString(R.string.logged_in_as), accountManager.getUser().getAccountName())); + DisplayUtils.showSnackMessage(this, String.format(getString(R.string.logged_in_as), accountManager.getUser().toOwnCloudAccount().getDisplayName())); } upgradeNotificationForInstantUpload(); @@ -870,6 +873,7 @@ public boolean onPrepareOptionsMenu(Menu menu) { } @Override + @IonosCustomization public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_file_display, menu); @@ -883,8 +887,6 @@ public boolean onCreateOptionsMenu(Menu menu) { searchView.setIconified(false); }); - viewThemeUtils.androidx.themeToolbarSearchView(searchView); - // populate list of menu items to show/hide when drawer is opened/closed mDrawerMenuItemstoShowHideList = new ArrayList<>(1); mDrawerMenuItemstoShowHideList.add(searchMenuItem); @@ -1498,6 +1500,7 @@ private boolean checkForRemoteOperationError(RemoteOperationResult syncResult) { /** * Show a text message on screen view for notifying user if content is loading or folder is empty */ + @IonosCustomization private void setBackgroundText() { final OCFileListFragment ocFileListFragment = getListOfFilesFragment(); if (ocFileListFragment != null) { @@ -1505,7 +1508,7 @@ private void setBackgroundText() { ocFileListFragment.setEmptyListLoadingMessage(); } else { if (MainApp.isOnlyOnDevice()) { - ocFileListFragment.setMessageForEmptyList(R.string.file_list_empty_headline, R.string.file_list_empty_on_device, R.drawable.ic_list_empty_folder, true); + ocFileListFragment.setMessageForEmptyList(R.string.file_list_empty_headline, R.string.file_list_empty_on_device, R.drawable.ic_list_empty_folder); } else { connectivityService.isNetworkAndServerAvailable(result -> { if (result) { @@ -2577,6 +2580,7 @@ private void openDeepLink(Uri uri) { } } + @IonosCustomization private void selectUserAndOpenFile(List users, String fileId) { final CharSequence[] userNames = new CharSequence[users.size()]; for (int i = 0; i < userNames.length; i++) { @@ -2589,7 +2593,7 @@ private void selectUserAndOpenFile(List users, String fileId) { showLoadingDialog(getString(R.string.retrieving_file)); }); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); final AlertDialog dialog = builder.create(); dismissLoadingDialog(); 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 7cba32bb9a55..22ec425dd9cc 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 @@ -22,6 +22,7 @@ import android.view.MenuItem import android.view.View import androidx.activity.OnBackPressedCallback import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.utils.fileNameValidator.FileNameValidator import com.owncloud.android.R @@ -206,6 +207,7 @@ open class FolderPickerActivity : /** * Show a text message on screen view for notifying user if content is loading or folder is empty */ + @IonosCustomization private fun setBackgroundText() { val listFragment = listOfFilesFragment @@ -219,7 +221,6 @@ open class FolderPickerActivity : R.string.folder_list_empty_headline, R.string.file_list_empty_moving, R.drawable.ic_list_empty_create_folder, - true ) } else { it.setEmptyListLoadingMessage() @@ -444,23 +445,23 @@ open class FolderPickerActivity : private fun initControls() { if (this is FilePickerActivity) { - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(filesPickerBinding.folderPickerBtnCancel) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryFilled(filesPickerBinding.folderPickerBtnCancel) filesPickerBinding.folderPickerBtnCancel.setOnClickListener { finish() } } else { - viewThemeUtils.material.colorMaterialButtonText(folderPickerBinding.folderPickerBtnCancel) + viewThemeUtils.ionos.material.colorMaterialButtonText(folderPickerBinding.folderPickerBtnCancel) folderPickerBinding.folderPickerBtnCancel.setOnClickListener { finish() } - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(folderPickerBinding.folderPickerBtnChoose) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(folderPickerBinding.folderPickerBtnChoose) folderPickerBinding.folderPickerBtnChoose.setOnClickListener { processOperation(null) } - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(folderPickerBinding.folderPickerBtnCopy) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryFilled(folderPickerBinding.folderPickerBtnCopy) folderPickerBinding.folderPickerBtnCopy.setOnClickListener { processOperation( OperationsService.ACTION_COPY_FILE ) } - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(folderPickerBinding.folderPickerBtnMove) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(folderPickerBinding.folderPickerBtnMove) folderPickerBinding.folderPickerBtnMove.setOnClickListener { processOperation( OperationsService.ACTION_MOVE_FILE diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt index 0034cf33122f..79cd16cd7fd3 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.kt @@ -28,6 +28,8 @@ import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.common.collect.Sets +import com.ionos.annotation.IonosCustomization +import com.ionos.authorization_method.AuthorizationMethodActivity import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.jobs.download.FileDownloadHelper @@ -237,10 +239,9 @@ class ManageAccountsActivity : return result } + @IonosCustomization override fun showFirstRunActivity() { - val intent = Intent(applicationContext, FirstRunActivity::class.java).apply { - putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true) - } + val intent = AuthorizationMethodActivity.createInstance(applicationContext); startActivity(intent) } 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 5d8020a45cf5..b85267f607f4 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 @@ -47,7 +47,11 @@ import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.ionos.annotation.IonosCustomization; +import com.ionos.privacy.DataProtectionActivity; +import com.ionos.privacy.PrivacyPreferences; import com.nextcloud.client.account.User; +import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.jobs.upload.FileUploadWorker; @@ -134,6 +138,7 @@ public class ReceiveExternalFilesActivity extends FileActivity public static final int SINGLE_PARENT = 1; @Inject AppPreferences preferences; + @Inject PrivacyPreferences privacyPreferences; @Inject LocalBroadcastManager localBroadcastManager; @Inject SyncedFolderProvider syncedFolderProvider; @@ -166,6 +171,7 @@ public class ReceiveExternalFilesActivity extends FileActivity private ReceiveExternalFilesBinding binding; @Override + @IonosCustomization protected void onCreate(Bundle savedInstanceState) { if (savedInstanceState != null) { String parentPath = savedInstanceState.getString(KEY_PARENTS); @@ -179,6 +185,14 @@ protected void onCreate(Bundle savedInstanceState) { mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); super.onCreate(savedInstanceState); + + String accountName = accountManager.getCurrentOwnCloudAccount() != null + ? accountManager.getCurrentOwnCloudAccount().getName() + : null; + if (!privacyPreferences.isDataProtectionProcessed(accountName)) { + startActivity(DataProtectionActivity.createIntent(this)); + } + binding = ReceiveExternalFilesBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); @@ -287,9 +301,10 @@ protected void onDestroy() { } @Override + @IonosCustomization public void onSortingOrderChosen(FileSortOrder newSortOrder) { preferences.setSortOrder(mFile, newSortOrder); - sortButton.setText(DisplayUtils.getSortOrderStringId(newSortOrder)); + sortButton.setIconResource(DisplayUtils.getSortOrderIconRes(newSortOrder)); populateDirectoryList(null); } @@ -326,6 +341,7 @@ public DialogNoAccount(ViewThemeUtils viewThemeUtils) { @NonNull @Override + @IonosCustomization public Dialog onCreateDialog(Bundle savedInstanceState) { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext()); builder.setIcon(R.drawable.ic_warning); @@ -345,7 +361,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { }); builder.setNeutralButton(R.string.uploader_wrn_no_account_quit_btn_text, (dialog, which) -> requireActivity().finish()); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(requireContext(), builder); return builder.create(); } } @@ -384,6 +400,7 @@ public void onAttach(@NonNull Context context) { @NonNull @Override + @IonosCustomization public Dialog onCreateDialog(Bundle savedInstanceState) { mFilenameBase = new ArrayList<>(); mFilenameSuffix = new ArrayList<>(); @@ -459,7 +476,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { setFilename(binding.userInput, selectPos); binding.userInput.requestFocus(); - viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer); + viewThemeUtils.ionos.material.colorTextInputLayout(binding.userInputContainer); setupSpinner(adapter, selectPos, binding.userInput, binding.fileType); if (adapter.getCount() == SINGLE_SPINNER_ENTRY) { @@ -723,6 +740,7 @@ private void setupActionBarSubtitle() { } } + @IonosCustomization private void populateDirectoryList(OCFile file) { setupEmptyList(); setupToolbar(); @@ -783,14 +801,14 @@ private void populateDirectoryList(OCFile file) { btnChooseFolder.setEnabled(mFile.canWrite()); - viewThemeUtils.platform.themeStatusBar(this); + viewThemeUtils.ionos.platform.themeSystemBars(this); viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.uploaderCancel); binding.uploaderCancel.setOnClickListener(this); sortButton = binding.toolbarLayout.sortButton; FileSortOrder sortOrder = preferences.getSortOrderByFolder(mFile); - sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); + sortButton.setIconResource(DisplayUtils.getSortOrderIconRes(sortOrder)); sortButton.setOnClickListener(l -> openSortingOrderDialogFragment(getSupportFragmentManager(), sortOrder)); } @@ -1050,6 +1068,7 @@ public boolean onCreateOptionsMenu(Menu menu) { return true; } + @IonosCustomization private void setupSearchView(Menu menu) { final MenuItem searchMenuItem = menu.findItem(R.id.action_search); @@ -1067,8 +1086,6 @@ public boolean onQueryTextChange(String newText) { return false; } }); - - viewThemeUtils.androidx.themeToolbarSearchView(searchView); } @Override 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 bde331c722a3..4ab258a57d4a 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 @@ -16,12 +16,12 @@ package com.owncloud.android.ui.activity; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -41,6 +41,8 @@ import android.webkit.URLUtil; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.ionos.annotation.IonosCustomization; +import com.ionos.privacy.PrivacySettingsActivity; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -89,7 +91,6 @@ import androidx.appcompat.app.ActionBar; 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. @@ -146,6 +147,7 @@ public class SettingsActivity extends PreferenceActivity @SuppressWarnings("deprecation") @Override + @IonosCustomization("Delegate fix") public void onCreate(Bundle savedInstanceState) { boolean isApiLevel35OrHigher = (Build.VERSION.SDK_INT >= 35); if (isApiLevel35OrHigher) { @@ -153,10 +155,11 @@ public void onCreate(Bundle savedInstanceState) { WindowExtensionsKt.setNoLimitLayout(getWindow()); } - super.onCreate(savedInstanceState); - getDelegate().installViewFactory(); getDelegate().onCreate(savedInstanceState); + + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); setupActionBar(); @@ -195,6 +198,10 @@ public void onCreate(Bundle savedInstanceState) { // workaround for mismatched color when app dark mode and system dark mode don't agree setListBackground(); + + // workaround to set custom paddings + setListPadding(); + showPasscodeDialogIfEnforceAppProtection(); if (isApiLevel35OrHigher) { @@ -362,9 +369,10 @@ private void setupSyncCategory() { viewThemeUtils.files.themePreferenceCategory(preferenceCategorySync); setupAutoUploadPreference(preferenceCategorySync); - setupInternalTwoWaySyncPreference(); + setupInternalTwoWaySyncPreference(preferenceCategorySync); } + @IonosCustomization private void setupMoreCategory() { final PreferenceCategory preferenceCategoryMore = (PreferenceCategory) findPreference("more"); viewThemeUtils.files.themePreferenceCategory(preferenceCategoryMore); @@ -381,6 +389,8 @@ private void setupMoreCategory() { removeE2E(preferenceCategoryMore); + setupPrivacySettingsPreference(preferenceCategoryMore); + setupHelpPreference(preferenceCategoryMore); setupRecommendPreference(preferenceCategoryMore); @@ -429,6 +439,7 @@ private void setupLoggingPreference(PreferenceCategory preferenceCategoryMore) { } + @IonosCustomization private void setupRecommendPreference(PreferenceCategory preferenceCategoryMore) { boolean recommendEnabled = getResources().getBoolean(R.bool.recommend_enabled); Preference pRecommend = findPreference("recommend"); @@ -443,8 +454,13 @@ private void setupRecommendPreference(PreferenceCategory preferenceCategoryMore) String appName = getString(R.string.app_name); 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); + String downloadUrls; + if (URLUtil.isValidUrl(downloadUrlFDroid)) { + downloadUrls = String.format(getString(R.string.recommend_urls), + downloadUrlGooglePlayStore, downloadUrlFDroid); + } else { + downloadUrls = downloadUrlGooglePlayStore; + } String recommendSubject = String.format(getString(R.string.recommend_subject), appName); String recommendText = String.format(getString(R.string.recommend_text), @@ -571,6 +587,16 @@ private void showRemoveE2EAlertDialog(PreferenceCategory preferenceCategoryMore, .show(); } + private void setupPrivacySettingsPreference(PreferenceCategory preferenceCategoryMore) { + Preference privacySettings = findPreference("privacy_settings"); + if (privacySettings != null) { + privacySettings.setOnPreferenceClickListener(preference -> { + startActivity(PrivacySettingsActivity.createIntent(this)); + return true; + }); + } + } + private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) { boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled); Preference pHelp = findPreference("help"); @@ -599,8 +625,10 @@ private void setupAutoUploadPreference(PreferenceCategory preferenceCategoryMore } } - private void setupInternalTwoWaySyncPreference() { + @IonosCustomization("internal_two_way_sync was hidden") + private void setupInternalTwoWaySyncPreference(PreferenceCategory preferenceCategorySync) { Preference twoWaySync = findPreference("internal_two_way_sync"); + preferenceCategorySync.removePreference(twoWaySync); twoWaySync.setOnPreferenceClickListener(preference -> { Intent intent = new Intent(this, InternalTwoWaySyncActivity.class); @@ -840,6 +868,7 @@ private void disableLock(String lock) { } } + @IonosCustomization("Workaround to hide prefStoragePath") private void setupGeneralCategory() { final PreferenceCategory preferenceCategoryGeneral = (PreferenceCategory) findPreference("general"); viewThemeUtils.files.themePreferenceCategory(preferenceCategoryGeneral); @@ -848,6 +877,7 @@ private void setupGeneralCategory() { prefDataLoc = findPreference(AppPreferencesImpl.DATA_STORAGE_LOCATION); if (prefDataLoc != null) { + preferenceCategoryGeneral.removePreference(prefDataLoc); prefDataLoc.setOnPreferenceClickListener(p -> { Intent intent = new Intent(MainApp.getAppContext(), ChooseStorageLocationActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); @@ -890,6 +920,12 @@ private void setListBackground() { getListView().setBackgroundColor(ContextCompat.getColor(this, R.color.bg_default)); } + @IonosCustomization + private void setListPadding() { + int bottom = (int) getResources().getDimension(R.dimen.settings_screen_list_bottom_padding); + getListView().setPadding(0, 0, 0, bottom); + } + private String getAppVersion() { String temp; try { @@ -908,24 +944,16 @@ public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); } + @IonosCustomization private void setupActionBar() { ActionBar actionBar = getDelegate().getSupportActionBar(); if (actionBar == null) return; - viewThemeUtils.platform.themeStatusBar(this); + viewThemeUtils.ionos.platform.themeSystemBars(this); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setDisplayShowTitleEnabled(true); - - if (getResources() == null) return; - Drawable menuIcon = ResourcesCompat.getDrawable(getResources(), - R.drawable.ic_arrow_back, - null); - - if (menuIcon == null) return; - viewThemeUtils.androidx.themeActionBar(this, - actionBar, - getString(R.string.actionbar_settings), - menuIcon); + actionBar.setHomeAsUpIndicator(R.drawable.ic_arrow_back); + actionBar.setTitle(R.string.actionbar_settings); } private void launchDavDroidLogin() { @@ -1129,6 +1157,11 @@ public void invalidateOptionsMenu() { getDelegate().invalidateOptionsMenu(); } + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(getDelegate().attachBaseContext2(newBase)); + } + private AppCompatDelegate getDelegate() { if (delegate == null) { delegate = AppCompatDelegate.create(this, null); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SingleStateDrawerArrowDrawable.kt b/app/src/main/java/com/owncloud/android/ui/activity/SingleStateDrawerArrowDrawable.kt new file mode 100644 index 000000000000..60ed8da431ed --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/activity/SingleStateDrawerArrowDrawable.kt @@ -0,0 +1,24 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.ui.activity + +import android.content.Context +import android.graphics.Canvas +import android.graphics.drawable.Drawable +import androidx.appcompat.graphics.drawable.DrawerArrowDrawable + +class SingleStateDrawerArrowDrawable( + context: Context, + private val drawable: Drawable, +) : DrawerArrowDrawable(context) { + + override fun draw(canvas: Canvas) { + drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) + drawable.draw(canvas) + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java index 41524cda38b2..8aa991300eb9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SsoGrantPermissionActivity.java @@ -28,6 +28,7 @@ import android.text.style.StyleSpan; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.sso.Constants; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.MainApp; @@ -76,6 +77,7 @@ public DialogSsoGrantPermissionBinding getBinding() { } @Override + @IonosCustomization protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -115,7 +117,7 @@ protected void onCreate(Bundle savedInstanceState) { .setPositiveButton(R.string.permission_allow, (dialog, which) -> grantPermission()) .setNegativeButton(R.string.permission_deny, (dialog, which) -> exitFailed()); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(this, builder); dialog = builder.create(); dialog.show(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java index 00ab1b25cfe5..531d691b1164 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java @@ -20,6 +20,7 @@ import android.view.View; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -88,6 +89,7 @@ private boolean storageFolderAlreadyExists() { return f.exists() && f.isDirectory(); } + @IonosCustomization public static void a(ViewThemeUtils viewThemeUtils, Context context) { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context) .setMessage(R.string.file_migration_directory_already_exists) @@ -105,13 +107,14 @@ public static void a(ViewThemeUtils viewThemeUtils, Context context) { }); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(context, builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(context, builder); AlertDialog alertDialog = builder.create(); alertDialog.show(); } + @IonosCustomization private void askToOverride() { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mContext) .setMessage(R.string.file_migration_directory_already_exists) @@ -156,7 +159,7 @@ private void askToOverride() { progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); }); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(mContext, builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(mContext, builder); builder.create().show(); } @@ -243,6 +246,7 @@ protected void onPostExecute(Integer code) { } } + @IonosCustomization private void askToStillMove() { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mContext) .setTitle(R.string.file_migration_source_not_readable_title) @@ -254,7 +258,7 @@ private void askToStillMove() { } }); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(mContext, builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(mContext, builder); builder.create().show(); } 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 d18c26825cb6..c7b39e1269c9 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 @@ -26,6 +26,7 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.core.Clock import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.di.Injectable @@ -215,13 +216,14 @@ class SyncedFoldersActivity : return true } + @IonosCustomization fun buildPowerCheckDialog(): AlertDialog { val builder = MaterialAlertDialogBuilder(this) .setPositiveButton(R.string.common_ok) { dialog, _ -> dialog.dismiss() } .setTitle(R.string.autoupload_disable_power_save_check) .setMessage(getString(R.string.power_save_check_dialog_message)) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(this, builder) return builder.create() } @@ -246,7 +248,7 @@ class SyncedFoldersActivity : viewThemeUtils ) binding.emptyList.emptyListIcon.setImageResource(R.drawable.nav_synced_folders) - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.emptyList.emptyListViewAction) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryFilled(binding.emptyList.emptyListViewAction) val lm = GridLayoutManager(this, gridWidth) adapter.setLayoutManager(lm) val spacing = resources.getDimensionPixelSize(R.dimen.media_grid_spacing) @@ -802,6 +804,8 @@ class SyncedFoldersActivity : item.setExcludeHidden(excludeHidden) } + @IonosCustomization("StackOverflow fix") + private var externalStoragePermissionRequestCount = 0 override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { when (requestCode) { PermissionUtil.PERMISSIONS_EXTERNAL_STORAGE -> { @@ -809,12 +813,15 @@ class SyncedFoldersActivity : if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted load(getItemsDisplayedPerFolder(), true) + } else if (externalStoragePermissionRequestCount++ == 0) { + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true) } } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) } } + @IonosCustomization("Buttons style") private fun showBatteryOptimizationInfo() { if (powerManagementService.isPowerSavingExclusionAvailable || checkIfBatteryOptimizationEnabled()) { val alertDialogBuilder = MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog) @@ -835,7 +842,7 @@ class SyncedFoldersActivity : .setIcon(R.drawable.ic_battery_alert) if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { val alertDialog = alertDialogBuilder.show() - viewThemeUtils.platform.colorTextButtons( + viewThemeUtils.ionos.platform.colorTextButtons( alertDialog.getButton(AlertDialog.BUTTON_POSITIVE), alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) ) 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 0e56749caa79..b1310ef3c233 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 @@ -13,7 +13,6 @@ */ package com.owncloud.android.ui.activity; -import android.animation.AnimatorInflater; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.Color; @@ -30,6 +29,7 @@ import com.google.android.material.button.MaterialButton; import com.google.android.material.card.MaterialCardView; import com.google.android.material.textview.MaterialTextView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.di.Injectable; import com.owncloud.android.R; import com.owncloud.android.datamodel.FileDataStorageManager; @@ -74,6 +74,7 @@ public abstract class ToolbarActivity extends BaseActivity implements Injectable * Toolbar setup that must be called in implementer's {@link #onCreate} after {@link #setContentView} if they want * to use the toolbar. */ + @IonosCustomization private void setupToolbar(boolean isHomeSearchToolbarShow, boolean showSortListButtonGroup) { mToolbar = findViewById(R.id.toolbar); setSupportActionBar(mToolbar); @@ -101,9 +102,7 @@ private void setupToolbar(boolean isHomeSearchToolbarShow, boolean showSortListB mToolbarSpinner = findViewById(R.id.toolbar_spinner); - viewThemeUtils.material.themeToolbar(mToolbar); - viewThemeUtils.material.colorToolbarOverflowIcon(mToolbar); - viewThemeUtils.platform.themeStatusBar(this); + viewThemeUtils.ionos.platform.themeSystemBars(this); viewThemeUtils.material.colorMaterialTextButton(mSwitchAccountButton); } @@ -162,26 +161,21 @@ public void hideSearchView(OCFile chosenFile) { } } + @IonosCustomization private void showHomeSearchToolbar(String title, boolean isRoot) { showHomeSearchToolbar(isHomeSearchToolbarShow && isRoot); - mSearchText.setText(getString(R.string.appbar_search_in, title)); + mSearchText.setText(getString(R.string.actionbar_search, title)); } @SuppressLint("PrivateResource") + @IonosCustomization 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)); + viewThemeUtils.ionos.platform.resetSystemBars(this); mDefaultToolbar.setVisibility(View.GONE); mHomeSearchToolbar.setVisibility(View.VISIBLE); - viewThemeUtils.material.themeCardView(mHomeSearchToolbar); - viewThemeUtils.material.themeSearchBarText(mSearchText); } else { - mAppBar.setStateListAnimator(AnimatorInflater.loadStateListAnimator(mAppBar.getContext(), - R.animator.appbar_elevation_on)); - viewThemeUtils.platform.themeStatusBar(this); + viewThemeUtils.ionos.platform.themeSystemBars(this); mDefaultToolbar.setVisibility(View.VISIBLE); mHomeSearchToolbar.setVisibility(View.GONE); } @@ -295,11 +289,11 @@ public FrameLayout getPreviewImageContainer() { return mPreviewImageContainer; } + @IonosCustomization public void updateToolbarSubtitle(@NonNull String subtitle) { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setSubtitle(subtitle); - viewThemeUtils.androidx.themeActionBarSubtitle(this, actionBar); } } 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 36b12acd7e68..047b9ba3e37b 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 @@ -28,6 +28,7 @@ import android.widget.ArrayAdapter; import android.widget.TextView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.upload.FileUploadHelper; @@ -133,6 +134,7 @@ public static void startUploadActivityForResult(Activity activity, @Override @SuppressLint("WrongViewCast") // wrong error on finding local_files_list + @IonosCustomization public void onCreate(Bundle savedInstanceState) { Log_OC.d(TAG, "onCreate() start"); super.onCreate(savedInstanceState); @@ -168,7 +170,7 @@ public void onCreate(Bundle savedInstanceState) { /// USER INTERFACE // Drop-down navigation - mDirectories = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item); + mDirectories = new ArrayAdapter<>(this, R.layout.simple_spinner_item); mDirectories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); fillDirectoryDropdown(); @@ -184,10 +186,10 @@ public void onCreate(Bundle savedInstanceState) { mFileListFragment = (LocalFileListFragment) getSupportFragmentManager().findFragmentByTag("local_files_list"); // Set input controllers - viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.uploadFilesBtnCancel); + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryOutlined(binding.uploadFilesBtnCancel); binding.uploadFilesBtnCancel.setOnClickListener(this); - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.uploadFilesBtnUpload); + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryFilled(binding.uploadFilesBtnUpload); binding.uploadFilesBtnUpload.setOnClickListener(this); binding.uploadFilesBtnUpload.setEnabled(mLocalFolderPickerMode); @@ -276,6 +278,7 @@ private void fillDirectoryDropdown() { } @Override + @IonosCustomization public boolean onCreateOptionsMenu(Menu menu) { mOptionsMenu = menu; getMenuInflater().inflate(R.menu.activity_upload_files, menu); @@ -287,8 +290,6 @@ public boolean onCreateOptionsMenu(Menu menu) { final MenuItem item = menu.findItem(R.id.action_search); mSearchView = (SearchView) MenuItemCompat.getActionView(item); - viewThemeUtils.androidx.themeToolbarSearchView(mSearchView); - viewThemeUtils.platform.tintTextDrawable(this, menu.findItem(R.id.action_choose_storage_path).getIcon()); mSearchView.setOnSearchClickListener(v -> mToolbarSpinner.setVisibility(View.GONE)); 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 a1a27d25429f..4c40de496d22 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 @@ -20,6 +20,7 @@ import android.view.MenuItem; import android.view.View; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.core.Clock; @@ -142,12 +143,11 @@ private void handleUploadWorkerState() { uploadListAdapter.loadUploadItemsFromDb(); } + @IonosCustomization private void setupContent() { binding.list.setEmptyView(binding.emptyList.getRoot()); binding.emptyList.getRoot().setVisibility(View.GONE); binding.emptyList.emptyListIcon.setImageResource(R.drawable.uploads); - binding.emptyList.emptyListIcon.getDrawable().mutate(); - binding.emptyList.emptyListIcon.setAlpha(0.5f); binding.emptyList.emptyListIcon.setVisibility(View.VISIBLE); binding.emptyList.emptyListViewHeadline.setText(getString(R.string.upload_list_empty_headline)); binding.emptyList.emptyListViewText.setText(getString(R.string.upload_list_empty_text_auto_upload)); 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 e1cf782b39cb..741394837e90 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 @@ -28,6 +28,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.preferences.AppPreferences; @@ -231,7 +232,9 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) { } } + @IonosCustomization("Hide account id") private void populateUserInfoUi(UserInfo userInfo) { + binding.userinfoUsername.setVisibility(View.GONE); binding.userinfoUsername.setText(user.getAccountName()); binding.userinfoIcon.setTag(user.getAccountName()); DisplayUtils.setAvatar(user, diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java index 3c20828d1950..1fc577b6f1b2 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java @@ -6,12 +6,12 @@ */ package com.owncloud.android.ui.adapter; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.ui.ImageDetailFragment; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.ui.fragment.FileDetailActivitiesFragment; import com.owncloud.android.ui.fragment.FileDetailSharingFragment; -import com.owncloud.android.utils.MimeTypeUtil; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; @@ -54,35 +54,16 @@ public ImageDetailFragment getImageDetailFragment() { @NonNull @Override + @IonosCustomization("Hide tabs in IONOS") public Fragment createFragment(int position) { - return switch (position) { - default -> { - fileDetailActivitiesFragment = FileDetailActivitiesFragment.newInstance(file, user); - yield fileDetailActivitiesFragment; - } - case 1 -> { - fileDetailSharingFragment = FileDetailSharingFragment.newInstance(file, user); - yield fileDetailSharingFragment; - } - case 2 -> { - imageDetailFragment = ImageDetailFragment.newInstance(file, user); - yield imageDetailFragment; - } - }; + fileDetailSharingFragment = FileDetailSharingFragment.newInstance(file, user); + return fileDetailSharingFragment; } @Override + @IonosCustomization("Hide tabs in IONOS") public int getItemCount() { - if (showSharingTab) { - if (MimeTypeUtil.isImage(file)) { - return 3; - } - return 2; - } else { - if (MimeTypeUtil.isImage(file)) { - return 2; - } - return 1; - } + if (showSharingTab) return 1; + else return 0; } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt index 26aeb7bb4224..f892b178ad18 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt @@ -7,22 +7,27 @@ */ package com.owncloud.android.ui.adapter +import android.view.LayoutInflater +import android.view.View.INVISIBLE +import android.view.View.VISIBLE import android.widget.ImageView -import android.widget.LinearLayout +import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.res.ResourcesCompat +import androidx.core.view.children import androidx.core.view.get import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.ionos.annotation.IonosCustomization import com.owncloud.android.R import com.owncloud.android.databinding.GalleryRowBinding +import com.owncloud.android.databinding.IonosItemMediaBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.datamodel.GalleryRow import com.owncloud.android.datamodel.OCFile import com.owncloud.android.datamodel.ThumbnailsCacheManager -import com.owncloud.android.lib.resources.files.model.ImageDimension import com.owncloud.android.utils.BitmapUtils -import com.owncloud.android.utils.DisplayUtils +@IonosCustomization("Simplified grid") class GalleryRowHolder( val binding: GalleryRowBinding, private val defaultThumbnailSize: Float, @@ -38,14 +43,20 @@ class GalleryRowHolder( currentRow = row // re-use existing ones - while (binding.rowLayout.childCount < row.files.size) { - val shimmer = LoaderImageView(context).apply { + while (binding.rowLayout.childCount < galleryAdapter.columns) { + val itemBinding = IonosItemMediaBinding.inflate( + LayoutInflater.from(context), + binding.rowLayout, + true, + ) + + itemBinding.shimmer.apply { setImageResource(R.drawable.background) resetLoader() invalidate() } - val imageView = ImageView(context).apply { + itemBinding.image.apply { setImageDrawable( ThumbnailsCacheManager.AsyncGalleryImageDrawable( context.resources, @@ -58,23 +69,19 @@ class GalleryRowHolder( ) ) } - - LinearLayout(context).apply { - addView(shimmer) - addView(imageView) - - binding.rowLayout.addView(this) - } } - if (binding.rowLayout.childCount > row.files.size) { + if (binding.rowLayout.childCount > galleryAdapter.columns) { binding.rowLayout.removeViewsInLayout(row.files.size - 1, (binding.rowLayout.childCount - row.files.size)) } - val shrinkRatio = computeShrinkRatio(row) + binding.rowLayout.children.take(row.files.size) + .forEach { it.visibility = VISIBLE } + binding.rowLayout.children.drop(row.files.size) + .forEach { it.visibility = INVISIBLE } for (indexedFile in row.files.withIndex()) { - adjustFile(indexedFile, shrinkRatio, row) + adjustFile(indexedFile, row) } } @@ -82,97 +89,31 @@ class GalleryRowHolder( bind(currentRow) } - @SuppressWarnings("MagicNumber", "ComplexMethod") - private fun computeShrinkRatio(row: GalleryRow): Float { - val screenWidth = - DisplayUtils.convertDpToPixel(context.resources.configuration.screenWidthDp.toFloat(), context) - .toFloat() - - if (row.files.size > 1) { - var newSummedWidth = 0f - for (file in row.files) { - // first adjust all thumbnails to max height - val thumbnail1 = file.imageDimension ?: ImageDimension(defaultThumbnailSize, defaultThumbnailSize) - - val height1 = thumbnail1.height - val width1 = thumbnail1.width - - val scaleFactor1 = row.getMaxHeight() / height1 - val newHeight1 = height1 * scaleFactor1 - val newWidth1 = width1 * scaleFactor1 - - file.imageDimension = ImageDimension(newWidth1, newHeight1) - - newSummedWidth += newWidth1 - } - - var c = 1f - // this ensures that files in last row are better visible, - // e.g. when 2 images are there, it uses 2/5 of screen - if (galleryAdapter.columns == 5) { - when (row.files.size) { - 2 -> { - c = 5 / 2f - } - 3 -> { - c = 4 / 3f - } - 4 -> { - c = 4 / 5f - } - 5 -> { - c = 1f - } - } - } - - return (screenWidth / c) / newSummedWidth - } else { - val thumbnail1 = row.files[0].imageDimension ?: ImageDimension(defaultThumbnailSize, defaultThumbnailSize) - return (screenWidth / galleryAdapter.columns) / thumbnail1.width - } - } - - private fun adjustFile(indexedFile: IndexedValue, shrinkRatio: Float, row: GalleryRow) { + private fun adjustFile(indexedFile: IndexedValue, row: GalleryRow) { val file = indexedFile.value val index = indexedFile.index - val adjustedHeight1 = ((file.imageDimension?.height ?: defaultThumbnailSize) * shrinkRatio).toInt() - val adjustedWidth1 = ((file.imageDimension?.width ?: defaultThumbnailSize) * shrinkRatio).toInt() - - // re-use existing one - val linearLayout = binding.rowLayout[index] as LinearLayout + val linearLayout = binding.rowLayout[index] as ConstraintLayout val shimmer = linearLayout[0] as LoaderImageView - val thumbnail = linearLayout[1] as ImageView - thumbnail.adjustViewBounds = true - thumbnail.scaleType = ImageView.ScaleType.FIT_CENTER - ocFileListDelegate.bindGalleryRowThumbnail( shimmer, thumbnail, file, this, - adjustedWidth1 + thumbnail.width ) - val params = LinearLayout.LayoutParams(adjustedWidth1, adjustedHeight1) - val zero = context.resources.getInteger(R.integer.zero) val margin = context.resources.getInteger(R.integer.small_margin) if (index < (row.files.size - 1)) { - params.setMargins(zero, zero, margin, margin) + (thumbnail.layoutParams as ConstraintLayout.LayoutParams).setMargins(zero, zero, margin, margin) + (shimmer.layoutParams as ConstraintLayout.LayoutParams).setMargins(zero, zero, margin, margin) } else { - params.setMargins(zero, zero, zero, margin) + (thumbnail.layoutParams as ConstraintLayout.LayoutParams).setMargins(zero, zero, zero, margin) + (shimmer.layoutParams as ConstraintLayout.LayoutParams).setMargins(zero, zero, zero, margin) } - - thumbnail.layoutParams = params - thumbnail.layoutParams.height = adjustedHeight1 - thumbnail.layoutParams.width = adjustedWidth1 - - shimmer.layoutParams = params - shimmer.layoutParams.height = adjustedHeight1 - shimmer.layoutParams.width = adjustedWidth1 } + } 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 b2e70da44dd8..e124ebb16f9d 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 @@ -19,6 +19,7 @@ import android.text.TextUtils; import android.view.View; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.lib.resources.files.FileDownloadLimit; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.R; @@ -50,6 +51,7 @@ public LinkShareViewHolder(FileDetailsShareLinkShareItemBinding binding, this.viewThemeUtils = viewThemeUtils; } + @IonosCustomization public void bind(OCShare publicShare, ShareeListAdapterListener listener) { if (ShareType.EMAIL == publicShare.getShareType()) { binding.name.setText(publicShare.getSharedWithDisplayName()); @@ -74,7 +76,7 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { } } - viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); + // viewThemeUtils.platform.colorImageViewBackgroundAndIcon(binding.icon); } FileDownloadLimit downloadLimit = publicShare.getFileDownloadLimit(); @@ -103,11 +105,12 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) { } } + @IonosCustomization private void setPermissionName(OCShare publicShare, String permissionName) { if (!TextUtils.isEmpty(permissionName) && !SharingMenuHelper.isSecureFileDrop(publicShare)) { binding.permissionName.setText(permissionName); binding.permissionName.setVisibility(View.VISIBLE); - viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName); + // viewThemeUtils.androidx.colorPrimaryTextViewElement(binding.permissionName); } else { binding.permissionName.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ListViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/ListViewHolder.kt index 44e9fa7e8ee8..1e2af563a9df 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ListViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ListViewHolder.kt @@ -13,11 +13,14 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.ionos.annotation.IonosCustomization interface ListViewHolder { val thumbnail: ImageView fun showVideoOverlay() val shimmerThumbnail: LoaderImageView + @IonosCustomization + val fileIcon: ImageView val favorite: ImageView val localFileIndicator: ImageView val imageFileName: TextView? 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 16c032707a29..1fc7cacd66bb 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 @@ -21,6 +21,7 @@ import android.widget.LinearLayout; import android.widget.TextView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.R; @@ -157,6 +158,7 @@ public long getItemId(int position) { } @Override + @IonosCustomization public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { if (holder instanceof LocalFileListFooterViewHolder) { ((LocalFileListFooterViewHolder) holder).footerText.setText(getFooterText()); @@ -178,9 +180,7 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi gridViewHolder.checkbox.setVisibility(View.VISIBLE); if (isCheckedFile(file)) { gridViewHolder.itemLayout.setBackgroundColor(ContextCompat.getColor(mContext, R.color.selected_item_background)); - - gridViewHolder.checkbox.setImageDrawable( - viewThemeUtils.platform.tintDrawable(mContext, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY)); + gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_marked); } else { gridViewHolder.itemLayout.setBackgroundColor(mContext.getResources().getColor(R.color.bg_default)); gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.java index 0894dd98ac12..28f7fee72b8d 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/NotificationListAdapter.java @@ -35,6 +35,7 @@ import com.bumptech.glide.load.resource.file.FileToStreamDecoder; import com.caverock.androidsvg.SVG; import com.google.android.material.button.MaterialButton; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.common.NextcloudClient; import com.owncloud.android.R; @@ -158,6 +159,7 @@ public void onBindViewHolder(@NonNull NotificationViewHolder holder, int positio notificationsActivity).execute()); } + @IonosCustomization() public void setButtons(NotificationViewHolder holder, Notification notification) { // add action buttons holder.binding.buttons.removeAllViews(); @@ -220,7 +222,7 @@ public void setButtons(NotificationViewHolder holder, Notification notification) moreButton.setBackgroundColor(ResourcesCompat.getColor(resources, android.R.color.transparent, null)); - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(moreButton); + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(moreButton); moreButton.setAllCaps(false); @@ -268,7 +270,7 @@ public void setButtons(NotificationViewHolder holder, Notification notification) button.setBackgroundColor(ResourcesCompat.getColor(resources, android.R.color.transparent, null)); - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(button); + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(button); } button.setAllCaps(false); 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 452e366448a8..eebbe09522bc 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,6 +31,7 @@ import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.chip.Chip; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.android.lib.resources.recommendations.Recommendation; import com.nextcloud.client.account.User; @@ -127,8 +128,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter { @@ -391,17 +385,6 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int ); } } - case VIEW_TYPE_IMAGE -> { - if (gridView) { - return new OCFileListViewHolder( - GridImageBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false) - ); - } else { - return new OCFileListItemViewHolder( - ListItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false) - ); - } - } case VIEW_TYPE_FOOTER -> { return new OCFileListFooterViewHolder( ListFooterBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false) @@ -535,19 +518,9 @@ private void updateLivePhotoIndicators(ListViewHolder holder, OCFile file) { } } + @IonosCustomization private void bindListGridItemViewHolder(ListGridItemViewHolder holder, OCFile file) { holder.getFileName().setText(mStorageManager.getFilenameConsideringOfflineOperation(file)); - - boolean gridImage = MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file); - if (gridView && gridImage) { - holder.getFileName().setVisibility(View.GONE); - } else { - if (gridView && ocFileListFragmentInterface.getColumnsCount() > showFilenameColumnThreshold) { - holder.getFileName().setVisibility(View.GONE); - } else { - holder.getFileName().setVisibility(View.VISIBLE); - } - } } private void bindListItemViewHolder(ListItemViewHolder holder, OCFile file) { @@ -765,7 +738,7 @@ public boolean shouldShowHeader() { return false; } - return !TextUtils.isEmpty(currentDirectory.getRichWorkspace().trim()); + return false; //Hide header in IONOS // !TextUtils.isEmpty(currentDirectory.getRichWorkspace().trim()); } /** 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 accfc04b6a8c..2f8adc7f44a4 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 @@ -16,6 +16,7 @@ import android.widget.ImageView import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.account.User import com.nextcloud.client.jobs.download.FileDownloadHelper @@ -212,6 +213,7 @@ class OCFileListDelegate( } @Suppress("MagicNumber") + @IonosCustomization fun bindGridViewHolder( gridViewHolder: ListViewHolder, file: OCFile, @@ -221,7 +223,20 @@ class OCFileListDelegate( // thumbnail gridViewHolder.imageFileName?.text = file.fileName gridViewHolder.thumbnail.tag = file.fileId - setThumbnail(gridViewHolder.thumbnail, gridViewHolder.shimmerThumbnail, file) + OCFileListThumbnailLoader( + file, + gridViewHolder.thumbnail, + user, + storageManager, + asyncTasks, + gridView, + context, + gridViewHolder.shimmerThumbnail, + preferences, + viewThemeUtils, + syncFolderProvider, + gridViewHolder.fileIcon, + ).load() // item layout + click listeners bindGridItemLayout(file, gridViewHolder) @@ -275,8 +290,9 @@ class OCFileListDelegate( } } + @IonosCustomization private fun bindGridItemLayout(file: OCFile, gridViewHolder: ListViewHolder) { - setItemLayoutBackgroundColor(file, gridViewHolder) + setItemLayoutBackground(file, gridViewHolder) setCheckBoxImage(file, gridViewHolder) setItemLayoutOnClickListeners(file, gridViewHolder) @@ -300,6 +316,26 @@ class OCFileListDelegate( } } + @IonosCustomization + private fun setItemLayoutBackground(file: OCFile, gridViewHolder: ListViewHolder) { + val isSelected = file.fileId == highlightedItem?.fileId || isCheckedFile(file) + if (gridViewHolder is OCFileListGridItemViewHolder) { + val itemLayoutBackgroundResId = if (isSelected) { + R.drawable.grid_mode_selected_item_background + } else { + R.drawable.grid_mode_item_background + } + gridViewHolder.itemLayout.setBackgroundResource(itemLayoutBackgroundResId) + } else { + val itemLayoutBackgroundColor = if (isSelected) { + ContextCompat.getColor(context, R.color.selected_item_background) + } else { + ContextCompat.getColor(context, R.color.bg_default) + } + gridViewHolder.itemLayout.setBackgroundColor(itemLayoutBackgroundColor) + } + } + private fun setItemLayoutBackgroundColor(file: OCFile, gridViewHolder: ListViewHolder) { val cornerRadius = context.resources.getDimension(R.dimen.selected_grid_container_radius) @@ -322,11 +358,10 @@ class OCFileListDelegate( } } + @IonosCustomization private fun setCheckBoxImage(file: OCFile, gridViewHolder: ListViewHolder) { if (isCheckedFile(file)) { - gridViewHolder.checkbox.setImageDrawable( - viewThemeUtils.platform.tintDrawable(context, R.drawable.ic_checkbox_marked, ColorRole.PRIMARY) - ) + gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_marked) } else { gridViewHolder.checkbox.setImageResource(R.drawable.ic_checkbox_blank_outline) } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt index 05ee4731e994..3257c54fc277 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListGridItemViewHolder.kt @@ -14,6 +14,7 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.ionos.annotation.IonosCustomization import com.owncloud.android.databinding.GridItemBinding internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) : @@ -32,6 +33,9 @@ internal class OCFileListGridItemViewHolder(var binding: GridItemBinding) : override val shimmerThumbnail: LoaderImageView get() = binding.thumbnailShimmer + @IonosCustomization + override val fileIcon: ImageView + get() = binding.fileIcon override val favorite: ImageView get() = binding.favoriteAction override val localFileIndicator: ImageView diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt index 38b3310f0bbe..ef7f80367603 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListItemViewHolder.kt @@ -16,6 +16,7 @@ import androidx.recyclerview.widget.RecyclerView import com.elyeproj.loaderviewlibrary.LoaderImageView import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup +import com.ionos.annotation.IonosCustomization import com.owncloud.android.databinding.ListItemBinding import com.owncloud.android.ui.AvatarGroupLayout @@ -66,6 +67,9 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) : get() = null override val shimmerThumbnail: LoaderImageView get() = binding.thumbnailLayout.thumbnailShimmer + @IonosCustomization + override val fileIcon: ImageView + get() = binding.thumbnailLayout.fileIcon override val favorite: ImageView get() = binding.favoriteAction override val localFileIndicator: ImageView diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListThumbnailLoader.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListThumbnailLoader.kt new file mode 100644 index 000000000000..a83ea74bf210 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListThumbnailLoader.kt @@ -0,0 +1,147 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.ui.adapter + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.drawable.Drawable +import android.os.AsyncTask +import android.view.View +import android.widget.ImageView +import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.nextcloud.client.account.User +import com.nextcloud.client.preferences.AppPreferences +import com.owncloud.android.R +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.SyncedFolderProvider +import com.owncloud.android.datamodel.ThumbnailsCacheManager +import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTaskObject +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.utils.MimeTypeUtil +import com.owncloud.android.utils.theme.ViewThemeUtils + +class OCFileListThumbnailLoader( + private val file: OCFile, + private val thumbnailView: ImageView, + private val user: User, + private val storageManager: FileDataStorageManager, + private val asyncTasks: MutableList, + private val gridView: Boolean, + private val context: Context, + private val shimmerView: LoaderImageView, + private val preferences: AppPreferences, + private val viewThemeUtils: ViewThemeUtils, + private val syncedFolderProvider: SyncedFolderProvider?, + private val iconView: ImageView, +) { + + fun load() { + if (file.isFolder) { + showFolderIcon() + } else if (!file.isPreviewAvailable || file.remoteId == null) { + showFileIcon() + } else { + loadFromCacheOrRemote() + } + } + + private fun loadFromCacheOrRemote() { + val cacheKey = ThumbnailsCacheManager.PREFIX_THUMBNAIL + file.remoteId + val cachedThumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(cacheKey) + if (cachedThumbnail == null || file.isUpdateThumbnailNeeded) { + loadFromRemote() + } else if (MimeTypeUtil.isVideo(file)) { + val cachedThumbnailWithOverlay = ThumbnailsCacheManager.addVideoOverlay(cachedThumbnail, context) + showThumbnail(cachedThumbnailWithOverlay) + } else { + showThumbnail(cachedThumbnail) + } + } + + private fun loadFromRemote() { + if (!ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailView)) { + return + } + + showShimmer() + + try { + val task = ThumbnailGenerationTask( + thumbnailView, + storageManager, + user, + asyncTasks, + gridView, + file.remoteId, + ) + + task.setListener(object : ThumbnailGenerationTask.Listener { + override fun onSuccess() { + showExistedThumbnail() + } + + override fun onError() { + showFileIcon() + } + }) + + val px = ThumbnailsCacheManager.getThumbnailDimension() + val tempBitmap = Bitmap.createBitmap(px, px, Bitmap.Config.RGB_565) + val asyncDrawable = AsyncThumbnailDrawable(context.resources, tempBitmap, task) + thumbnailView.setImageDrawable(asyncDrawable) + + asyncTasks.add(task) + val taskObject = ThumbnailGenerationTaskObject(file, file.remoteId) + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, taskObject) + } catch (e: Exception) { + Log_OC.d(this::class.simpleName, "ThumbnailGenerationTask : " + e.message) + } + } + + private fun showFolderIcon() { + val isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user) + val isDarkModeActive = preferences.isDarkModeEnabled + val overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder) + val fileIcon = MimeTypeUtil.getFolderIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) + showIcon(fileIcon) + } + + private fun showFileIcon() { + val fileIcon = MimeTypeUtil.getFileTypeIcon(file.mimeType, file.fileName, context, viewThemeUtils) + showIcon(fileIcon) + } + + private fun showIcon(icon: Drawable) { + iconView.setImageDrawable(icon) + iconView.visibility = View.VISIBLE + thumbnailView.visibility = View.GONE + shimmerView.visibility = View.GONE + } + + private fun showThumbnail(thumbnail: Bitmap) { + thumbnailView.setImageBitmap(thumbnail) + showExistedThumbnail() + } + + private fun showExistedThumbnail() { + iconView.visibility = View.GONE + thumbnailView.visibility = View.VISIBLE + shimmerView.visibility = View.GONE + } + + private fun showShimmer() { + shimmerView.setImageResource(R.drawable.background) + shimmerView.resetLoader() + iconView.visibility = View.GONE + thumbnailView.visibility = View.GONE + shimmerView.visibility = View.VISIBLE + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt index 7619df6544fb..9e7a150ca6a2 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListViewHolder.kt @@ -14,6 +14,7 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.elyeproj.loaderviewlibrary.LoaderImageView +import com.ionos.annotation.IonosCustomization import com.owncloud.android.databinding.GridImageBinding internal class OCFileListViewHolder(var binding: GridImageBinding) : @@ -34,6 +35,9 @@ internal class OCFileListViewHolder(var binding: GridImageBinding) : override val shimmerThumbnail: LoaderImageView get() = binding.thumbnailShimmer + @IonosCustomization + override val fileIcon: ImageView + get() = binding.fileIcon override val favorite: ImageView get() = binding.favoriteAction override val localFileIndicator: ImageView 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 64ffa0350002..1041e5a018c9 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 @@ -14,6 +14,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.ionos.annotation.IonosCustomization import com.owncloud.android.databinding.ItemQuickSharePermissionsBinding import com.owncloud.android.datamodel.QuickPermissionModel import com.owncloud.android.utils.theme.ViewThemeUtils @@ -48,10 +49,10 @@ class QuickSharingPermissionsAdapter( RecyclerView .ViewHolder(itemView) { + @IonosCustomization("Disable icon tinting") 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/ShareViewHolder.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java index 4c9b95471f29..19875097f38b 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareViewHolder.java @@ -18,6 +18,8 @@ import android.view.View; import android.widget.ImageView; +import com.ionos.annotation.IonosCustomization; +import com.ionos.utils.IonosBuildHelper; import com.nextcloud.client.account.User; import com.owncloud.android.R; import com.owncloud.android.databinding.FileDetailsShareShareItemBinding; @@ -126,7 +128,12 @@ private void setPermissionName(String permissionName) { } } + @IonosCustomization private void setImage(ImageView avatar, String name, @DrawableRes int fallback) { + if (IonosBuildHelper.isIonosBuild()) { + avatar.setImageResource(R.drawable.account_circle_white); + return; + } try { avatar.setImageDrawable(TextDrawable.createNamedAvatar(name, avatarRadiusDimension)); } catch (StringIndexOutOfBoundsException e) { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java index 2b22b72050b9..71a62be5a1c3 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java @@ -17,6 +17,7 @@ import android.view.ViewGroup; import android.widget.ImageView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.R; @@ -226,6 +227,7 @@ public void remove(OCShare share) { /** * sort all by creation time, then email/link shares on top */ + @IonosCustomization("Hide internal share link") protected final void sortShares() { List links = new ArrayList<>(); List users = new ArrayList<>(); @@ -244,12 +246,6 @@ protected final void sortShares() { shares = links; shares.addAll(users); - // add internal share link at end - if (!encrypted && sharesType == SharesType.INTERNAL) { - final OCShare ocShare = new OCShare(); - ocShare.setShareType(ShareType.INTERNAL); - shares.add(ocShare); - } } public List getShares() { diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/StoragePathAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/StoragePathAdapter.kt index 7f37a9a216ef..640bcd69d9ae 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/StoragePathAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/StoragePathAdapter.kt @@ -10,6 +10,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.ionos.annotation.IonosCustomization import com.owncloud.android.databinding.StoragePathItemBinding import com.owncloud.android.ui.adapter.StoragePathAdapter.StoragePathViewHolder import com.owncloud.android.utils.theme.ViewThemeUtils @@ -26,12 +27,13 @@ class StoragePathAdapter( ) } + @IonosCustomization() override fun onBindViewHolder(holder: StoragePathViewHolder, position: Int) { if (pathList != null && pathList.size > position) { val storagePathItem = pathList[position] holder.binding.btnStoragePath.setIconResource(storagePathItem.icon) holder.binding.btnStoragePath.text = storagePathItem.name - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(holder.binding.btnStoragePath) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(holder.binding.btnStoragePath) } } diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt b/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt index 215f23f1f4b3..17c1f77b3ce4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/SyncedFolderAdapter.kt @@ -9,15 +9,20 @@ package com.owncloud.android.ui.adapter import android.annotation.SuppressLint import android.content.Context +import android.graphics.drawable.Drawable import android.view.LayoutInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.PopupMenu +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes import androidx.annotation.VisibleForTesting +import androidx.appcompat.content.res.AppCompatResources import com.afollestad.sectionedrecyclerview.SectionedRecyclerViewAdapter import com.afollestad.sectionedrecyclerview.SectionedViewHolder +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.core.Clock import com.owncloud.android.R @@ -240,6 +245,7 @@ class SyncedFolderAdapter( return -1 } + @IonosCustomization override fun onBindHeaderViewHolder(commonHolder: SectionedViewHolder, section: Int, expanded: Boolean) { if (section < filteredSyncFolderItems.size) { val holder = commonHolder as HeaderViewHolder @@ -248,11 +254,11 @@ class SyncedFolderAdapter( holder.binding.title.text = filteredSyncFolderItems[section].folderName if (MediaFolderType.VIDEO == filteredSyncFolderItems[section].type) { - holder.binding.type.setImageResource(R.drawable.video_32dp) + holder.binding.type.setImageDrawable(colorDrawable(R.drawable.video_32dp)) } else if (MediaFolderType.IMAGE == filteredSyncFolderItems[section].type) { - holder.binding.type.setImageResource(R.drawable.image_32dp) + holder.binding.type.setImageDrawable(colorDrawable(R.drawable.image_32dp)) } else { - holder.binding.type.setImageResource(R.drawable.folder_star_32dp) + holder.binding.type.setImageDrawable(colorDrawable(R.drawable.folder_star_32dp)) } holder.binding.syncStatusButton.visibility = View.VISIBLE @@ -437,16 +443,25 @@ class SyncedFolderAdapter( binding.root ) + @IonosCustomization private fun setSyncButtonActiveIcon(syncStatusButton: ImageButton, enabled: Boolean) { if (enabled) { - syncStatusButton.setImageDrawable( - viewThemeUtils.platform.tintDrawable(context, R.drawable.ic_cloud_sync_on, ColorRole.PRIMARY) - ) + syncStatusButton.setImageDrawable(colorDrawable(R.drawable.ic_cloud_sync_on)) } else { - syncStatusButton.setImageResource(R.drawable.ic_cloud_sync_off) + syncStatusButton.setImageDrawable(colorDrawable(R.drawable.ic_cloud_sync_off)) } } + @IonosCustomization + private fun colorDrawable( + @DrawableRes drawableRes: Int, + @ColorRes colorRes: Int = R.color.default_icon_color, + context: Context = this.context, + ): Drawable? = + AppCompatResources.getDrawable(context, drawableRes)?.let { drawable -> + viewThemeUtils.platform.colorDrawable(drawable, context.getColor(colorRes)) + } + companion object { private const val VIEW_TYPE_EMPTY = Int.MAX_VALUE private const val VIEW_TYPE_ITEM = 1 diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt index 69054c3ed240..0d73367c6581 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UnifiedSearchItemViewHolder.kt @@ -11,18 +11,20 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.drawable.Drawable import android.view.View +import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import com.afollestad.sectionedrecyclerview.SectionedViewHolder import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target -import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.network.ClientFactory import com.nextcloud.model.SearchResultEntryType import com.nextcloud.utils.CalendarEventManager import com.nextcloud.utils.ContactManager import com.nextcloud.utils.extensions.getType +import com.owncloud.android.R import com.owncloud.android.databinding.UnifiedSearchItemBinding import com.owncloud.android.datamodel.FileDataStorageManager import com.owncloud.android.lib.common.SearchResultEntry @@ -110,6 +112,7 @@ class UnifiedSearchItemViewHolder( } } + @IonosCustomization private fun getPlaceholder( entry: SearchResultEntry, entryType: SearchResultEntryType, @@ -121,7 +124,8 @@ class UnifiedSearchItemViewHolder( val defaultDrawable = MimeTypeUtil.getFileTypeIcon(mimetype, entry.title, context, viewThemeUtils) val drawable: Drawable = ResourcesCompat.getDrawable(context.resources, iconId, null) ?: defaultDrawable - return viewThemeUtils.platform.tintDrawable(context, drawable, ColorRole.PRIMARY) + val color = ContextCompat.getColor(context, R.color.filelist_file_icon_color) + return viewThemeUtils.platform.colorDrawable(drawable, color) } private inner class RoundIfNeededListener(private val entry: SearchResultEntry) : 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 1f2c7144a813..301e83229e1c 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 @@ -20,6 +20,7 @@ import android.view.ViewGroup; import android.widget.ImageView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.utils.mdm.MDMConfig; @@ -242,7 +243,9 @@ public void bind(User user, * * @param user the account */ + @IonosCustomization("Hide account id") private void setUser(User user) { + binding.account.setVisibility(View.GONE); binding.account.setText(DisplayUtils.convertIdn(user.getAccountName(), false)); binding.account.setTag(user.getAccountName()); } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt index e42f1b7c626f..715783e55352 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/AccountRemovalDialog.kt @@ -16,6 +16,7 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -47,6 +48,7 @@ class AccountRemovalDialog : DialogFragment(), AvatarGenerationListener, Injecta user = requireArguments().getParcelableArgument(KEY_USER, User::class.java) } + @IonosCustomization("colorMaterialButtonPrimaryTonal, colorMaterialButtonPrimaryBorderless, hide account name") override fun onStart() { super.onStart() @@ -56,17 +58,19 @@ class AccountRemovalDialog : DialogFragment(), AvatarGenerationListener, Injecta viewThemeUtils.platform.themeRadioButton(binding.radioLocalRemove) viewThemeUtils.platform.themeRadioButton(binding.radioRequestDeletion) - viewThemeUtils.material.colorMaterialButtonPrimaryTonal( + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal( alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton ) - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless( + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless( alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton ) binding.userName.text = UserAccountManager.getDisplayName(user) binding.account.text = user?.let { DisplayUtils.convertIdn(it.accountName, false) } + binding.account.visibility = View.GONE } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { _binding = AccountRemovalDialogBinding.inflate(layoutInflater) @@ -109,7 +113,7 @@ class AccountRemovalDialog : DialogFragment(), AvatarGenerationListener, Injecta } } - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(requireActivity(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.kt index b3b5eac4cfe4..73754b5db5e7 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ChooseRichDocumentsTemplateDialogFragment.kt @@ -21,6 +21,7 @@ import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.common.collect.Sets +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable @@ -91,6 +92,7 @@ class ChooseRichDocumentsTemplateDialogFragment : private lateinit var binding: ChooseTemplateBinding + @IonosCustomization() override fun onStart() { super.onStart() @@ -99,14 +101,14 @@ class ChooseRichDocumentsTemplateDialogFragment : alertDialog?.let { positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(it) it.setOnClickListener(this) it.isEnabled = false } val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton negativeButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) } } @@ -125,13 +127,14 @@ class ChooseRichDocumentsTemplateDialogFragment : } @Suppress("DEPRECATION") + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val arguments = arguments ?: throw IllegalArgumentException("Arguments may not be null") val activity = activity ?: throw IllegalArgumentException("Activity may not be null") initClient() initFilenames(arguments) - viewThemeUtils.material.colorTextInputLayout(binding.filenameContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.filenameContainer) val type = Type.valueOf(arguments.getString(ARG_TYPE) ?: "") FetchTemplateTask(this, client).execute(type) @@ -187,6 +190,7 @@ class ChooseRichDocumentsTemplateDialogFragment : }) } + @IonosCustomization private fun getDialogBuilder(activity: Activity, titleTextId: Int): MaterialAlertDialogBuilder { val builder = MaterialAlertDialogBuilder(activity) .setView(binding.root) @@ -194,7 +198,7 @@ class ChooseRichDocumentsTemplateDialogFragment : .setNegativeButton(R.string.common_cancel, null) .setTitle(titleTextId) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(activity, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(activity, builder) return builder } 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 34740ce9604e..046c7fe63eac 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 @@ -24,6 +24,7 @@ import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.GridLayoutManager import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.lib.resources.directediting.DirectEditingCreateFileRemoteOperation import com.nextcloud.android.lib.resources.directediting.DirectEditingObtainListOfTemplatesRemoteOperation import com.nextcloud.client.account.CurrentAccountProvider @@ -86,18 +87,19 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem private var _binding: ChooseTemplateBinding? = null val binding get() = _binding!! + @IonosCustomization() override fun onStart() { super.onStart() val alertDialog = dialog as AlertDialog val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton negativeButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) } val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(positiveButton) positiveButton.setOnClickListener(this) positiveButton.isEnabled = false positiveButton.isClickable = false @@ -112,6 +114,7 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem keyboardUtils.showKeyboardForEditText(dialog?.window, binding.filename) } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val arguments = arguments ?: throw IllegalArgumentException("Arguments may not be null") val activity = activity ?: throw IllegalArgumentException("Activity may not be null") @@ -130,7 +133,7 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem val inflater = requireActivity().layoutInflater _binding = ChooseTemplateBinding.inflate(inflater, null, false) - viewThemeUtils.material.colorTextInputLayout( + viewThemeUtils.ionos.material.colorTextInputLayout( binding.filenameContainer ) @@ -162,7 +165,7 @@ class ChooseTemplateDialogFragment : DialogFragment(), View.OnClickListener, Tem .setNegativeButton(R.string.common_cancel, null) .setTitle(title) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.list.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.list.context, builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt index 8fcc9b52603e..8314c511c594 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.kt @@ -18,6 +18,7 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -30,6 +31,7 @@ open class ConfirmationDialogFragment : DialogFragment(), Injectable { private var mListener: ConfirmationDialogFragmentListener? = null + @IonosCustomization() override fun onStart() { super.onStart() @@ -38,17 +40,17 @@ open class ConfirmationDialogFragment : DialogFragment(), Injectable { if (alertDialog != null) { val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton? if (positiveButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryTonal(positiveButton) } val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton? if (negativeButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) } val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as MaterialButton? if (neutralButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) } } } @@ -57,6 +59,7 @@ open class ConfirmationDialogFragment : DialogFragment(), Injectable { mListener = listener } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val messageArguments = requireArguments().getStringArray(ARG_MESSAGE_ARGUMENTS) ?: arrayOf() val titleId = requireArguments().getInt(ARG_TITLE_ID, -1) @@ -98,7 +101,7 @@ open class ConfirmationDialogFragment : DialogFragment(), Injectable { } } - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt index bda667cd6b08..4c3eb8146efd 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ConflictsResolveDialog.kt @@ -17,6 +17,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.database.entity.OfflineOperationEntity import com.nextcloud.client.di.Injectable @@ -82,6 +83,7 @@ class ConflictsResolveDialog : DialogFragment(), Injectable { } } + @IonosCustomization() override fun onStart() { super.onStart() @@ -96,10 +98,10 @@ class ConflictsResolveDialog : DialogFragment(), Injectable { val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(it) } - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) positiveButton?.isEnabled = false } @@ -125,6 +127,7 @@ class ConflictsResolveDialog : DialogFragment(), Injectable { } } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = ConflictResolveDialogBinding.inflate(requireActivity().layoutInflater) @@ -136,7 +139,7 @@ class ConflictsResolveDialog : DialogFragment(), Injectable { viewThemeUtils.run { platform.themeCheckbox(binding.leftCheckbox) platform.themeCheckbox(binding.rightCheckbox) - dialog.colorMaterialAlertDialogBackground(requireContext(), builder) + ionos.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) } return builder.create() diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt index b2e983d296d7..d961c7372c96 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt @@ -22,6 +22,7 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.common.collect.Sets +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.network.ConnectivityService @@ -75,6 +76,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList bindButton() } + @IonosCustomization("colorMaterialButtonPrimaryTonal, colorMaterialButtonPrimaryBorderless") private fun bindButton() { val dialog = dialog @@ -82,12 +84,6 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton positiveButton?.let { it.isEnabled = false - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) - } - - val negativeButton = dialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton - negativeButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(it) } } } @@ -99,6 +95,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList } @Suppress("EmptyFunctionBlock") + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { parentFolder = arguments?.getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) @@ -106,7 +103,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList binding = EditBoxDialogBinding.inflate(inflater, null, false) binding.userInput.setText(R.string.empty) - viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.userInputContainer) val parentFolder = requireArguments().getParcelableArgument(ARG_PARENT_FOLDER, OCFile::class.java) @@ -125,7 +122,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList }) val builder = buildMaterialAlertDialog(binding.root) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.kt index b5baded8ed3b..b6b694902b34 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ExpirationDatePickerDialogFragment.kt @@ -21,6 +21,7 @@ import android.text.format.DateUtils import android.widget.DatePicker import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.utils.theme.ViewThemeUtils @@ -42,6 +43,7 @@ class ExpirationDatePickerDialogFragment : DialogFragment(), OnDateSetListener, this.onExpiryDateListener = onExpiryDateListener } + @IonosCustomization() override fun onStart() { super.onStart() @@ -52,15 +54,15 @@ class ExpirationDatePickerDialogFragment : DialogFragment(), OnDateSetListener, val positiveButton = dialog.getButton(DatePickerDialog.BUTTON_POSITIVE) as MaterialButton? if (positiveButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryTonal(positiveButton) } val negativeButton = dialog.getButton(DatePickerDialog.BUTTON_NEGATIVE) as MaterialButton? if (negativeButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) } val neutralButton = dialog.getButton(DatePickerDialog.BUTTON_NEUTRAL) as MaterialButton? if (neutralButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.kt index ed179977f7af..c441304a9b62 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/LoadingDialog.kt @@ -8,13 +8,13 @@ */ package com.owncloud.android.ui.dialog +import android.app.Dialog import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.fragment.app.DialogFragment -import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable +import com.owncloud.android.R import com.owncloud.android.databinding.LoadingDialogBinding import com.owncloud.android.utils.theme.ViewThemeUtils import javax.inject.Inject @@ -35,18 +35,13 @@ class LoadingDialog : DialogFragment(), Injectable { isCancelable = false } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { - binding = LoadingDialogBinding.inflate(inflater, container, false) + @IonosCustomization + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + binding = LoadingDialogBinding.inflate(layoutInflater) binding.loadingText.text = mMessage - - val loadingDrawable = binding.loadingBar.indeterminateDrawable - if (loadingDrawable != null) { - viewThemeUtils?.platform?.tintDrawable(requireContext(), loadingDrawable) - } - - viewThemeUtils?.platform?.colorViewBackground(binding.loadingLayout, ColorRole.SURFACE) - - return binding.root + return MaterialAlertDialogBuilder(requireContext(), R.style.Theme_ownCloud_LoadingDialog) + .setView(binding.root) + .create() } override fun onDestroyView() { diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.kt index bc8de2411c22..4afcaa488bf0 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/LocalStoragePathPickerDialogFragment.kt @@ -15,6 +15,7 @@ import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.databinding.StoragePathDialogBinding @@ -38,6 +39,7 @@ class LocalStoragePathPickerDialogFragment : private lateinit var binding: StoragePathDialogBinding + @IonosCustomization() override fun onStart() { super.onStart() @@ -45,10 +47,11 @@ class LocalStoragePathPickerDialogFragment : val positiveButton = alertDialog?.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton? positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(positiveButton) } } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { require(activity is StoragePathAdapterListener) { "Calling activity must implement " + @@ -70,7 +73,7 @@ class LocalStoragePathPickerDialogFragment : .setPositiveButton(R.string.common_cancel, this) .setTitle(R.string.storage_choose_location) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt index 5b95a263a3b1..e1e39bcb044e 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt @@ -15,6 +15,7 @@ import android.view.View import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -35,6 +36,7 @@ class MultipleAccountsDialog : DialogFragment(), Injectable, UserListAdapter.Cli var viewThemeUtils: ViewThemeUtils? = null var highlightCurrentlyActiveAccount = true + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val inflater = requireActivity().layoutInflater val binding = MultipleAccountsBinding.inflate(inflater, null, false) @@ -57,7 +59,7 @@ class MultipleAccountsDialog : DialogFragment(), Injectable, UserListAdapter.Cli builder.setView(binding.root).setTitle(R.string.common_choose_account) - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.kt index 4b66ebf955c9..478fe71d492a 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.kt @@ -16,6 +16,7 @@ import android.os.Bundle import android.view.ActionMode import androidx.appcompat.app.AlertDialog import com.google.android.material.button.MaterialButton +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getTypedActivity import com.owncloud.android.R @@ -39,6 +40,7 @@ class RemoveFilesDialogFragment : ConfirmationDialogFragment(), ConfirmationDial private var positiveButton: MaterialButton? = null + @IonosCustomization() override fun onStart() { super.onStart() @@ -46,17 +48,17 @@ class RemoveFilesDialogFragment : ConfirmationDialogFragment(), ConfirmationDial positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton positiveButton?.let { - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(it) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryTonal(it) } val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton negativeButton?.let { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) } val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as? MaterialButton neutralButton?.let { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(neutralButton) } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt index 38c74ca57eb7..eb0aaba7baa4 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenameFileDialogFragment.kt @@ -21,6 +21,7 @@ import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.common.collect.Sets +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument @@ -72,6 +73,7 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen keyboardUtils.showKeyboardForEditText(requireDialog().window, binding.userInput) } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { mTargetFile = requireArguments().getParcelableArgument(ARG_TARGET_FILE, OCFile::class.java) @@ -80,7 +82,7 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen val currentName = mTargetFile?.fileName binding.userInput.setText(currentName) - viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.userInputContainer) val extensionStart = if (mTargetFile?.isFolder == true) -1 else currentName?.lastIndexOf('.') val selectionEnd = if ((extensionStart ?: -1) >= 0) extensionStart else currentName?.length if (selectionEnd != null) { @@ -99,7 +101,7 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen val builder = buildMaterialAlertDialog(binding.root) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.userInputContainer.context, builder) return builder.create() } @@ -116,6 +118,7 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen return builder } + @IonosCustomization() private fun initAlertDialog() { val alertDialog = dialog as AlertDialog? @@ -124,9 +127,9 @@ class RenameFileDialogFragment : DialogFragment(), DialogInterface.OnClickListen val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(it) } - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.kt index 845d8748b217..99fe5a24cfb0 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/RenamePublicShareDialogFragment.kt @@ -16,6 +16,7 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R @@ -40,6 +41,7 @@ class RenamePublicShareDialogFragment : DialogFragment(), DialogInterface.OnClic private lateinit var binding: EditBoxDialogBinding private var publicShare: OCShare? = null + @IonosCustomization() override fun onStart() { super.onStart() @@ -49,11 +51,11 @@ class RenamePublicShareDialogFragment : DialogFragment(), DialogInterface.OnClic val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(positiveButton) } negativeButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) } } @@ -62,6 +64,7 @@ class RenamePublicShareDialogFragment : DialogFragment(), DialogInterface.OnClic keyboardUtils.showKeyboardForEditText(requireDialog().window, binding.userInput) } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { publicShare = requireArguments().getParcelableArgument(ARG_PUBLIC_SHARE, OCShare::class.java) @@ -69,7 +72,7 @@ class RenamePublicShareDialogFragment : DialogFragment(), DialogInterface.OnClic binding = EditBoxDialogBinding.inflate(inflater, null, false) val view: View = binding.root - viewThemeUtils.material.colorTextInputLayout(binding.userInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.userInputContainer) binding.userInput.setText(publicShare?.label) val builder = MaterialAlertDialogBuilder(view.context) @@ -78,7 +81,7 @@ class RenamePublicShareDialogFragment : DialogFragment(), DialogInterface.OnClic .setNegativeButton(R.string.common_cancel, this) .setTitle(R.string.public_share_name) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.userInput.context, builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(binding.userInput.context, builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.kt index 4f851b3d99e5..87faeeb7161e 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SendFilesDialog.kt @@ -56,7 +56,7 @@ class SendFilesDialog : BottomSheetDialogFragment(R.layout.send_files_fragment), binding = SendFilesFragmentBinding.inflate(inflater, container, false) setupSendButtonRecyclerView() - viewThemeUtils?.platform?.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) + viewThemeUtils?.ionos?.platform?.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) return binding.root } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt index c45d2f854fe1..341761fd86fc 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt @@ -112,7 +112,7 @@ class SendShareDialog : BottomSheetDialogFragment(R.layout.send_share_fragment), private fun applyTintColor() { viewThemeUtils?.material?.colorMaterialButtonPrimaryFilled(binding.btnLink) viewThemeUtils?.material?.colorMaterialButtonPrimaryFilled(binding.btnShare) - viewThemeUtils?.platform?.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) + viewThemeUtils?.ionos?.platform?.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) } @Suppress("MagicNumber") diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt index 2c73b3a92d58..d5d47cfb01a2 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.kt @@ -20,6 +20,7 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.owncloud.android.R @@ -53,6 +54,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { private var createShare = false private var askForPassword = false + @IonosCustomization() override fun onStart() { super.onStart() @@ -61,7 +63,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { if (alertDialog != null) { val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton? if (positiveButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryTonal(positiveButton) positiveButton.setOnClickListener { val sharePassword = binding?.sharePassword?.text @@ -84,7 +86,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton? if (negativeButton != null) { - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(negativeButton) } val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as MaterialButton? @@ -100,6 +102,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { keyboardUtils?.showKeyboardForEditText(requireDialog().window, binding!!.sharePassword) } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { file = requireArguments().getParcelableArgument(ARG_FILE, OCFile::class.java) share = requireArguments().getParcelableArgument(ARG_SHARE, OCShare::class.java) @@ -113,7 +116,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { // Setup layout binding?.sharePassword?.setText(R.string.empty) - viewThemeUtils?.material?.colorTextInputLayout(binding!!.sharePasswordContainer) + viewThemeUtils?.ionos?.material?.colorTextInputLayout(binding!!.sharePasswordContainer) val neutralButtonTextId: Int val title: Int @@ -137,7 +140,7 @@ class SharePasswordDialogFragment : DialogFragment(), Injectable { } .setTitle(title) - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt index 8a593cabf541..b69a3c18239b 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SortingOrderDialogFragment.kt @@ -14,6 +14,7 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.databinding.SortingOrderFragmentBinding @@ -49,6 +50,7 @@ class SortingOrderDialogFragment : DialogFragment(), Injectable { * * @param binding the parent binding */ + @IonosCustomization("Remove material buttons styling") private fun setupDialogElements(binding: SortingOrderFragmentBinding) { val bindings = listOf( binding.sortByNameAscending to FileSortOrder.SORT_A_TO_Z, @@ -63,14 +65,13 @@ class SortingOrderDialogFragment : DialogFragment(), Injectable { view.tag = sortOrder view.let { it.setOnClickListener(OnSortOrderClickListener()) - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(it) } } - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(binding.cancel) binding.cancel.setOnClickListener { dismiss() } } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { binding = SortingOrderFragmentBinding.inflate(requireActivity().layoutInflater, null, false) setupDialogElements(binding!!) @@ -78,7 +79,7 @@ class SortingOrderDialogFragment : DialogFragment(), Injectable { val builder = MaterialAlertDialogBuilder(requireContext()) builder.setView(binding?.root) - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt index 76bd0aaea843..ebba72605f77 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt @@ -22,6 +22,7 @@ import android.webkit.SslErrorHandler import android.widget.Button import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding @@ -73,6 +74,7 @@ open class SslUntrustedCertDialog : DialogFragment(), Injectable { binding = null } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { Log_OC.d(TAG, "onCreateDialog, savedInstanceState is $savedInstanceState") @@ -103,7 +105,7 @@ open class SslUntrustedCertDialog : DialogFragment(), Injectable { setView(layoutBinding.getRoot()) } - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create().apply { requestWindowFeature(Window.FEATURE_NO_TITLE) 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 220f28edd680..2b8c9390d0c1 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 @@ -17,6 +17,7 @@ import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.owncloud.android.R import com.owncloud.android.utils.theme.ViewThemeUtils @@ -43,50 +44,48 @@ class StoragePermissionDialogFragment : DialogFragment(), Injectable { } } + @IonosCustomization() override fun onStart() { super.onStart() dialog?.let { val alertDialog = it as AlertDialog val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(positiveButton) val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(negativeButton) val neutralButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL) as MaterialButton - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(neutralButton) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(neutralButton) } } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val title = when { - permissionRequired -> R.string.file_management_permission - else -> R.string.file_management_permission_optional + permissionRequired -> R.string.ionos_file_management_permission + else -> R.string.ionos_file_management_permission_optional } val explanationResource = when { - permissionRequired -> R.string.file_management_permission_text - else -> R.string.file_management_permission_optional_text + permissionRequired -> R.string.ionos_file_management_permission_text + else -> R.string.ionos_file_management_permission_optional_text } val message = getString(explanationResource, getString(R.string.app_name)) - val dialogBuilder = MaterialAlertDialogBuilder(requireContext()) + val dialogBuilder = MaterialAlertDialogBuilder(requireContext(), R.style.Theme_ownCloud_Dialog) .setTitle(title) .setMessage(message) - .setPositiveButton(R.string.storage_permission_full_access) { _, _ -> + .setPositiveButton(R.string.permission_allow) { _, _ -> setResult(Result.FULL_ACCESS) dismiss() } - .setNegativeButton(R.string.storage_permission_media_read_only) { _, _ -> - setResult(Result.MEDIA_READ_ONLY) - dismiss() - } - .setNeutralButton(R.string.common_cancel) { _, _ -> + .setNegativeButton(R.string.permission_deny) { _, _ -> setResult(Result.CANCEL) dismiss() } - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), dialogBuilder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(requireContext(), dialogBuilder) return dialogBuilder.create() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt index 556dac4db784..e17b6a190b6c 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt @@ -20,6 +20,7 @@ import android.widget.AdapterView import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.SubFolderRule import com.nextcloud.utils.extensions.getParcelableArgument @@ -85,6 +86,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { nameCollisionPolicyItemStrings = resources.getTextArray(R.array.pref_name_collision_policy_entries) } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { Log_OC.d(TAG, "onCreateView, savedInstanceState is $savedInstanceState") binding = SyncedFoldersSettingsLayoutBinding.inflate(requireActivity().layoutInflater, null, false) @@ -95,7 +97,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { val builder = MaterialAlertDialogBuilder(requireContext()) builder.setView(binding!!.getRoot()) - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create() } @@ -144,6 +146,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { } } + @IonosCustomization() private fun applyUserColor(binding: SyncedFoldersSettingsLayoutBinding) { viewThemeUtils?.androidx?.colorSwitchCompat(binding.syncEnabled) @@ -155,9 +158,9 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantUploadExcludeHiddenCheckbox ) - viewThemeUtils?.material?.colorMaterialButtonPrimaryTonal(binding.btnPositive) - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNegative) - viewThemeUtils?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNeutral) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryTonal(binding.btnPositive) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNegative) + viewThemeUtils?.ionos?.material?.colorMaterialButtonPrimaryBorderless(binding.btnNeutral) } private fun setButtonOrder(binding: SyncedFoldersSettingsLayoutBinding) { @@ -401,6 +404,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding.settingInstantNameCollisionPolicyContainer.setOnClickListener { showNameCollisionPolicyDialog() } } + @IonosCustomization private fun showBehaviourDialog() { val builder = MaterialAlertDialogBuilder(requireActivity()) @@ -418,12 +422,13 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { } behaviourDialogShown = true - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) behaviourDialog = builder.create() behaviourDialog?.show() } + @IonosCustomization private fun showNameCollisionPolicyDialog() { syncedFolder?.let { val builder = MaterialAlertDialogBuilder(requireActivity()) @@ -437,7 +442,7 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { nameCollisionPolicyDialogShown = true - viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) + viewThemeUtils?.ionos?.dialog?.colorMaterialAlertDialogBackground(requireActivity(), builder) behaviourDialog = builder.create() behaviourDialog?.show() } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt index 0f67fe0053aa..55638034193c 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/setupEncryption/SetupEncryptionDialogFragment.kt @@ -20,6 +20,7 @@ import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import com.google.android.material.button.MaterialButton import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable import com.nextcloud.client.network.ClientFactory @@ -77,18 +78,19 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { executeTask() } + @IonosCustomization() private fun setupAlertDialog() { val alertDialog = dialog as AlertDialog? if (alertDialog != null) { positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as? MaterialButton? positiveButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryTonal(it) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryTonal(it) } negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as? MaterialButton? negativeButton?.let { - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(it) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(it) } } } @@ -98,6 +100,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { task?.execute() } + @IonosCustomization override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { checkNotNull(arguments) { "Arguments may not be null" } @@ -114,10 +117,10 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { binding = SetupEncryptionDialogBinding.inflate(inflater, null, false) // Setup layout - viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.encryptionPasswordInputContainer) val builder = buildMaterialAlertDialog(binding.root) - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(requireContext(), builder) return builder.create().apply { setCanceledOnTouchOutside(false) setOnShowListener { dialog1: DialogInterface -> @@ -494,6 +497,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { } @VisibleForTesting + @IonosCustomization fun showMnemonicInfo() { if (dialog == null) { Log_OC.e(TAG, "Dialog is null cannot proceed further.") @@ -501,7 +505,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { } requireDialog().setTitle(R.string.end_to_end_encryption_passphrase_title) binding.encryptionStatus.setText(R.string.end_to_end_encryption_keywords_description) - viewThemeUtils.material.colorTextInputLayout(binding.encryptionPasswordInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.encryptionPasswordInputContainer) binding.encryptionPassphrase.text = generateMnemonicString(true) binding.encryptionPassphrase.visibility = View.VISIBLE @@ -511,7 +515,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { positiveButton?.let { positiveButton -> negativeButton?.let { negativeButton -> - viewThemeUtils.platform.colorTextButtons(positiveButton, negativeButton) + viewThemeUtils.ionos.platform.colorTextButtons(positiveButton, negativeButton) } } @@ -519,6 +523,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { } @VisibleForTesting + @IonosCustomization fun errorSavingKeys() { if (dialog == null) { Log_OC.e(TAG, "Dialog is null cannot proceed further.") @@ -533,7 +538,7 @@ class SetupEncryptionDialogFragment : DialogFragment(), Injectable { positiveButton?.setText(R.string.end_to_end_encryption_dialog_close) positiveButton?.visibility = View.VISIBLE positiveButton?.let { - viewThemeUtils.platform.colorTextButtons(it) + viewThemeUtils.ionos.platform.colorTextButtons(it) } } 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 f38898d8da2e..617ae4249598 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 @@ -41,6 +41,7 @@ import android.widget.TextView; import com.google.android.material.button.MaterialButton; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.preferences.AppPreferences; @@ -107,7 +108,6 @@ public class ExtendedListFragment extends Fragment implements @Inject UserAccountManager accountManager; @Inject ViewThemeUtils viewThemeUtils; - private ScaleGestureDetector mScaleGestureDetector; protected SwipeRefreshLayout mRefreshListLayout; protected MaterialButton mSortButton; protected MaterialButton mSwitchGridViewButton; @@ -171,10 +171,10 @@ public boolean isGridEnabled() { } @Override + @IonosCustomization 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); @@ -319,6 +319,7 @@ public void onAttach(@NonNull Context context) { } @Override + @IonosCustomization public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log_OC.d(TAG, "onCreateView"); @@ -336,18 +337,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, mScale = preferences.getGridColumns(); setGridViewColumns(1f); - mScaleGestureDetector = new ScaleGestureDetector(MainApp.getAppContext(), new ScaleListener()); - - getRecyclerView().setOnTouchListener((view, motionEvent) -> { - mScaleGestureDetector.onTouchEvent(motionEvent); - - if (motionEvent.getAction() == MotionEvent.ACTION_UP) { - view.performClick(); - } - - return false; - }); - // Pull-down to refresh layout mRefreshListLayout = binding.swipeContainingList; viewThemeUtils.androidx.themeSwipeRefreshLayout(mRefreshListLayout); @@ -601,6 +590,7 @@ public void setMessageForEmptyList(@StringRes final int headline, @StringRes fin }); } + @IonosCustomization public void setEmptyListMessage(final SearchType searchType) { new Handler(Looper.getMainLooper()).post(() -> { if (searchType == SearchType.OFFLINE_MODE) { @@ -611,16 +601,15 @@ public void setEmptyListMessage(final SearchType searchType) { } else if (searchType == SearchType.NO_SEARCH) { setMessageForEmptyList(R.string.file_list_empty_headline, R.string.file_list_empty, - R.drawable.ic_list_empty_folder, - true); + R.drawable.ic_list_empty_folder); } else if (searchType == SearchType.FILE_SEARCH) { setMessageForEmptyList(R.string.file_list_empty_headline_server_search, R.string.file_list_empty, - R.drawable.ic_search_light_grey); + R.drawable.ic_search); } else if (searchType == SearchType.FAVORITE_SEARCH) { setMessageForEmptyList(R.string.file_list_empty_favorite_headline, R.string.file_list_empty_favorites_filter_list, - R.drawable.ic_star_light_yellow); + R.drawable.favorite); } else if (searchType == SearchType.RECENTLY_MODIFIED_SEARCH) { setMessageForEmptyList(R.string.file_list_empty_headline_server_search, R.string.file_list_empty_recently_modified, @@ -628,7 +617,7 @@ public void setEmptyListMessage(final SearchType searchType) { } else if (searchType == SearchType.REGULAR_FILTER) { setMessageForEmptyList(R.string.file_list_empty_headline_search, R.string.file_list_empty_search, - R.drawable.ic_search_light_grey); + R.drawable.ic_search); } else if (searchType == SearchType.SHARED_FILTER) { setMessageForEmptyList(R.string.file_list_empty_shared_headline, R.string.file_list_empty_shared, @@ -640,7 +629,7 @@ public void setEmptyListMessage(final SearchType searchType) { } else if (searchType == SearchType.LOCAL_SEARCH) { setMessageForEmptyList(R.string.file_list_empty_headline_server_search, R.string.file_list_empty_local_search, - R.drawable.ic_search_light_grey); + R.drawable.ic_search); } }); } @@ -684,18 +673,11 @@ public void onRefresh(boolean ignoreETag) { } @Override + @IonosCustomization public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); - - if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { - maxColumnSize = 10; - } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { - maxColumnSize = 5; - } - - if (isGridEnabled() && getColumnsCount() > maxColumnSize) { - ((GridLayoutManager) getRecyclerView().getLayoutManager()).setSpanCount(maxColumnSize); - } + mScale = preferences.getGridColumns(); + setGridViewColumns(1f); } protected void setGridSwitchButton() { 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 4b53078e5e9f..8dc485b519f5 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 @@ -18,6 +18,7 @@ import android.view.ViewGroup; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -110,6 +111,7 @@ public static FileDetailActivitiesFragment newInstance(OCFile file, User user) { } @Override + @IonosCustomization public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -164,7 +166,7 @@ public void onError(int error) { binding.submitComment.setOnClickListener(v -> submitComment()); - viewThemeUtils.material.colorTextInputLayout(binding.commentInputFieldContainer); + viewThemeUtils.ionos.material.colorTextInputLayout(binding.commentInputFieldContainer); DisplayUtils.setAvatar(user, this, 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 1c20e2e58a94..fd78fb968dbd 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 @@ -23,7 +23,7 @@ import com.google.android.material.chip.Chip; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.google.android.material.tabs.TabLayout; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -82,7 +82,6 @@ import androidx.annotation.Nullable; import androidx.core.content.res.ResourcesCompat; import androidx.fragment.app.FragmentManager; -import androidx.viewpager2.widget.ViewPager2; /** * This Fragment is used to display the details about a file. @@ -321,80 +320,15 @@ private void onOverflowIconClicked() { .show(fragmentManager, "actions"); } + @IonosCustomization("Hide tabs in IONOS") private void setupViewPager() { - binding.tabLayout.removeAllTabs(); - - binding.tabLayout.addTab(binding.tabLayout.newTab().setText(R.string.drawer_item_activities).setIcon(R.drawable.ic_activity)); - - - if (showSharingTab()) { - binding.tabLayout.addTab(binding.tabLayout.newTab().setText(R.string.share_dialog_title).setIcon(R.drawable.shared_via_users)); - } - - if (MimeTypeUtil.isImage(getFile())) { - binding.tabLayout.addTab(binding.tabLayout.newTab().setText(R.string.filedetails_details).setIcon(R.drawable.image_32dp)); - } - - viewThemeUtils.material.themeTabLayout(binding.tabLayout); + binding.tabLayout.setVisibility(View.GONE); final FileDetailTabAdapter adapter = new FileDetailTabAdapter(requireActivity(), getFile(), user, showSharingTab()); binding.pager.setAdapter(adapter); - - binding.pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - final FileDetailActivitiesFragment fragment = getFileDetailActivitiesFragment(); - if (activeTab == 0 && fragment != null) { - fragment.markCommentsAsRead(); - } - super.onPageScrolled(position, positionOffset, positionOffsetPixels); - } - - @Override - public void onPageSelected(int position) { - super.onPageSelected(position); - if (binding != null) { - final var tab = binding.tabLayout.getTabAt(position); - if (tab != null) { - tab.select(); - } - } - } - }); - - binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { - @Override - public void onTabSelected(TabLayout.Tab tab) { - binding.pager.setCurrentItem(tab.getPosition()); - if (tab.getPosition() == 0) { - final FileDetailActivitiesFragment fragment = getFileDetailActivitiesFragment(); - if (fragment != null) { - fragment.markCommentsAsRead(); - } - } - } - - @Override - public void onTabUnselected(TabLayout.Tab tab) { - // unused at the moment - } - - @Override - public void onTabReselected(TabLayout.Tab tab) { - // unused at the moment - } - }); - - binding.tabLayout.post(() -> { - if (binding != null) { - TabLayout.Tab tab = binding.tabLayout.getTabAt(activeTab); - if (tab == null) return; - tab.select(); - } - }); } @Override @@ -842,8 +776,8 @@ public void initiateSharingProcess(String shareeName, * * @param isFragmentReplaced */ + @IonosCustomization("Hide tabs in IONOS") public void showHideFragmentView(boolean isFragmentReplaced) { - binding.tabLayout.setVisibility(isFragmentReplaced ? View.GONE : View.VISIBLE); binding.pager.setVisibility(isFragmentReplaced ? View.GONE : View.VISIBLE); binding.sharingFrameContainer.setVisibility(isFragmentReplaced ? View.VISIBLE : View.GONE); FloatingActionButton mFabMain = requireActivity().findViewById(R.id.fab_main); 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 1d6b78a4361a..c91c99f358fb 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 @@ -31,6 +31,7 @@ import android.view.View; import android.view.ViewGroup; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -233,6 +234,7 @@ public void onStop() { searchConfig.reset(); } + @IonosCustomization private void setupView() { setShareWithYou(); @@ -242,7 +244,6 @@ private void setupView() { (SearchManager) fileActivity.getSystemService(Context.SEARCH_SERVICE), binding.searchView, fileActivity.getComponentName()); - viewThemeUtils.androidx.themeToolbarSearchView(binding.searchView); viewThemeUtils.material.colorMaterialTextButton(binding.sharesListInternalShowAll); binding.sharesListInternalShowAll.setOnClickListener(view -> { @@ -284,7 +285,7 @@ private void setupView() { } } else { binding.createLink.setText(R.string.create_link); - binding.searchView.setQueryHint(getResources().getString(R.string.share_search_internal)); + binding.searchView.setQueryHint(getResources().getString(R.string.ionos_share_search)); } binding.createLink.setOnClickListener(v -> createPublicShareLink()); 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 be6779b9573a..32674c5d298f 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 @@ -12,10 +12,10 @@ 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.ionos.annotation.IonosCustomization; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.databinding.FileDetailsSharingMenuBottomSheetFragmentBinding; import com.owncloud.android.lib.resources.shares.OCShare; @@ -43,21 +43,13 @@ public FileDetailSharingMenuBottomSheetDialog(FileActivity fileActivity, } @Override + @IonosCustomization("Remove custom window LayoutParams. Disable icon tinting") protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = FileDetailsSharingMenuBottomSheetFragmentBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - if (getWindow() != null) { - getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - } - - viewThemeUtils.platform.themeDialog(binding.getRoot()); - - viewThemeUtils.platform.colorImageView(binding.menuIconAdvancedPermissions); - viewThemeUtils.platform.colorImageView(binding.menuIconSendLink); - viewThemeUtils.platform.colorImageView(binding.menuIconUnshare); - viewThemeUtils.platform.colorImageView(binding.menuIconSendNewEmail); + viewThemeUtils.ionos.platform.themeDialog(binding.getRoot()); updateUI(); 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 d82e6200629b..8bc82bd29c52 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 @@ -18,6 +18,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.di.Injectable import com.nextcloud.utils.extensions.getParcelableArgument import com.nextcloud.utils.extensions.getSerializableArgument @@ -189,6 +190,7 @@ class FileDetailsSharingProcessFragment : themeView() } + @IonosCustomization private fun themeView() { viewThemeUtils.platform.colorTextView(binding.shareProcessEditShareLink) viewThemeUtils.platform.colorTextView(binding.shareProcessAdvancePermissionTitle) @@ -205,13 +207,13 @@ class FileDetailsSharingProcessFragment : viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessHideDownloadCheckbox) viewThemeUtils.androidx.colorSwitchCompat(binding.shareProcessChangeNameSwitch) - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer) - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessSetDownloadLimitInputContainer) - viewThemeUtils.material.colorTextInputLayout(binding.shareProcessChangeNameContainer) - viewThemeUtils.material.colorTextInputLayout(binding.noteContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.shareProcessEnterPasswordContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.shareProcessSetDownloadLimitInputContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.shareProcessChangeNameContainer) + viewThemeUtils.ionos.material.colorTextInputLayout(binding.noteContainer) - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext) - viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.shareProcessBtnCancel) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryFilled(binding.shareProcessBtnNext) + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryOutlined(binding.shareProcessBtnCancel) } override fun onConfigurationChanged(newConfig: Configuration) { 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 b264078da243..9cdd44ec3250 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 @@ -22,6 +22,7 @@ import android.view.View; import android.view.ViewGroup; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.owncloud.android.BuildConfig; import com.owncloud.android.R; @@ -35,7 +36,6 @@ import com.owncloud.android.ui.activity.ToolbarActivity; import com.owncloud.android.ui.adapter.CommonOCFileListAdapterInterface; import com.owncloud.android.ui.adapter.GalleryAdapter; -import com.owncloud.android.ui.adapter.OCFileListDelegate; import com.owncloud.android.ui.asynctasks.GallerySearchTask; import com.owncloud.android.ui.events.ChangeMenuEvent; @@ -68,7 +68,8 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme @Inject FileDataStorageManager fileDataStorageManager; private final static int maxColumnSizeLandscape = 5; - private final static int maxColumnSizePortrait = 2; + @IonosCustomization("increased quantity") + private final static int maxColumnSizePortrait = 3; private int columnSize; protected void setPhotoSearchQueryRunning(boolean value) { 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 178c5e6bb3c3..9d54fc804a1e 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 @@ -13,7 +13,10 @@ import android.os.Bundle import android.view.LayoutInflater 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.android.material.bottomsheet.BottomSheetDialogFragment +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.client.di.Injectable import com.owncloud.android.R @@ -32,6 +35,9 @@ class GalleryFragmentBottomSheetDialog( override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentGalleryBottomSheetBinding.inflate(layoutInflater, container, false) + val bottomSheetDialog = dialog as BottomSheetDialog + bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED + bottomSheetDialog.behavior.skipCollapsed = true return binding.root } @@ -41,23 +47,9 @@ class GalleryFragmentBottomSheetDialog( setupClickListener() } + @IonosCustomization private fun setupLayout() { - viewThemeUtils.platform.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) - - listOf( - binding.tickMarkShowImages, - binding.tickMarkShowVideos - ).forEach { - viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) - } - - listOf( - binding.btnSelectMediaFolder, - binding.btnHideVideos, - binding.btnHideImages - ).forEach { - viewThemeUtils.material.colorMaterialButtonText(it) - } + viewThemeUtils.ionos.platform.colorViewBackground(binding.bottomSheet, ColorRole.SURFACE) when (currentMediaState) { MediaState.MEDIA_STATE_PHOTOS_ONLY -> { 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 e82f04e04129..1fccb802dc48 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 @@ -20,6 +20,7 @@ import android.view.View; import android.view.ViewGroup; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.R; @@ -91,16 +92,17 @@ public void onAttach(@NonNull Activity activity) { * {@inheritDoc} */ @Override + @IonosCustomization public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log_OC.i(TAG, "onCreateView() start"); View v = super.onCreateView(inflater, container, savedInstanceState); if (!mContainerActivity.isFolderPickerMode()) { setMessageForEmptyList(R.string.file_list_empty_headline, R.string.local_file_list_empty, - R.drawable.ic_list_empty_folder, true); + R.drawable.ic_list_empty_folder); } else { setMessageForEmptyList(R.string.folder_list_empty_headline, R.string.local_folder_list_empty, - R.drawable.ic_list_empty_folder, true); + R.drawable.ic_list_empty_folder); } setSwipeEnabled(false); // Disable pull-to-refresh @@ -114,6 +116,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, * {@inheritDoc} */ @Override + @IonosCustomization public void onActivityCreated(Bundle savedInstanceState) { Log_OC.i(TAG, "onActivityCreated() start"); @@ -136,7 +139,7 @@ public void onActivityCreated(Bundle savedInstanceState) { }); FileSortOrder sortOrder = preferences.getSortOrderByType(FileSortOrder.Type.localFileListView); - mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); + mSortButton.setIconResource(DisplayUtils.getSortOrderIconRes(sortOrder)); setGridSwitchButton(); mSwitchGridViewButton.setOnClickListener(v -> { @@ -303,8 +306,9 @@ public int getFilesCount() { return mAdapter.getFilesCount(); } + @IonosCustomization public void sortFiles(FileSortOrder sortOrder) { - mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); + mSortButton.setIconResource(DisplayUtils.getSortOrderIconRes(sortOrder)); mAdapter.setSortOrder(sortOrder); } 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 556cbbcc6637..8b41290de5c0 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 @@ -41,6 +41,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; +import com.ionos.scanbot.controller.ScanbotController; import com.nextcloud.android.lib.resources.files.ToggleFileLockRemoteOperation; import com.nextcloud.android.lib.resources.recommendations.GetRecommendationsRemoteOperation; import com.nextcloud.android.lib.richWorkspace.RichWorkspaceDirectEditingRemoteOperation; @@ -49,7 +51,6 @@ import com.nextcloud.client.device.DeviceInfo; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.documentscan.AppScanOptionalFeature; -import com.nextcloud.client.documentscan.DocumentScanActivity; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.jobs.BackgroundJobManager; import com.nextcloud.client.network.ClientFactory; @@ -219,6 +220,7 @@ public class OCFileListFragment extends ExtendedListFragment implements @Inject ShortcutUtil shortcutUtil; @Inject SyncedFolderProvider syncedFolderProvider; @Inject AppScanOptionalFeature appScanOptionalFeature; + @Inject ScanbotController scanbotController; protected FileFragment.ContainerActivity mContainerActivity; @@ -314,6 +316,7 @@ public void onAttach(@NonNull Context context) { * {@inheritDoc} */ @Override + @IonosCustomization public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log_OC.i(TAG, "onCreateView() start"); View v = super.onCreateView(inflater, container, savedInstanceState); @@ -337,11 +340,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, mFabMain = requireActivity().findViewById(R.id.fab_main); - if (mFabMain != null) { - // is not available in FolderPickerActivity - viewThemeUtils.material.themeFAB(mFabMain); - } - Log_OC.i(TAG, "onCreateView() end"); return v; } @@ -516,24 +514,21 @@ protected void prepareCurrentSearch(SearchEvent event) { /** * register listener on FAB. */ + @IonosCustomization("Show simple FAB menu bottom sheet") public void registerFabListener() { FileActivity activity = (FileActivity) getActivity(); if (mFabMain != null) { // is not available in FolderPickerActivity - viewThemeUtils.material.themeFAB(mFabMain); mFabMain.setOnClickListener(v -> { PermissionUtil.requestMediaLocationPermission(activity); - final OCFileListBottomSheetDialog dialog = - new OCFileListBottomSheetDialog(activity, + final SimpleOCFileListBottomSheetDialog dialog = + new SimpleOCFileListBottomSheetDialog(activity, this, deviceInfo, - accountManager.getUser(), - getCurrentFile(), themeUtils, viewThemeUtils, - editorUtils, appScanOptionalFeature); dialog.getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED); @@ -578,6 +573,7 @@ public void directCameraUpload() { showDirectCameraUploadAlertDialog(fileDisplayActivity); } + @IonosCustomization private void showDirectCameraUploadAlertDialog(FileDisplayActivity fileDisplayActivity) { final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(fileDisplayActivity) .setTitle(R.string.upload_direct_camera_promt) @@ -585,7 +581,7 @@ private void showDirectCameraUploadAlertDialog(FileDisplayActivity fileDisplayAc .setPositiveButton(R.string.upload_direct_camera_video, (dialog, which) -> fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity, FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_VIDEO_CAMERA, true)) .setNegativeButton(R.string.upload_direct_camera_photo, (dialog, which) -> fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity, FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA, false)); - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(fileDisplayActivity, builder); + viewThemeUtils.ionos.dialog.colorMaterialAlertDialogBackground(fileDisplayActivity, builder); builder.create(); builder.show(); @@ -598,9 +594,9 @@ public void scanDocUpload() { final OCFile currentFile = getCurrentFile(); if (fileDisplayActivity != null && currentFile != null && currentFile.isFolder()) { - Intent intent = new Intent(requireContext(), DocumentScanActivity.class); - intent.putExtra(DocumentScanActivity.EXTRA_FOLDER, currentFile.getRemotePath()); - startActivity(intent); +// Intent intent = new Intent(requireContext(), DocumentScanActivity.class); +// intent.putExtra(DocumentScanActivity.EXTRA_FOLDER, currentFile.getRemotePath()); + scanbotController.scanToDocument(requireContext(), currentFile.getRemotePath()); } else { Log.w(TAG, "scanDocUpload: Failed to start doc scanning, fileDisplayActivity=" + fileDisplayActivity + ", currentFile=" + currentFile); @@ -814,6 +810,7 @@ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, bo * Load menu and customize UI when action mode is started. */ @Override + @IonosCustomization public boolean onCreateActionMode(ActionMode mode, Menu menu) { mActiveActionMode = mode; // Determine if actionMode is "new" or not (already affected by item-selection) @@ -822,8 +819,6 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) { // fake menu to be able to use bottom sheet instead MenuInflater inflater = getActivity().getMenuInflater(); inflater.inflate(R.menu.custom_menu_placeholder, menu); - final MenuItem item = menu.findItem(R.id.custom_menu_placeholder_item); - item.setIcon(viewThemeUtils.platform.colorDrawable(item.getIcon(), ContextCompat.getColor(requireContext(), R.color.white))); mode.invalidate(); //set actionMode color @@ -883,7 +878,7 @@ public void onDestroyActionMode(ActionMode mode) { Activity activity = getActivity(); if (activity != null) { - viewThemeUtils.platform.resetStatusBar(activity); + viewThemeUtils.ionos.platform.resetSystemBars(activity); } getCommonAdapter().setMultiSelect(false); @@ -1604,6 +1599,7 @@ public void updateOCFile(@NonNull OCFile file) { mAdapter.notifyItemChanged(file); } + @IonosCustomization private void updateLayout() { // decide grid vs list view if (isGridViewPreferred(mFile)) { @@ -1613,7 +1609,7 @@ private void updateLayout() { } if (mSortButton != null) { - mSortButton.setText(DisplayUtils.getSortOrderStringId(preferences.getSortOrderByFolder(mFile))); + mSortButton.setIconResource(DisplayUtils.getSortOrderIconRes(preferences.getSortOrderByFolder(mFile))); } if (mSwitchGridViewButton != null) { setGridSwitchButton(); @@ -1638,8 +1634,9 @@ private void invalidateActionMode() { } } + @IonosCustomization public void sortFiles(FileSortOrder sortOrder) { - mSortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); + mSortButton.setIconResource(DisplayUtils.getSortOrderIconRes(sortOrder)); mAdapter.setSortOrder(mFile, sortOrder); } @@ -2211,6 +2208,7 @@ public boolean isLoading() { * * @param visible Desired visibility for the FAB. */ + @IonosCustomization public void setFabVisible(final boolean visible) { if (mFabMain == null) { // is not available in FolderPickerActivity @@ -2221,7 +2219,6 @@ public void setFabVisible(final boolean visible) { getActivity().runOnUiThread(() -> { if (visible) { mFabMain.show(); - viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.hide(); } @@ -2261,6 +2258,7 @@ private void showFabWithBehavior(boolean visible) { * * @param enabled Desired visibility for the FAB. */ + @IonosCustomization public void setFabEnabled(final boolean enabled) { if (mFabMain == null) { // is not available in FolderPickerActivity @@ -2271,10 +2269,8 @@ public void setFabEnabled(final boolean enabled) { getActivity().runOnUiThread(() -> { if (enabled) { mFabMain.setEnabled(true); - viewThemeUtils.material.themeFAB(mFabMain); } else { mFabMain.setEnabled(false); - 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 292818ec3df0..523e94c0fbc0 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 @@ -50,7 +50,7 @@ class ProfileBottomSheetDialog( window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } - viewThemeUtils.platform.themeDialog(binding.root) + viewThemeUtils.ionos.platform.themeDialog(binding.root) binding.icon.tag = hoverCard.userId DisplayUtils.setAvatar( 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 820a6b0a7f22..dc7cab66d5de 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 @@ -12,10 +12,10 @@ 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.ionos.annotation.IonosCustomization; import com.owncloud.android.R; import com.owncloud.android.databinding.QuickSharingPermissionsBottomSheetFragmentBinding; import com.owncloud.android.datamodel.QuickPermissionModel; @@ -57,16 +57,13 @@ public QuickSharingPermissionsBottomSheetDialog(FileActivity fileActivity, } @Override + @IonosCustomization("Remove custom window LayoutParams") protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = QuickSharingPermissionsBottomSheetFragmentBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); - if (getWindow() != null) { - getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - } - - viewThemeUtils.platform.themeDialog(binding.getRoot()); + viewThemeUtils.ionos.platform.themeDialog(binding.getRoot()); setUpRecyclerView(); setOnShowListener(d -> diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/SimpleOCFileListBottomSheetDialog.java b/app/src/main/java/com/owncloud/android/ui/fragment/SimpleOCFileListBottomSheetDialog.java new file mode 100644 index 000000000000..13ca7c841094 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/fragment/SimpleOCFileListBottomSheetDialog.java @@ -0,0 +1,106 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.ui.fragment; + +import android.os.Bundle; +import android.view.View; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.nextcloud.android.common.ui.theme.utils.ColorRole; +import com.nextcloud.client.device.DeviceInfo; +import com.nextcloud.client.di.Injectable; +import com.nextcloud.client.documentscan.AppScanOptionalFeature; +import com.owncloud.android.R; +import com.owncloud.android.databinding.SimpleFileListActionsBottomSheetFragmentBinding; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.utils.theme.ThemeUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; + +/** + * Simple FAB menu {@link android.app.Dialog} styled as a bottom sheet for main actions. + */ +public class SimpleOCFileListBottomSheetDialog extends BottomSheetDialog implements Injectable { + + private SimpleFileListActionsBottomSheetFragmentBinding binding; + private final OCFileListBottomSheetActions actions; + private final DeviceInfo deviceInfo; + private final ThemeUtils themeUtils; + private final ViewThemeUtils viewThemeUtils; + + private final AppScanOptionalFeature appScanOptionalFeature; + + + public SimpleOCFileListBottomSheetDialog(FileActivity fileActivity, + OCFileListBottomSheetActions actions, + DeviceInfo deviceInfo, + ThemeUtils themeUtils, + ViewThemeUtils viewThemeUtils, + AppScanOptionalFeature appScanOptionalFeature) { + super(fileActivity); + this.actions = actions; + this.deviceInfo = deviceInfo; + this.themeUtils = themeUtils; + this.viewThemeUtils = viewThemeUtils; + this.appScanOptionalFeature = appScanOptionalFeature; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = SimpleFileListActionsBottomSheetFragmentBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + viewThemeUtils.ionos.platform.colorViewBackground(binding.getRoot(), ColorRole.SURFACE); + + binding.addToCloud.setText(getContext().getResources().getString(R.string.add_to_cloud, + themeUtils.getDefaultDisplayNameForRootFolder(getContext()))); + + if (!deviceInfo.hasCamera(getContext())) { + binding.menuDirectCameraUpload.setVisibility(View.GONE); + } + + setupClickListener(); + } + + private void setupClickListener() { + binding.menuMkdir.setOnClickListener(v -> { + actions.createFolder(); + dismiss(); + }); + + binding.menuUploadFromApp.setOnClickListener(v -> { + actions.uploadFromApp(); + dismiss(); + }); + + binding.menuDirectCameraUpload.setOnClickListener(v -> { + actions.directCameraUpload(); + dismiss(); + }); + + if (appScanOptionalFeature.isAvailable()) { + binding.menuScanDocUpload.setOnClickListener(v -> { + actions.scanDocUpload(); + dismiss(); + }); + } else { + binding.menuScanDocUpload.setVisibility(View.GONE); + } + + binding.menuUploadFiles.setOnClickListener(v -> { + actions.uploadFiles(); + dismiss(); + }); + } + + @Override + protected void onStop() { + super.onStop(); + binding = null; + } +} 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 a158c8052948..ad096c973bfb 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 @@ -24,6 +24,7 @@ import androidx.core.view.updatePadding import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.GridLayoutManager +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.AsyncRunner @@ -140,7 +141,7 @@ class UnifiedSearchFragment : setupFileDisplayActivity() setupAdapter() if (supportsOpeningCalendarContactsLocally()) { - checkPermissions() + // checkPermissions() } } @@ -170,12 +171,12 @@ class UnifiedSearchFragment : } } + @IonosCustomization private fun setupSearchView(item: MenuItem) { (item.actionView as? SearchView?)?.run { // Required to align with TextView width. // Because this fragment is opened with TextView onClick on the previous screen maxWidth = Integer.MAX_VALUE - viewThemeUtils.androidx.themeToolbarSearchView(this) setQuery(vm.query.value, false) setOnQueryTextListener(this@UnifiedSearchFragment) isIconified = false @@ -183,6 +184,7 @@ class UnifiedSearchFragment : } } + @IonosCustomization private fun setUpViewModel() { vm.searchResults.observe(this, this::onSearchResultChanged) vm.isLoading.observe(this) { loading -> @@ -208,9 +210,7 @@ class UnifiedSearchFragment : requireContext().getString(R.string.file_list_empty_headline_server_search) binding.emptyList.emptyListViewText.text = requireContext().getString(R.string.file_list_empty_unified_search_no_results) - binding.emptyList.emptyListIcon.setImageDrawable( - viewThemeUtils.platform.tintDrawable(requireContext(), R.drawable.ic_search_grey) - ) + binding.emptyList.emptyListIcon.setImageResource(R.drawable.ic_search) } } } diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt index 52e7d03b695b..231573ae306c 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/fragment/contactsbackup/BackupFragment.kt @@ -24,6 +24,7 @@ import android.widget.CompoundButton import android.widget.DatePicker import android.widget.Toast import androidx.core.app.ActivityCompat +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable import com.nextcloud.client.jobs.BackgroundJobManager @@ -220,16 +221,8 @@ class BackupFragment : FileFragment(), OnDateSetListener, Injectable { } } + @IonosCustomization private fun applyUserColor() { - viewThemeUtils.androidx.colorSwitchCompat(binding.contacts) - viewThemeUtils.androidx.colorSwitchCompat(binding.calendar) - viewThemeUtils.androidx.colorSwitchCompat(binding.dailyBackup) - - viewThemeUtils.material.colorMaterialButtonPrimaryFilled(binding.backupNow) - viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.contactsDatepicker) - - viewThemeUtils.platform.colorTextView(binding.dataToBackUpTitle) - viewThemeUtils.platform.colorTextView(binding.backupSettingsTitle) } override fun onResume() { @@ -493,6 +486,7 @@ class BackupFragment : FileFragment(), OnDateSetListener, Injectable { } } + @IonosCustomization private fun openDate(savedDate: Calendar?) { val contactsPreferenceActivity = activity as ContactsPreferenceActivity? if (contactsPreferenceActivity == null) { @@ -529,10 +523,6 @@ class BackupFragment : FileFragment(), OnDateSetListener, Injectable { show() } - viewThemeUtils.platform.colorTextButtons( - datePickerDialog!!.getButton(DatePickerDialog.BUTTON_NEGATIVE), - datePickerDialog!!.getButton(DatePickerDialog.BUTTON_POSITIVE) - ) } else { DisplayUtils.showSnackMessage( requireView().findViewById(R.id.contacts_linear_layout), 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 0d11a6e57c7f..1bb48b39436b 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 @@ -21,6 +21,7 @@ import android.widget.Toast; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -114,6 +115,7 @@ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflat inflater.inflate(R.menu.fragment_contact_list, menu); } + @IonosCustomization("colorMaterialButtonPrimaryBorderless") @Override public View onCreateView(@NonNull final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -235,7 +237,7 @@ public View onCreateView(@NonNull final LayoutInflater inflater, ViewGroup conta closeFragment(); }); - viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.restoreSelected); + viewThemeUtils.ionos.material.colorMaterialButtonPrimaryBorderless(binding.restoreSelected); return view; } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt index c2580868bc35..63fcae6aa0e9 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.kt @@ -24,6 +24,7 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.di.Injectable import com.nextcloud.client.editimage.EditImageActivity @@ -55,6 +56,12 @@ import com.owncloud.android.ui.fragment.OCFileListFragment import com.owncloud.android.ui.preview.model.PreviewImageActivityState import com.owncloud.android.utils.DisplayUtils import com.owncloud.android.utils.MimeTypeUtil +import android.graphics.drawable.ColorDrawable +import android.view.ViewGroup +import androidx.activity.enableEdgeToEdge +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.updatePadding import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import java.io.Serializable import javax.inject.Inject @@ -83,10 +90,22 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR lateinit var localBroadcastManager: LocalBroadcastManager private var actionBar: ActionBar? = null + private var showDirectoryWhenDeletionCompleted = false + @IonosCustomization override fun onCreate(savedInstanceState: Bundle?) { + enableEdgeToEdge() super.onCreate(savedInstanceState) + val contentContainer = (window.decorView as ViewGroup).getChildAt(0) + ViewCompat.setOnApplyWindowInsetsListener(contentContainer) { view, windowInsets -> + val insetsType = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() + val insets = windowInsets.getInsets(insetsType) + val actionBarView = view.findViewById(androidx.appcompat.R.id.action_bar) + actionBarView?.updatePadding(left = insets.left, top = insets.top, right = insets.right) + WindowInsetsCompat.CONSUMED + } + actionBar = supportActionBar if (savedInstanceState != null && !savedInstanceState.getBoolean( @@ -106,8 +125,10 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR val chosenFile = intent.getParcelableArgument(EXTRA_FILE, OCFile::class.java) updateActionBarTitleAndHomeButton(chosenFile) + viewThemeUtils.ionos.platform.themeSystemBars(this, getColor(R.color.preview_image_system_bars_color)) if (actionBar != null) { viewThemeUtils.files.setWhiteBackButton(this, actionBar!!) + actionBar?.setBackgroundDrawable(ColorDrawable(getColor(R.color.preview_image_system_bars_color))) actionBar?.setDisplayHomeAsUpEnabled(true) } @@ -123,6 +144,13 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR observeWorkerState() } + @IonosCustomization("Remove default window insets paddings") + override fun isDefaultWindowInsetsHandlingEnabled() = false + + fun showDirectoryWhenDeletionCompleted() { + showDirectoryWhenDeletionCompleted = true + } + fun toggleActionBarVisibility(hide: Boolean) { if (actionBar == null) { return @@ -486,10 +514,15 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR fun toggleFullScreen() { if (fullScreenAnchorView == null) return - val visible = ( - fullScreenAnchorView!!.systemUiVisibility - and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - ) == 0 + val visible = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val insets = window.decorView.rootWindowInsets + insets.isVisible(WindowInsets.Type.statusBars()) + || insets.isVisible(WindowInsets.Type.navigationBars()) + } else { + @Suppress("DEPRECATION") + (fullScreenAnchorView!!.systemUiVisibility + and View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 + } if (visible) { hideSystemUI(fullScreenAnchorView!!) @@ -535,6 +568,7 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR private fun hideSystemUI(anchorView: View) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + actionBar?.hide() window.insetsController?.let { controller -> controller.hide(WindowInsets.Type.systemBars()) controller.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE @@ -554,6 +588,7 @@ class PreviewImageActivity : FileActivity(), FileFragment.ContainerActivity, OnR private fun showSystemUI(anchorView: View) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + actionBar?.show() window.insetsController?.let { controller -> controller.show(WindowInsets.Type.systemBars()) diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt index 91a4f16b3c89..43b6eac71e98 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.kt @@ -43,6 +43,7 @@ import com.caverock.androidsvg.SVG import com.caverock.androidsvg.SVGParseException import com.github.chrisbanes.photoview.PhotoView import com.google.android.material.snackbar.Snackbar +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable import com.nextcloud.client.jobs.BackgroundJobManager @@ -262,6 +263,7 @@ class PreviewImageFragment : FileFragment(), Injectable { } } + @IonosCustomization private fun adjustResizedImage(thumbnail: Bitmap?, width: Int, height: Int) { var resizedImage = getResizedBitmap(file, width, height) @@ -270,7 +272,7 @@ class PreviewImageFragment : FileFragment(), Injectable { binding.image.visibility = View.VISIBLE binding.emptyListView.visibility = View.GONE binding.emptyListProgress.visibility = View.GONE - binding.image.setBackgroundColor(resources.getColor(R.color.background_color_inverse)) + binding.image.setBackgroundColor(resources.getColor(R.color.preview_image_background)) bitmap = resizedImage } else { @@ -286,7 +288,7 @@ class PreviewImageFragment : FileFragment(), Injectable { containerActivity.storageManager, connectivityService, containerActivity.storageManager.user, - resources.getColor(R.color.background_color_inverse) + resources.getColor(R.color.preview_image_background) ) if (resizedImage == null) { resizedImage = thumbnail @@ -589,6 +591,7 @@ class PreviewImageFragment : FileFragment(), Injectable { } } + @IonosCustomization private fun showLoadedImage(result: LoadImage?) { val imageView = imageViewRef.get() val bitmap = result?.bitmap @@ -630,7 +633,7 @@ class PreviewImageFragment : FileFragment(), Injectable { val progressView = progressViewRef.get() progressView?.visibility = View.GONE - imageView.setBackgroundColor(resources.getColor(R.color.background_color_inverse)) + imageView.setBackgroundColor(resources.getColor(R.color.preview_image_background)) imageView.visibility = View.VISIBLE } } diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt index 1f892cf18122..19f8c5381eac 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewMediaActivity.kt @@ -60,6 +60,7 @@ import androidx.media3.ui.PlayerView import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.MoreExecutors +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.User import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.di.Injectable @@ -185,6 +186,9 @@ class PreviewMediaActivity : } } + @IonosCustomization("Remove default window insets paddings") + override fun isDefaultWindowInsetsHandlingEnabled() = false + private fun sendAudioSessionReleaseBroadcast() { val intent = Intent(BackgroundPlayerService.RELEASE_MEDIA_SESSION_BROADCAST_ACTION).apply { setPackage(packageName) @@ -249,6 +253,7 @@ class PreviewMediaActivity : private fun isFileVideo(): Boolean = MimeTypeUtil.isVideo(file) + @IonosCustomization("System bar colors") private fun configureSystemBars() { updateActionBarTitleAndHomeButton(file) @@ -269,13 +274,17 @@ class PreviewMediaActivity : ?.apply { setTint(Color.WHITE) } ) - it.setBackgroundDrawable(ColorDrawable(Color.BLACK)) + it.setBackgroundDrawable(ColorDrawable(getColor(R.color.exo_bottom_bar_background))) + + viewThemeUtils.ionos.platform.themeSystemBars(this, getColor(R.color.transparent)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + window.isNavigationBarContrastEnforced = false + } + + } else { + viewThemeUtils.ionos.platform.themeSystemBars(this) } } - - viewThemeUtils.platform.themeStatusBar( - this - ) } private fun showProgressLayout() { @@ -290,6 +299,7 @@ class PreviewMediaActivity : binding.emptyView.emptyListView.visibility = View.VISIBLE } + @IonosCustomization("ui bugfix") private fun setErrorMessage(headline: String, @StringRes message: Int) { binding.emptyView.run { emptyListViewHeadline.text = headline @@ -297,8 +307,7 @@ class PreviewMediaActivity : emptyListIcon.setImageResource(R.drawable.file_movie) emptyListViewText.visibility = View.VISIBLE emptyListIcon.visibility = View.VISIBLE - - hideProgressLayout() + binding.progress.visibility = View.GONE } } @@ -306,15 +315,9 @@ class PreviewMediaActivity : binding.imagePreview.setImageDrawable(genericThumbnail()) } + @IonosCustomization("No generic thumbnail") private fun genericThumbnail(): Drawable? { - val result = AppCompatResources.getDrawable(this, R.drawable.logo) - result?.let { - if (!resources.getBoolean(R.bool.is_branded_client)) { - DrawableCompat.setTint(it, resources.getColor(R.color.primary, this.theme)) - } - } - - return result + return null } override fun onSaveInstanceState(outState: Bundle) { @@ -490,6 +493,7 @@ class PreviewMediaActivity : } } + @IonosCustomization("Insets for media controller") private fun applyWindowInsets() { val playerView = binding.exoplayerView val exoControls = playerView.findViewById(R.id.exo_bottom_bar) @@ -502,22 +506,21 @@ class PreviewMediaActivity : .displayCutout() ) - binding.materialToolbar.updateLayoutParams { - topMargin = insets.top - } exoControls.updateLayoutParams { - bottomMargin = insets.bottom + height = insets.bottom + resources.getDimensionPixelSize(R.dimen.exo_bottom_bar_height) } exoProgress.updateLayoutParams { bottomMargin = insets.bottom + progressBottomMargin } exoControls.updatePadding(left = insets.left, right = insets.right) + binding.audioControllerView.updatePadding(left = insets.left, right = insets.right, bottom = insets.bottom) exoProgress.updatePadding(left = insets.left, right = insets.right) - binding.materialToolbar.updatePadding(left = insets.left, right = insets.right) + binding.materialToolbar.updatePadding(left = insets.left, top = insets.top, right = insets.right) WindowInsetsCompat.CONSUMED } } + @IonosCustomization("Hide cantrolls animation fix") private fun setupVideoView() { initWindowInsetsController() val type = WindowInsetsCompat.Type.systemBars() @@ -533,6 +536,12 @@ class PreviewMediaActivity : windowInsetsController.hide(type) supportActionBar!!.hide() } + val bottomBarMainControls = it.findViewById(R.id.exo_bottom_bar_main_controls) + if (it.isControllerFullyVisible) { + bottomBarMainControls?.visibility = View.VISIBLE + } else { + bottomBarMainControls?.visibility = View.INVISIBLE + } } ) it.player = videoPlayer @@ -711,16 +720,19 @@ class PreviewMediaActivity : } @Suppress("TooGenericExceptionCaught") + @IonosCustomization("Better UX") private fun playVideo() { setupVideoView() - if (file.isDown) { - prepareVideoPlayer(file.storageUri) - } else { - try { - LoadStreamUrl(this, user, clientFactory).execute(file.localId) - } catch (e: Exception) { - Log_OC.e(TAG, "Loading stream url for Video not possible: $e") + if(videoPlayer?.currentMediaItem == null) { + if (file.isDown) { + prepareVideoPlayer(file.storageUri) + } else { + try { + LoadStreamUrl(this, user, clientFactory).execute(file.localId) + } catch (e: Exception) { + Log_OC.e(TAG, "Loading stream url for Video not possible: $e") + } } } } @@ -797,17 +809,19 @@ class PreviewMediaActivity : Log_OC.v(TAG, "onResume") } + @IonosCustomization("Stopping audio on latter lifecycle stage") override fun onDestroy() { + releaseVideoPlayer() mediaControllerFuture?.let { MediaController.releaseFuture(it) } super.onDestroy() Log_OC.v(TAG, "onDestroy") } + @IonosCustomization("Keeping audio/video playing in background") override fun onStop() { Log_OC.v(TAG, "onStop") - releaseVideoPlayer() super.onStop() } 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 410173d0fab6..17848a27c186 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 @@ -17,6 +17,7 @@ import android.widget.FrameLayout; import android.widget.TextView; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.nextcloud.ui.fileactions.FileActionsBottomSheet; import com.nextcloud.utils.extensions.BundleExtensionsKt; @@ -240,6 +241,7 @@ protected void onPostExecute(final StringWriter stringWriter) { * {@inheritDoc} */ @Override + @IonosCustomization public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.custom_menu_placeholder, menu); @@ -248,7 +250,6 @@ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflat 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/PreviewTextStringFragment.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewTextStringFragment.java index b9aa3f092a5f..975902a9052c 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 @@ -17,6 +17,7 @@ import android.view.ViewGroup; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.lib.richWorkspace.RichWorkspaceDirectEditingRemoteOperation; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.owncloud.android.R; @@ -72,6 +73,7 @@ public void onSaveInstanceState(@NonNull Bundle outState) { } @Override + @IonosCustomization public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = super.onCreateView(inflater, container, savedInstanceState); @@ -85,7 +87,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, fabMain.setOnClickListener(v -> edit()); fabMain.setImageResource(R.drawable.ic_edit); - viewThemeUtils.material.themeFAB(fabMain); return view; } @@ -104,6 +105,7 @@ public void onStart() { * {@inheritDoc} */ @Override + @IonosCustomization public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); @@ -112,7 +114,6 @@ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflat searchView = (SearchView) MenuItemCompat.getActionView(menuItem); searchView.setOnQueryTextListener(this); 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/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index ebb94da68f90..abf00825333a 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -27,7 +27,9 @@ import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar +import com.ionos.annotation.IonosCustomization import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.network.ClientFactory @@ -295,9 +297,10 @@ class TrashbinActivity : onBackPressedCallback.isEnabled = !isRoot } + @IonosCustomization override fun onSortingOrderChosen(selection: FileSortOrder?) { - val sortButton = findViewById(R.id.sort_button) - sortButton.setText(DisplayUtils.getSortOrderStringId(selection)) + val sortButton = findViewById(R.id.sort_button) + sortButton.setIconResource(DisplayUtils.getSortOrderIconRes(selection)) trashbinListAdapter?.setSortOrder(selection) } 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 b70853136846..9ea88bd1132b 100644 --- a/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -56,6 +56,8 @@ import com.caverock.androidsvg.SVG; import com.elyeproj.loaderviewlibrary.LoaderImageView; import com.google.android.material.snackbar.Snackbar; +import com.ionos.annotation.IonosCustomization; +import com.ionos.utils.IonosBuildHelper; import com.nextcloud.client.account.CurrentAccountProvider; import com.nextcloud.client.account.User; import com.nextcloud.client.network.ClientFactory; @@ -102,6 +104,7 @@ import java.util.Map; import java.util.TimeZone; +import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -478,6 +481,7 @@ public static void setAvatar(@NonNull User user, @NonNull String userId, AvatarG * @param resources reference for density information * @param callContext which context is called to set the generated avatar */ + @IonosCustomization public static void setAvatar(@NonNull User user, @NonNull String userId, String displayName, @@ -490,6 +494,12 @@ public static void setAvatar(@NonNull User user, ((View) callContext).setContentDescription(String.valueOf(user.toPlatformAccount().hashCode())); } + if (IonosBuildHelper.isIonosBuild()) { + Drawable avatar = ResourcesCompat.getDrawable(resources, R.drawable.account_circle_white, null); + listener.avatarGenerated(avatar, callContext); + return; + } + ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(context); final String accountName = user.getAccountName(); @@ -819,21 +829,22 @@ static public void openSortingOrderDialogFragment(FragmentManager supportFragmen SortingOrderDialogFragment.newInstance(sortOrder).show(fragmentTransaction, SORTING_ORDER_FRAGMENT); } - public static @StringRes int getSortOrderStringId(FileSortOrder sortOrder) { + @IonosCustomization + public static @DrawableRes int getSortOrderIconRes(FileSortOrder sortOrder) { switch (sortOrder.name) { case SORT_Z_TO_A_ID: - return R.string.menu_item_sort_by_name_z_a; + return R.drawable.ic_alphabetical_desc; case SORT_NEW_TO_OLD_ID: - return R.string.menu_item_sort_by_date_newest_first; + return R.drawable.ic_modification_desc; case SORT_OLD_TO_NEW_ID: - return R.string.menu_item_sort_by_date_oldest_first; + return R.drawable.ic_modification_asc; case SORT_BIG_TO_SMALL_ID: - return R.string.menu_item_sort_by_size_biggest_first; + return R.drawable.ic_size_desc; case SORT_SMALL_TO_BIG_ID: - return R.string.menu_item_sort_by_size_smallest_first; + return R.drawable.ic_size_asc; case SORT_A_TO_Z_ID: default: - return R.string.menu_item_sort_by_name_a_z; + return R.drawable.ic_alphabetical_asc; } } diff --git a/app/src/main/java/com/owncloud/android/utils/DrawableUtil.kt b/app/src/main/java/com/owncloud/android/utils/DrawableUtil.kt index fcd2434c1be2..9a2b6555fcf4 100644 --- a/app/src/main/java/com/owncloud/android/utils/DrawableUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/DrawableUtil.kt @@ -7,10 +7,11 @@ */ package com.owncloud.android.utils -import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable +import android.view.Gravity import androidx.core.graphics.drawable.DrawableCompat +import com.ionos.annotation.IonosCustomization object DrawableUtil { @@ -20,28 +21,12 @@ object DrawableUtil { return drawable } + @IonosCustomization fun addDrawableAsOverlay(backgroundDrawable: Drawable, overlayDrawable: Drawable): LayerDrawable { - val containerDrawable = LayerDrawable(arrayOf(backgroundDrawable, overlayDrawable)) - val overlayWidth = overlayDrawable.intrinsicWidth - val overlayHeight = overlayDrawable.intrinsicHeight - val backgroundWidth = backgroundDrawable.intrinsicWidth - val backgroundHeight = backgroundDrawable.intrinsicHeight - - val scaleFactor = 2f / maxOf(overlayWidth, overlayHeight) - val scaledOverlayWidth = (overlayWidth * scaleFactor).toInt() - val scaledOverlayHeight = (overlayHeight * scaleFactor).toInt() - - val left = (backgroundWidth - scaledOverlayWidth) / 2 - val top = (backgroundHeight - scaledOverlayHeight) / 2 - - // Icons are centered on the folder icon. However, some icons take up more vertical space, - // so adding a top margin to all icons helps center the overlay icon better. - val topMargin = 2 - - containerDrawable.setLayerInset(1, left, top + topMargin, left, top) - (overlayDrawable as? BitmapDrawable)?.setBounds(0, 0, scaledOverlayWidth, scaledOverlayHeight) - - return containerDrawable + return LayerDrawable(arrayOf(backgroundDrawable, overlayDrawable)).apply { + setLayerSize(1, overlayDrawable.intrinsicWidth, overlayDrawable.intrinsicHeight) + setLayerGravity(1, Gravity.CENTER) + } } } diff --git a/app/src/main/java/com/owncloud/android/utils/DrawerMenuUtil.java b/app/src/main/java/com/owncloud/android/utils/DrawerMenuUtil.java index 0591b0d0c4d0..8ab5daab1594 100644 --- a/app/src/main/java/com/owncloud/android/utils/DrawerMenuUtil.java +++ b/app/src/main/java/com/owncloud/android/utils/DrawerMenuUtil.java @@ -10,6 +10,7 @@ import android.content.res.Resources; import android.view.Menu; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.client.account.User; import com.owncloud.android.R; import com.owncloud.android.lib.resources.status.OCCapability; @@ -77,6 +78,11 @@ public static void setupHomeMenuItem(Menu menu, Resources resources) { } } + @IonosCustomization + public static void removePersonalFiles(Menu menu) { + removeMenuItem(menu, R.id.nav_personal_files); + } + private static void removeMenuItem(Menu menu, int... menuIds) { if (menuIds != null) { for (int menuId : menuIds) { 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 5e9493f67190..c06fede16c60 100644 --- a/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java +++ b/app/src/main/java/com/owncloud/android/utils/MimeTypeUtil.java @@ -16,6 +16,7 @@ import android.net.Uri; import android.webkit.MimeTypeMap; +import com.ionos.annotation.IonosCustomization; import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; @@ -88,6 +89,7 @@ private MimeTypeUtil() { * @param filename Name, with extension. * @return Drawable of an image resource. */ + @IonosCustomization("Custom icon tint") public static Drawable getFileTypeIcon(String mimetype, String filename, Context context, @@ -99,9 +101,7 @@ public static Drawable getFileTypeIcon(String mimetype, return null; } - if (R.drawable.file_zip == iconId) { - viewThemeUtils.platform.tintDrawable(context, icon, ColorRole.PRIMARY); - } + icon.setTint(context.getColor(R.color.filelist_file_icon_color)); return icon; } else { @@ -144,14 +144,16 @@ public static int getFileTypeIconId(String mimetype, String filename) { return determineIconIdByMimeTypeList(possibleMimeTypes); } + @IonosCustomization("Custom icon tint") public static Drawable getDefaultFolderIcon(Context context, ViewThemeUtils viewThemeUtils) { Drawable drawable = ContextCompat.getDrawable(context, R.drawable.folder); assert(drawable != null); - viewThemeUtils.platform.tintDrawable(context, drawable, ColorRole.PRIMARY); + drawable.setTint(context.getColor(R.color.filelist_file_icon_color)); return drawable; } + @IonosCustomization("Remove custom overlay color for dark mode") public static LayerDrawable getFolderIcon(boolean isDarkModeActive, Integer overlayIconId, Context context, ViewThemeUtils viewThemeUtils) { Drawable folderDrawable = getDefaultFolderIcon(context, viewThemeUtils); assert(folderDrawable != null); @@ -165,10 +167,6 @@ public static LayerDrawable getFolderIcon(boolean isDarkModeActive, Integer over Drawable overlayDrawable = ContextCompat.getDrawable(context, overlayIconId); assert(overlayDrawable != null); - if (isDarkModeActive) { - overlayDrawable = DrawableUtil.INSTANCE.changeColor(overlayDrawable, R.color.dark); - } - return DrawableUtil.INSTANCE.addDrawableAsOverlay(folderDrawable, overlayDrawable); } 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 3d35656655d7..41c00edd954f 100644 --- a/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt +++ b/app/src/main/java/com/owncloud/android/utils/PermissionUtil.kt @@ -180,7 +180,7 @@ object PermissionUtil { Snackbar.LENGTH_INDEFINITE ).setAction(R.string.common_ok) { doRequest() - }.also { viewThemeUtils.material.themeSnackbar(it) }.show() + }.also { viewThemeUtils.ionos.material.themeSnackbar(it) }.show() } else { // No explanation needed, request the permission. doRequest() 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 index 41f13b37156f..5508572164b9 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/theme/FilesSpecificViewThemeUtils.kt @@ -23,6 +23,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.ActionBar import androidx.core.content.res.ResourcesCompat import com.google.android.material.card.MaterialCardView +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase @@ -43,17 +44,9 @@ class FilesSpecificViewThemeUtils @Inject constructor( private val androidXViewThemeUtils: AndroidXViewThemeUtils ) : ViewThemeUtilsBase(schemes) { // not ported to common lib because PreferenceCategory is deprecated + @IonosCustomization 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 - } + // Do nothing } fun createAvatar(type: ShareType?, avatar: ImageView, context: Context) { @@ -132,19 +125,11 @@ class FilesSpecificViewThemeUtils @Inject constructor( */ // TODO move back arrow resource to lib and use lib method directly? @JvmOverloads + @IonosCustomization fun themeActionBar(context: Context, actionBar: ActionBar, title: String, isMenu: Boolean = false) { val icon = getHomeAsUpIcon(isMenu) - val backArrow = ResourcesCompat.getDrawable( - context.resources, - icon, - null - )!! - androidXViewThemeUtils.themeActionBar( - context, - actionBar, - title, - backArrow - ) + actionBar.setHomeAsUpIndicator(icon) + actionBar.title = title } /** @@ -165,13 +150,10 @@ class FilesSpecificViewThemeUtils @Inject constructor( * Colors actionbar background and back arrow but not the title */ @JvmOverloads + @IonosCustomization fun themeActionBar(context: Context, actionBar: ActionBar, isMenu: Boolean = false) { - val backArrow = ResourcesCompat.getDrawable( - context.resources, - getHomeAsUpIcon(isMenu), - null - )!! - androidXViewThemeUtils.themeActionBar(context, actionBar, backArrow) + val icon = getHomeAsUpIcon(isMenu) + actionBar.setHomeAsUpIndicator(icon) } fun themeTemplateCardView(cardView: MaterialCardView) { diff --git a/app/src/main/java/com/owncloud/android/utils/theme/IonosAndroidViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/IonosAndroidViewThemeUtils.kt new file mode 100644 index 000000000000..7b73dcbebd90 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/IonosAndroidViewThemeUtils.kt @@ -0,0 +1,43 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.utils.theme + +import android.app.Activity +import android.content.Context +import android.view.View +import android.widget.Button +import androidx.annotation.ColorInt +import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.ColorRole +import com.owncloud.android.R + +class IonosAndroidViewThemeUtils( + private val platformUtil: AndroidViewThemeUtils, +) { + fun themeSystemBars(activity: Activity) { + platformUtil.colorStatusBar(activity, activity.getSystemBarsColor()) + } + + fun themeSystemBars(activity: Activity, @ColorInt color: Int) { + platformUtil.colorStatusBar(activity, color) + } + + fun resetSystemBars(activity: Activity) { + platformUtil.colorStatusBar(activity, activity.getSystemBarsColor()) + } + + @JvmOverloads + fun colorViewBackground(view: View, colorRole: ColorRole = ColorRole.SURFACE) {} + + fun themeDialog(view: View) {} + + fun colorTextButtons(vararg buttons: Button) {} + + @ColorInt + private fun Context.getSystemBarsColor(): Int = getColor(R.color.system_bars_color) +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/IonosDialogViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/IonosDialogViewThemeUtils.kt new file mode 100644 index 000000000000..1fe45bd4d0b1 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/IonosDialogViewThemeUtils.kt @@ -0,0 +1,42 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.utils.theme + +import android.content.Context +import android.content.res.ColorStateList +import android.os.Build +import com.google.android.material.button.MaterialButton +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.shape.MaterialShapeDrawable +import com.owncloud.android.R + +class IonosDialogViewThemeUtils { + + fun colorDialogMenuText(button: MaterialButton) { + button.setTextColor(button.context.getColor(R.color.text_color)) + button.iconTint = ColorStateList.valueOf(button.context.getColor(R.color.default_icon_color)) + } + + fun colorMaterialAlertDialogBackground(context: Context, dialogBuilder: MaterialAlertDialogBuilder) { + val materialShapeDrawable = MaterialShapeDrawable( + context, + null, + com.google.android.material.R.attr.alertDialogStyle, + com.google.android.material.R.style.MaterialAlertDialog_MaterialComponents, + ) + materialShapeDrawable.initializeElevationOverlay(context) + materialShapeDrawable.fillColor = ColorStateList.valueOf(context.getColor(R.color.bg_default)) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + val radius = context.resources.getDimension(R.dimen.dialogBorderRadius) + materialShapeDrawable.setCornerSize(radius) + } + + dialogBuilder.background = materialShapeDrawable + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/IonosMaterialViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/IonosMaterialViewThemeUtils.kt new file mode 100644 index 000000000000..756f6e4101c7 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/IonosMaterialViewThemeUtils.kt @@ -0,0 +1,70 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.utils.theme + +import android.util.TypedValue +import androidx.core.view.setPadding +import com.google.android.material.button.MaterialButton +import com.google.android.material.snackbar.Snackbar +import com.google.android.material.textfield.TextInputLayout +import com.nextcloud.android.common.ui.util.buildColorStateList +import com.owncloud.android.R + +class IonosMaterialViewThemeUtils { + + fun colorMaterialButtonPrimaryTonal(button: MaterialButton) {} + + fun colorMaterialButtonPrimaryBorderless(button: MaterialButton) {} + + fun colorMaterialButtonPrimaryFilled(button: MaterialButton) {} + + fun colorMaterialButtonText(button: MaterialButton) {} + + fun themeSnackbar(snackbar: Snackbar) {} + + fun colorMaterialButtonPrimaryOutlined(button: MaterialButton) {} + + fun colorTextInputLayout(textInputLayout: TextInputLayout) { + val context = textInputLayout.context + + val boxStrokeWidthRes = R.dimen.text_input_box_stroke_width + val cornerRadiusRes = R.dimen.text_input_box_corner_radius + val boxStrokeColorStateList = buildColorStateList( + -android.R.attr.state_focused to context.getColor(R.color.text_input_border_stroke_color), + android.R.attr.state_focused to context.getColor(R.color.text_input_focused_border_stroke_color), + ) + + textInputLayout.setBoxStrokeWidthResource(boxStrokeWidthRes) + textInputLayout.setBoxStrokeWidthFocusedResource(boxStrokeWidthRes) + textInputLayout.setBoxCornerRadiiResources(cornerRadiusRes, cornerRadiusRes, cornerRadiusRes, cornerRadiusRes) + textInputLayout.setBoxStrokeColorStateList(boxStrokeColorStateList) + + val errorColorStateList = buildColorStateList( + -android.R.attr.state_focused to context.getColor(R.color.text_input_error_color), + android.R.attr.state_focused to context.getColor(R.color.text_input_error_color), + ) + + textInputLayout.setErrorIconTintList(errorColorStateList) + textInputLayout.setErrorTextColor(errorColorStateList) + textInputLayout.boxStrokeErrorColor = errorColorStateList + + val hintTextColorStateList = buildColorStateList( + -android.R.attr.state_focused to context.getColor(R.color.text_input_hint_text_color), + android.R.attr.state_focused to context.getColor(R.color.text_input_focused_hint_text_color), + ) + + textInputLayout.defaultHintTextColor = hintTextColorStateList + + val padding = context.resources.getDimension(R.dimen.text_input_padding).toInt() + val textSize = context.resources.getDimension(R.dimen.text_input_text_size) + + textInputLayout.editText?.setPadding(padding) + textInputLayout.editText?.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + textInputLayout.editText?.highlightColor = context.getColor(R.color.text_input_highlight_color) + } +} diff --git a/app/src/main/java/com/owncloud/android/utils/theme/IonosViewThemeUtils.kt b/app/src/main/java/com/owncloud/android/utils/theme/IonosViewThemeUtils.kt new file mode 100644 index 000000000000..ea99ae53458a --- /dev/null +++ b/app/src/main/java/com/owncloud/android/utils/theme/IonosViewThemeUtils.kt @@ -0,0 +1,28 @@ +/* + * IONOS HiDrive Next - Android Client + * + * SPDX-FileCopyrightText: 2025 STRATO GmbH. + * SPDX-License-Identifier: GPL-2.0 + */ + +package com.owncloud.android.utils.theme + +import com.ionos.annotation.IonosCustomization +import com.nextcloud.android.common.ui.theme.utils.AndroidViewThemeUtils +import com.nextcloud.android.common.ui.theme.utils.MaterialViewThemeUtils + +@IonosCustomization +class IonosViewThemeUtils( + private val platformUtil: AndroidViewThemeUtils, + private val materialUtil: MaterialViewThemeUtils, +) { + + @JvmField + val platform = IonosAndroidViewThemeUtils(platformUtil) + + @JvmField + val material = IonosMaterialViewThemeUtils() + + @JvmField + val dialog = IonosDialogViewThemeUtils() +} \ No newline at end of file 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 index 5a09ea8d69a5..d4e2e3923ac4 100644 --- a/app/src/main/java/com/owncloud/android/utils/theme/ViewThemeUtils.kt +++ b/app/src/main/java/com/owncloud/android/utils/theme/ViewThemeUtils.kt @@ -7,6 +7,7 @@ */ package com.owncloud.android.utils.theme +import com.ionos.annotation.IonosCustomization import com.nextcloud.android.common.ui.color.ColorUtil import com.nextcloud.android.common.ui.theme.MaterialSchemes import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase @@ -38,6 +39,10 @@ class ViewThemeUtils @Inject constructor( @JvmField val files = FilesSpecificViewThemeUtils(schemes, colorUtil, platform, androidx) + @JvmField + @IonosCustomization + val ionos = IonosViewThemeUtils(platform, material) + class Factory @Inject constructor( private val schemesProvider: MaterialSchemesProvider, private val colorUtil: ColorUtil diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml new file mode 100644 index 000000000000..a21744ff2499 --- /dev/null +++ b/app/src/main/res/anim/fade_in.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml new file mode 100644 index 000000000000..a2b5526cb1ec --- /dev/null +++ b/app/src/main/res/anim/fade_out.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/color/fab_background_tint.xml b/app/src/main/res/color/fab_background_tint.xml new file mode 100644 index 000000000000..debb631f48e9 --- /dev/null +++ b/app/src/main/res/color/fab_background_tint.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/background_splash.xml b/app/src/main/res/drawable/background_splash.xml new file mode 100644 index 000000000000..e27a0271888a --- /dev/null +++ b/app/src/main/res/drawable/background_splash.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/grid_mode_item_background.xml b/app/src/main/res/drawable/grid_mode_item_background.xml new file mode 100644 index 000000000000..a35817881607 --- /dev/null +++ b/app/src/main/res/drawable/grid_mode_item_background.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/main/res/drawable/grid_mode_selected_item_background.xml b/app/src/main/res/drawable/grid_mode_selected_item_background.xml new file mode 100644 index 000000000000..88b9877084b8 --- /dev/null +++ b/app/src/main/res/drawable/grid_mode_selected_item_background.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_data_protection.xml b/app/src/main/res/drawable/ic_data_protection.xml new file mode 100644 index 000000000000..72c7887423de --- /dev/null +++ b/app/src/main/res/drawable/ic_data_protection.xml @@ -0,0 +1,17 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_cancel_sync.xml b/app/src/main/res/drawable/ic_file_action_cancel_sync.xml new file mode 100644 index 000000000000..c7f0db0ca5d3 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_cancel_sync.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_download_file.xml b/app/src/main/res/drawable/ic_file_action_download_file.xml new file mode 100644 index 000000000000..4b1561b1b431 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_download_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_edit.xml b/app/src/main/res/drawable/ic_file_action_edit.xml new file mode 100644 index 000000000000..e2bcc65afb5c --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_edit.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_export_file.xml b/app/src/main/res/drawable/ic_file_action_export_file.xml new file mode 100644 index 000000000000..e6670404593a --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_export_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_favorite.xml b/app/src/main/res/drawable/ic_file_action_favorite.xml new file mode 100644 index 000000000000..271799f8e9e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_favorite.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_lock_file.xml b/app/src/main/res/drawable/ic_file_action_lock_file.xml new file mode 100644 index 000000000000..eaeef744157c --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_lock_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_move_or_copy.xml b/app/src/main/res/drawable/ic_file_action_move_or_copy.xml new file mode 100644 index 000000000000..388986ce246c --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_move_or_copy.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_open_file_with.xml b/app/src/main/res/drawable/ic_file_action_open_file_with.xml new file mode 100644 index 000000000000..388986ce246c --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_open_file_with.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_pin_to_homescreen.xml b/app/src/main/res/drawable/ic_file_action_pin_to_homescreen.xml new file mode 100644 index 000000000000..cd3fb9e8fb92 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_pin_to_homescreen.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_remove_file.xml b/app/src/main/res/drawable/ic_file_action_remove_file.xml new file mode 100644 index 000000000000..b72c7a747d03 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_remove_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_rename_file.xml b/app/src/main/res/drawable/ic_file_action_rename_file.xml new file mode 100644 index 000000000000..72ff8ee453d5 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_rename_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_see_details.xml b/app/src/main/res/drawable/ic_file_action_see_details.xml new file mode 100644 index 000000000000..ef7bb988dfb8 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_see_details.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_select_all.xml b/app/src/main/res/drawable/ic_file_action_select_all.xml new file mode 100644 index 000000000000..b017bf913225 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_select_all.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_select_none.xml b/app/src/main/res/drawable/ic_file_action_select_none.xml new file mode 100644 index 000000000000..329e4d1b7e7e --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_select_none.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_set_as_wallpaper.xml b/app/src/main/res/drawable/ic_file_action_set_as_wallpaper.xml new file mode 100644 index 000000000000..41755ab3be06 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_set_as_wallpaper.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_set_encrypted.xml b/app/src/main/res/drawable/ic_file_action_set_encrypted.xml new file mode 100644 index 000000000000..b7d8b3c97021 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_set_encrypted.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_share_file.xml b/app/src/main/res/drawable/ic_file_action_share_file.xml new file mode 100644 index 000000000000..1a9d21d9b281 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_share_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_stream_media.xml b/app/src/main/res/drawable/ic_file_action_stream_media.xml new file mode 100644 index 000000000000..be328e566a66 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_stream_media.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_sync_file.xml b/app/src/main/res/drawable/ic_file_action_sync_file.xml new file mode 100644 index 000000000000..7054f44c69be --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_sync_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_unlock_file.xml b/app/src/main/res/drawable/ic_file_action_unlock_file.xml new file mode 100644 index 000000000000..8b84787751ec --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_unlock_file.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_unset_encrypted.xml b/app/src/main/res/drawable/ic_file_action_unset_encrypted.xml new file mode 100644 index 000000000000..9a17c0e2b9dd --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_unset_encrypted.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_file_action_unset_favorite.xml b/app/src/main/res/drawable/ic_file_action_unset_favorite.xml new file mode 100644 index 000000000000..23b75c5bafe3 --- /dev/null +++ b/app/src/main/res/drawable/ic_file_action_unset_favorite.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/src/main/res/drawable/rounded_rect_4dp.xml b/app/src/main/res/drawable/rounded_rect_4dp.xml new file mode 100644 index 000000000000..1952e3c9f856 --- /dev/null +++ b/app/src/main/res/drawable/rounded_rect_4dp.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_data_protection.xml b/app/src/main/res/layout/activity_data_protection.xml new file mode 100644 index 000000000000..662d0f05fe0d --- /dev/null +++ b/app/src/main/res/layout/activity_data_protection.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_data_protection_detail_page.xml b/app/src/main/res/layout/activity_data_protection_detail_page.xml new file mode 100644 index 000000000000..459f10840155 --- /dev/null +++ b/app/src/main/res/layout/activity_data_protection_detail_page.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_data_protection_overview_page.xml b/app/src/main/res/layout/activity_data_protection_overview_page.xml new file mode 100644 index 000000000000..7363d67193dd --- /dev/null +++ b/app/src/main/res/layout/activity_data_protection_overview_page.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_edit_image.xml b/app/src/main/res/layout/activity_edit_image.xml index 4b11869ee501..a67156844e45 100644 --- a/app/src/main/res/layout/activity_edit_image.xml +++ b/app/src/main/res/layout/activity_edit_image.xml @@ -10,13 +10,13 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/black"> + android:background="@color/edit_image_background"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_choose_account.xml b/app/src/main/res/layout/dialog_choose_account.xml index 66e05389de49..53e7b9fa2693 100644 --- a/app/src/main/res/layout/dialog_choose_account.xml +++ b/app/src/main/res/layout/dialog_choose_account.xml @@ -46,10 +46,12 @@ android:textAlignment="textStart" android:textAllCaps="false" android:textColor="@color/fontAppbar" + android:visibility="gone" app:icon="@drawable/ic_edit" app:iconGravity="start" app:iconPadding="22dp" - app:iconTint="@color/fontAppbar" /> + app:iconTint="@color/fontAppbar" + app:ionosCustomization="" /> diff --git a/app/src/main/res/layout/empty_list.xml b/app/src/main/res/layout/empty_list.xml index 5f1aea457a05..a0d1da1af082 100644 --- a/app/src/main/res/layout/empty_list.xml +++ b/app/src/main/res/layout/empty_list.xml @@ -43,6 +43,7 @@ android:paddingTop="@dimen/standard_padding" android:paddingBottom="@dimen/standard_half_padding" android:text="@string/file_list_loading" + android:textColor="@color/text_color" android:textSize="26sp" /> diff --git a/app/src/main/res/layout/file_details_share_public_link_add_new_item.xml b/app/src/main/res/layout/file_details_share_public_link_add_new_item.xml index 466cdcddc3d3..9efada5357dd 100644 --- a/app/src/main/res/layout/file_details_share_public_link_add_new_item.xml +++ b/app/src/main/res/layout/file_details_share_public_link_add_new_item.xml @@ -19,9 +19,8 @@ android:layout_gravity="center_vertical" android:layout_marginStart="@dimen/standard_margin" android:layout_marginEnd="@dimen/standard_margin" - android:background="@drawable/round_bgnd" android:contentDescription="@string/share" - android:padding="@dimen/standard_half_padding" + android:scaleType="centerInside" android:src="@drawable/shared_via_link" /> + android:scaleType="centerInside" + android:src="@drawable/account_circle_white" /> 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 14af3dff721c..1a628cb70909 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 @@ -48,6 +48,7 @@ android:id="@+id/share_process_permission_read_only" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/text_color" android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_share_view_only" /> @@ -55,6 +56,7 @@ android:id="@+id/share_process_permission_upload_editing" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/text_color" android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_share_allow_upload_and_editing" /> @@ -62,6 +64,7 @@ android:id="@+id/share_process_permission_file_drop" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textColor="@color/text_color" android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/link_share_file_drop" /> @@ -82,6 +85,7 @@ android:layout_height="wrap_content" android:minHeight="@dimen/minimum_size_for_touchable_area" android:text="@string/allow_resharing" + android:textColor="@color/text_color" android:visibility="gone" tools:visibility="visible" /> @@ -90,7 +94,8 @@ 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"/> + android:text="@string/share_no_password_title" + android:textColor="@color/text_color" /> + android:text="@string/share_no_expiration_date_label" + android:textColor="@color/text_color" /> @@ -187,7 +194,8 @@ 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" /> + android:text="@string/link_name" + android:textColor="@color/text_color" /> + app:cornerRadius="@dimen/button_corner_radius" + app:ionosCustomization="Adjust the height to match the height of the Next button" /> + android:theme="@style/Theme.Dialog.IconButton.Filled" + android:textColor="@color/filled_button_text_color" + app:cornerRadius="@dimen/button_corner_radius" + app:ionosCustomization="Limit max lines number to 2" /> diff --git a/app/src/main/res/layout/file_thumbnail.xml b/app/src/main/res/layout/file_thumbnail.xml index 6f318d47e9b3..76b528104a57 100644 --- a/app/src/main/res/layout/file_thumbnail.xml +++ b/app/src/main/res/layout/file_thumbnail.xml @@ -19,6 +19,16 @@ android:layout_height="@dimen/file_icon_size" android:layout_gravity="center"> + + diff --git a/app/src/main/res/layout/files_folder_picker.xml b/app/src/main/res/layout/files_folder_picker.xml index f1d4f53ebb5d..ddbdc84a720e 100644 --- a/app/src/main/res/layout/files_folder_picker.xml +++ b/app/src/main/res/layout/files_folder_picker.xml @@ -51,7 +51,7 @@ @@ -31,6 +32,8 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/standard_margin" android:layout_marginBottom="@dimen/standard_margin" + android:textStyle="bold" + app:ionosCustomization="bold text" android:textAppearance="?android:attr/textAppearanceLarge" tools:text="2016" /> diff --git a/app/src/main/res/layout/grid_image.xml b/app/src/main/res/layout/grid_image.xml index 69e064ac87f4..7cab438f410e 100644 --- a/app/src/main/res/layout/grid_image.xml +++ b/app/src/main/res/layout/grid_image.xml @@ -23,6 +23,20 @@ android:layout_width="@dimen/grid_container_width" android:layout_height="@dimen/grid_container_height"> + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/log_entry_list_item.xml b/app/src/main/res/layout/log_entry_list_item.xml index 969711013c5b..ce6cf8f44fc0 100644 --- a/app/src/main/res/layout/log_entry_list_item.xml +++ b/app/src/main/res/layout/log_entry_list_item.xml @@ -20,6 +20,7 @@ android:ellipsize="end" android:lines="1" android:textStyle="bold" + android:textColor="@color/text_color" tools:text="@tools:sample/lorem/random" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_users_groups_layout.xml b/app/src/main/res/layout/search_users_groups_layout.xml index f0b30be55872..21f1237cf328 100644 --- a/app/src/main/res/layout/search_users_groups_layout.xml +++ b/app/src/main/res/layout/search_users_groups_layout.xml @@ -30,7 +30,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/searchView" - android:hint="@string/share_search" + android:hint="@string/ionos_share_search" style="@style/ownCloud.SearchView"/> + app:icon="@drawable/ic_share" /> + app:icon="@drawable/ic_link" /> diff --git a/app/src/main/res/layout/settings_privacy_switchers.xml b/app/src/main/res/layout/settings_privacy_switchers.xml new file mode 100644 index 000000000000..8aa656803d02 --- /dev/null +++ b/app/src/main/res/layout/settings_privacy_switchers.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml b/app/src/main/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml new file mode 100644 index 000000000000..88b1e407a71c --- /dev/null +++ b/app/src/main/res/layout/simple_file_list_actions_bottom_sheet_fragment.xml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/simple_spinner_item.xml b/app/src/main/res/layout/simple_spinner_item.xml new file mode 100644 index 000000000000..accb287cbdde --- /dev/null +++ b/app/src/main/res/layout/simple_spinner_item.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/layout/storage_path_item.xml b/app/src/main/res/layout/storage_path_item.xml index 2b506d49cede..3415ebc58674 100644 --- a/app/src/main/res/layout/storage_path_item.xml +++ b/app/src/main/res/layout/storage_path_item.xml @@ -15,6 +15,9 @@ android:gravity="center|start" android:paddingBottom="@dimen/standard_half_padding" android:text="@string/menu_item_sort_by_name_z_a" + android:textColor="@color/text_color" app:icon="@drawable/ic_user" app:iconPadding="@dimen/standard_padding" + app:iconTint="@color/default_icon_color" + app:ionosCustomization="Custom color" tools:text="DCIM" /> diff --git a/app/src/main/res/layout/synced_folders_settings_layout.xml b/app/src/main/res/layout/synced_folders_settings_layout.xml index d0e0e423c9b5..d800222c1003 100644 --- a/app/src/main/res/layout/synced_folders_settings_layout.xml +++ b/app/src/main/res/layout/synced_folders_settings_layout.xml @@ -431,7 +431,7 @@ @@ -454,7 +454,7 @@ android:id="@+id/btnPositive" android:layout_width="wrap_content" android:text="@string/common_save" - style="@style/Widget.Material3.Button.TonalButton" + style="@style/Theme.Dialog.IconButton.Filled.Tonal" android:layout_height="wrap_content" android:layout_weight="1"/> diff --git a/app/src/main/res/layout/upload_files_layout.xml b/app/src/main/res/layout/upload_files_layout.xml index 4012193eb6a9..2c4209c22e3d 100644 --- a/app/src/main/res/layout/upload_files_layout.xml +++ b/app/src/main/res/layout/upload_files_layout.xml @@ -78,7 +78,7 @@ android:layout_marginEnd="@dimen/standard_half_margin" android:layout_weight="1" android:text="@string/common_cancel" - style="@style/OutlinedButton" + style="@style/Theme.Dialog.Button.OutlinedButton" app:cornerRadius="@dimen/button_corner_radius" /> diff --git a/app/src/main/res/layout/user_info_layout.xml b/app/src/main/res/layout/user_info_layout.xml index 5a7d442c24ee..c1ca59544861 100644 --- a/app/src/main/res/layout/user_info_layout.xml +++ b/app/src/main/res/layout/user_info_layout.xml @@ -62,6 +62,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/userinfo_icon" app:layout_constraintTop_toTopOf="@id/userinfo_icon" + app:layout_constraintBottom_toTopOf="@id/userinfo_username" tools:text="John Doe" /> diff --git a/app/src/main/res/layout/view_authorization_method.xml b/app/src/main/res/layout/view_authorization_method.xml new file mode 100644 index 000000000000..51ea5477db49 --- /dev/null +++ b/app/src/main/res/layout/view_authorization_method.xml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_folder_picker.xml b/app/src/main/res/menu/activity_folder_picker.xml index 3e6fdcebbf2a..21a6ab87f424 100644 --- a/app/src/main/res/menu/activity_folder_picker.xml +++ b/app/src/main/res/menu/activity_folder_picker.xml @@ -23,6 +23,6 @@ android:icon="@drawable/ic_action_create_dir" android:orderInCategory="1" android:title="@string/actionbar_mkdir" - app:iconTint="?attr/colorOnSurface" + app:ionosCustomization="Remove tint" app:showAsAction="ifRoom"/> diff --git a/app/src/main/res/menu/activity_receive_external_files.xml b/app/src/main/res/menu/activity_receive_external_files.xml index 4c22d95237bd..ed4a7894823e 100644 --- a/app/src/main/res/menu/activity_receive_external_files.xml +++ b/app/src/main/res/menu/activity_receive_external_files.xml @@ -27,7 +27,7 @@ android:icon="@drawable/ic_action_create_dir" android:orderInCategory="1" android:title="@string/actionbar_mkdir" - app:iconTint="?attr/colorOnSurface" + app:ionosCustomization="Remove tint" app:showAsAction="never"/> diff --git a/app/src/main/res/values-de/string.xml b/app/src/main/res/values-de/string.xml new file mode 100644 index 000000000000..5cb86d606c01 --- /dev/null +++ b/app/src/main/res/values-de/string.xml @@ -0,0 +1,32 @@ + + + + + + + Speicherberechtigungen + Speicherberechtigungen + %1$s braucht die Erlaubnis, auf Ihre Dateien zuzugreifen, um besser zu funktionieren. Sie können den Zugriff erlauben oder verweigern. + %1$s braucht die Erlaubnis, auf Ihre Dateien zuzugreifen, um besser zu funktionieren. Sie können den Zugriff erlauben oder verweigern. + + + Name oder E-Mail-Adresse… + + + Datenschutz-Einstellungen + Diese Anwendung verwendet Cookies und ähnliche Technologien. Durch Klicken auf Zustimmen akzeptieren Sie die Verarbeitung und auch die Weitergabe Ihrer Daten an Dritte. Weitere Informationen, auch zur Datenverarbeitung durch Drittanbieter, finden Sie in den Einstellungen und in unserer Datenschutzhinweise Sie können die Nutzung der Tools Ablehnen oder Ihre Auswahl jederzeit über Ihre Einstellungen anpassen. + Einstellungen + Zustimmen + Zur Optimierung unserer App erfassen wir anonymisierte Daten. Hierzu nutzen wir Softwarelösungen verschiedener Partner. Wir möchten Ihnen volle Transparenz und Entscheidungsgewalt über die Verarbeitung und Erfassung Ihrer anonymisierten Nutzungsdaten geben. Ihre Einstellungen können Sie auch später jederzeit unter dem Menüpunkt Datenschutz ändern. Bitte beachten Sie jedoch, dass die Datenerfassung einen erheblichen Beitrag zur Optimierung dieser App leistet und Sie diese Optimierungen durch die Unterbindung der Datenübermittlung verhindern. + Die Erfassung dieser Daten ist notwendig, um wesentliche Funktionen der App nutzen zu können. + Erforderliche Datenerfassung + Diese Daten helfen uns, die App-Nutzung für Sie zu optimieren und Systemabstürze und Fehler schneller zu identifizieren. + Analyse der Datenerfassung zur bedarfsgerechten Gestaltung + Einstellungen speichern + + \ No newline at end of file diff --git a/app/src/main/res/values-es-rCR/strings.xml b/app/src/main/res/values-es-rCR/strings.xml new file mode 100644 index 000000000000..97660ca56e6f --- /dev/null +++ b/app/src/main/res/values-es-rCR/strings.xml @@ -0,0 +1,543 @@ + + + %1$s aplicación Android + Acerca de + versión %1$s + Ícono de la cuenta + ¡No se encontró la cuenta! + Editar + Enviar/Compartir + Vista de cuadrícula + Vista de lista + Nueva carpeta + Abrir con + Buscar + Detalles + Enviar + Configuraciones + Ordenar + Usuario activo + Aún no hay actividades + Enviar + Enviar liga a… + Actividad + Agregar a %1$s + Permitir volver a compartir + Todos + Completado + Desconocido + La cuenta aún no ha sido agregada a este dispositivo + Ya existe una cuenta en el dispositivo para el mismo usuario y servidor + El usuario ingresado no corresponde con el usuario de esta cuenta + Versión del servidor no reconocida + Conexión establecida + Dirección del servidor https://… + El formato de dirección para el servidor es erróneo + El servidor no se encontró + No hay conexión de red + Conexión segura no disponible. + La configuración del servidor está mal formada. + Autorización no exitosa + Acceso denegado por el servidor de autorización + La conexión segura se está redirigiendo a través de una ruta insegura. + Conexión segura establecida + Falla en la inicialización de SSL + No fue posible verificar la identidad del servidor SSL + Probando conexión + El servidor tardó demasiado en responder + Intentando iniciar sesión… + Nombre de usuario o contraseña incorrecto + Error desconocido: %1$s + ¡Se presentó un error HTTP desconocido! + ¡Se presentó un error desconocido! + No fue posible encontrar el servidor + %1$s no soporta cuentas múltiples + No fue posible establecer la conexión + Solo cargar sobre una Wi-Fi no tarificada + /CargaAutomática + Crear nueva configuración de carpeta personalizada + Configurar una carpeta personalizada + Avatar + Cerrar + Deshabilitar + Calendario + Se presentó un problema al cargar el certificado. + Casilla de verificación + Elige la carpeta local… + Elige la carpeta remota… + Texto copiado desde %1$s + No se ha recibido texto para copiar al portapapeles + Se presentó un error inesperado al copiar al portapapeles + Atrás + Cancelar + Cancelar sincronización + Selecciona una cuenta + Confirmar + Copiar + Borrar + Error + Memoria insuficiente + Error desconocido + Cargando + Siguiente + No + OK + Pendiente + Eliminar + Renombrar + Guardar + Enviar + Compartir + Omitir + + Probar la versión de desarrollo + Esto incluye todas las últimas funcionalidades y es lo más nuevo. Fallas/errores pueden ocurrir y si es el caso, por favor repórtanoslo. + foro + Ayuda a otros en + Contribuye activamente + la aplicación + Traducir + Obtén la liberación de desarrollo directamente + Obtén la liberación de desarrollo de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de Google Play + Candidato a lanzamiento + El candidato a lanzamiento (RC) es una foto del lanzamiento más próximo y se espera que sea estable. Hacer preubas en tu configuración individual puede ayudarnos a asegurar ésto. Anótate para probar en la Play store o consulta manualmente la sección de \"Versión\" de F-Droid. + ¿Encontraste una falla? ¿Hay algo raro? + Ayúdanos probando + Reporta un tema en GitHub + ¿Realmente deseas elminiar %1$s? + ¿Realmente deseas borrar los elementos seleccionados? + ¿Realmente quieres eliminar %1$s y sus contenidos? + ¿Reamente deseas eliminar los elementos seleccionados y sus contenidos? + Sólo local + Ícono de usuario para la lista de contactos + No se han otorgado privilegios, nada fue importado. + Contactos + Respaldar ahora + El respaldo está calendarizado y deberá iniciar en breve + La importación está calendarizada y deberá iniciar en breve + No se encontraron archivos + ¡No fue posible encontrar tu último respaldo! + Copiado al portapapeles + Se presentó un error al intentar copiar este archivo o carpeta + No es posible copiar una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta destino + Copiar liga + Copiar/ mover a la carpeta encriptada no se encuentra soportado por el momento. + Crear + No fue posible crear la carpeta + Nuevo + Carpeta nueva + Cerrar sesión + Deseleccionar todo + Nueva versión disponible + No hay información disponible. + No hay una nueva versión disponible. + Cerrar + Este algoritmo de verificación no está disponible en tu teléfono + Deshabilitar + Descartar + Terminado + No fue posible descargar %1$s + La descarga falló, inicia sesión de nuevo + Falla en la descarga + El archivo ya no se encuentra disponible en el servidor + %1$d%% Descargando %2$s + Descargando… + %1$s descargado + Descargado + Aún no ha descargado + Imagen de fondo para el encabezado de la barra de navegación + Actividades + Todos los archivos + Favoritos + Inicio + Notificaciones + Disponibles sin conexión + Modificado recientemente + Compartido + Papelera + Cargas + Cerrar sesión + %1$s de %2$s usados + Carga automática + Hablar + Establecer como encriptado + Configurar la encripción + Desencriptando… + Cerrar + Por favor ingresa la contraseña para desencriptar la llave privada. + Esta carpeta no está vacía. + Generando nuevas llaves… + Las 12 palabras juntas hacer una contraseña muy fuerte, permitiéndote solo a ti ver y hacer uso de tus archivos encriptados. Por favor escríbelo y mantenlo en un lugar seguro. + La encripción de punta-a-punta está dehabilitada en el servidor. + Anota tu contraseña de encripción de 12 palabras + Contraseña… + Recuperando llaves… + Almacenando llaves + Configurar encripción + No se pudieron guardar las llaves, por favor vuelve a intentarlo. + Se presentó un error al desencriptar. ¿Contraseña equivocada? + %1$s no pudo ser copiado a la carpeta local %2$s + Error crítico: No se pueden realizar operaciones + Cuentas + Creado + Usuario + Trabajos en segundo plano + Descargar + Cargar + Agregar a tus favoritos + Hacer favorito + Borrar + Archivo + Carga algún contenido o sincroniza con tus dispositivos. + Aún no hay nada marcado como favorito + No hay archivos aquí + No hay resultados en esta carpeta + No hay resultados + No hay nada aquí. Puedes agregar una carpeta. + No se encontraron archivos modificados dentro de los últimos 7 días + ¿Tal vez está dentro de una carpeta diferente? + Aún no hay nada compartido + carpeta + Cargando… + No se cuenta con una aplicación que maneje este tipo de archivo. + hace algunos segundos + Verificando el destino… + Limpiando… + La carpeta de datos ya existe. Selecciona una de las siguientes: + La carpeta Nextcloud ya existe + Se necesita más espacio + No fue posible leer el archivo fuente + No fue posible escribir al archivo destino + Se presentó una falla durante la migración + Se presentó una falla al actualizar el índice + Moviendo los datos… + Terminado + Reemplazar + Preparando la migración… + Restaurando la configuración de la cuenta… + Guardando la configuración de la cuenta… + ¡No se puede leer la carpeta fuente! + Actualizando índice… + Usar + Aguardando sincronización completa… + Archivo no encontrado + El archivo no pudo ser sincronizado. Mostrando la última versión disponible. + Renombrar + Detalles + Descargar + Exportar + El archivo se renombró com %1$s durante la carga + Sincronizar + No se ha seleccionado algún archivo + El nombre del archivo no puede estar en blanco. + Caracteres inválidos: / \\ < > : \" | ? * + El nombre del archivo contiene al menos un carácter inválido + Nombre del archivo + Crear + No hay carpetas aquí + Seleccionar + Mover + No se te permite %s + para copiar este archivo + para crear este archivo + para borrar este archivo + para mover este archivo + para renombrar este archivo + Cargando archivos… + Algunos archivos no se pudieron mover + Local: %1$s + Mover todos + Remoto: %1$s + Se han movido todos los archivos + Adelante + Nombre + Contraseña + Cargar archivos sólo con el dispositivo conectado a la toma de corriente + /Cargas Automáticas + Invisible + Liga + Permitir carga y edición + Permitir carga + Vista de lista + No hay archivos en esta carpeta + No se encontró el archivo en el sistema de archivos local + No hay más carpetas. +  %1$s bitácora de aplicación Android + Iniciar sesión + Actualizar + Cargando... + Bitácoras + Borrar datos + Las configuraciones, base de datos y certificados del servidor de los datos de %1$s serán borrados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. + Administrar espacio + No fue posible leer el archivo de medios + El archivo de medios tiene una codificación incorrecta + El intento de reproducir el archivo sobrepasó el tiempo de espera + El reproductor de medios integrado es incapaz de reproducir el archivo de medios + Codec no soportado + Botón de avanzar rápido + Reproductor de música %1$s + Botón de reproducir o pausar + Botón de rebobinar + %1$s (reproduciendo) + Más reciente primero + Más antiguo primero + A - Z + Z - A + Más grande primero + Más pequeño primero + Más + Se presentó un error al intentar mover este archivo o carpeta + No es posible mover una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta de destino + Se presentó un error durante la conexión al servidor + foto + Muestra el progreso de la descarga + Descargas + Muestra el progreso de la sincronización de archivos y los resultados + Sincronizar archivo + Progreso del reproductor de música + Reproductor de medios + Mostrar las notificaciones push enviadas por el servidor: Menciones en comentarios, recepción de nuevos elementos compartidos remotos, anuncios publicados por el administrador, etc. + Notificaciones push + Muestra el progreso de la carga + Cargas + No hay notificaciones + Por favor verifica más tarde. + 1 hora + Ingresa tu código de seguridad + El código de seguridad será solicitado cada vez que inicie la aplicación + Por favor ingresa tu código de seguridad + Los códigos de seguridad no son iguales + Por favor reingresa el código de seguridad + Elimina tu código de seguirdad + Código de seguirdad eliminado + Código de seguridad almacenado + Código de seguridad incorrecto + Se requieren permisos adicionales para cargar y descargar archivos. + No se encontró una aplicación con la cual establecer la imagen + 389 KB + marcadordeposición.txt + 12:23:45 + Este es un marcador de posición + 2012/05/18 12:23 PM + Borrado + mantenido en la carpeta original + movido a la carpeta de la aplicación + Agregar cuenta + No ha sido instalado ni F-Droid o Google Play + Acerca de + Detalles + Desarrollo + General + Más + Sincronizar + Respaldo diario de tus contactos + GNU Licencia Pública General, versión 2 + Ayuda + Exención de responsabilidad + El archivo original será… + El archivo original será… + Usar sub carpetas + Licencia + Ninguno + Administrar cuentas + Mostrar archivos ocultos + Obtener el código fuente + Carpeta local + Carpeta remota + Tema + Oscuro + Claro + Vista previa de imagen + No existe un archivo local a previsualizar + No es posible mostrar la imagen + Disculpa + Privacidad + Las notificaciones push están deshabilitadas debido a dependencias de servicios propietarios de Google Play. + No hay notificaciones push debido a un inicio de sesión caduco. Por favor vuelve a ingresar a tu cuenta. + En este momento las notificaciones push no están disponibles. + ¡Prueba %1$s en tu dispositivo! + Quiero invitarte a usar %1$s en tu dispositivo\nDescárgalo aquí:%2$s + %1$s ó %2$s + Volver a cargar + Falla al eliminar + Eliminar + Eliminado + Ingresa un nombre nuevo + No se pudo renombrar la copia local, intenta con un nombre diferente + No fue posible renombrar, el nombre ya está ocupado + No se permite volver a compartir + No está permitido recompartir + No hay una imagen a escala disponible. ¿Descargar la imagen completa? + Reintentar + Seleccionar todo + Enviar + Ícono de botón de envío + Establecer Como + Usar imagen como + Compartir + Compartiendo + Compartir %1$s + %1$s (grupo) + Compartir liga + Debes ingresar una contraseña + para compartir este archivo + Ingresa una contraseña + Establecer fecha de expiración + Establecer contraseña + Puede editar + %1$s (remoto) + Configuraciones + Compartir liga + Compartir con… + compartido + Ordenar por + Ocultar + Detalles + La identidad del servidor no pudo ser verificada + País: + Nombre común: + Ubicación: + Organización: + Unidad organizacional: + Estado: + Huella digital: + Emitido por: + Firma: + Algoritmo: + Emitido para: + Validez: + De: + Para: + - No hay información acerca del error + No fue posible guardar el certificado + El certificado no puede ser mostrado. + ¿Quieres confiar en este certificado de todas formas? + - El certificado del servidor expiró + - El certificado del servidor no es de confianza + - Las fechas del certificado del servidor están en el futuro + - La URL no corresponde con el nombre del servidor en el certificado + Mensaje de estado + Predeterminado + Descargas + \"%1$s\" ha sido compartido contigo + %1$s ha compartido \"%2$s\" contigo + Sincronizar + Se encontraron conflictos + La carpeta %1$s ya no existe + No fue posible sincronizar %1$s + Contraseña equivocada para %1$s + Falla en archivos mantenidos-en-sincronización. + Falla en la sincronización + La sincronización falló, inicia sesión de nuevo + Los contenidos del archivo ya han sido sincronizados + A partir de la versión 1.3.16, los archivos cargados desde este dispositivo serán copiados a la carpeta local %1$s para prevenir pérdidas de datos cuando un archivo se sincroniza entre múltiples cuentas. \n\nDerivado de este cambio, todos los archivos cargados con versiones anteriores de la aplicación fueron copiados a la carpeta %2$s. Sin embargo, un error evitó que se completara esta operación durante la sincronización de la cuenta. Puedes dejar el(los) archivo(s) como está(n) y eliminar la liga a %3$s, o bien, mover el(los) archivo(s) a la carpeta %1$s y mantener la liga a %4$s.\n\nSe enlistan a continuación los archivos locales así como los archivos remotos en %5$s a donde estaban ligados + Algunos archivos locales se han perdido + Obteniendo la versión más reciente del archivo. + Botón de status de sincronización + Archivos + Botón de configuración + Configurar carpetas + Las cargas instantáneas se han mejorado por completo. Re-configura tu carga automática desde el menú principal.\n\nDisfruta la nueva y mejorada carga automática. + Para %1$s + Tipo + Etiquetas + Probar la conexión del servidor + 30 minutos + Esta semana + Miniatura + Hoy + Papelera + No hay archivos borrados + Borrar permanentemente + Desestablecer encripción + para dejar de compartir este archivo + Accede a través de un dominio no de confianza. Por favor consulta la documentación para más información. + para actualizar este recurso compartido + Borrar cargas fallidas + Reintentar cargas fallidas + Cargar forma… + Cargar contenido de otras aplicaciones + Nombre de archivo + Tipo de archivo + Archivo de acceso directo a Google Maps(%s) + Archivo de acceso directo a Internet(%s) + Archivo snippet de texto(.txt) + Ingresa el nombre y el tipo del archivo a cargar + Cargar archivos + Botón de cargar elemento + Borrar + No hay cargas disponibles + Carga algún contenido o activa la carga automática + El espacio insuficiente evita que se copien los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría moverlos ahí en su lugar? + Error desconocido + Seleccionar + Cargar + La información recibida no contiene un archivo válido. + %1$s no tiene permitido leer un archivo recibido + No fue posible copiar el archivo a una carpeta temporal. Por favor intenta enviarlo de nuevo. + El archivo seleccionado para cargar no fue encontrado. Por favor verifica si el archivo existe. + No hay un archivo a cargar + Nombre de la carpeta + Selecciona la carpeta de cargas + No fue posible cargar %1$s + La carga falló, inicia sesión de nuevo + Falla en la carga + Opción de carga: + Mover el archivo a la carpeta %1$s + Mantener el archivo en la carpeta de origen + Borrar el archivo de la carpeta de origen + para cargar a esta carpeta + %1$d%% Cargando %2$s + Cargando + %1$s cargado + Salir + Ajustes + No existen cuentas %1$s en tu dispositivo. Por favor configura una cuenta primero. + No se encontró la cuenta + Actual + Fallido/pendiente de reinicio + Cargado + Cancelado + Esperando para cargar + Cargas + Cancelado + Conflicto + Error de conexión + Error de credenciales + Error de archivo + Error de carpeta + No se encontró el archivo local + Error de permisos + El certificado del servidor no es de confianza + La aplicación ha sido terminada + Completado + Error desconocido + Virus detectado. ¡La carga no puede ser completada! + Esperando a salir de modo de conservación de energía + Aguardando la recarga del dispositivo + Usuario + Dirección + Correo electrónico + Número telefónico + Twitter + Sitio web + Error al extraer la información del usuario + No se ha establecido la información personal + Agrega tu nombre, una imagen y detalles de contacto en tu página de perfil. + Usuario + Descargar + Aguarda un momento… + Verificando credenciales almacenadas + Copiando el archivo desde almacenamiento privado + Actualizar + Imagen de qué es nuevo + Omitir + Nuevo en %1$s + Descargando archivos… + Enviar correo electrónico + diff --git a/app/src/main/res/values-es-rDO/strings.xml b/app/src/main/res/values-es-rDO/strings.xml new file mode 100644 index 000000000000..48de6bf41681 --- /dev/null +++ b/app/src/main/res/values-es-rDO/strings.xml @@ -0,0 +1,561 @@ + + + %1$s aplicación Android + Acerca de + versión %1$s + version %1$s, build #%2$s + Error al crear la cuenta + Ícono de la cuenta + ¡No se encontró la cuenta! + Editar + Borrar todas las notificaciones + Enviar/Compartir + Vista de cuadrícula + Vista de lista + Nueva carpeta + Abrir con + Buscar + Detalles + Enviar + Configuraciones + Ordenar + Usuario activo + Aún no hay actividades + Aún no hay eventos como adiciones, cambios y acciones. + Enviar + Enviar liga a… + Actividad + Añadir otro enlace + Agregar nuevo enlace para compartir público + Agregar a %1$s + Permitir volver a compartir + Buscar en %s + Todos + Completado + Desconocido + ¡Cuenta asociada no encontrada! + Error de acceso: %1$s + La cuenta aún no ha sido agregada a este dispositivo + Ya existe una cuenta en el dispositivo para el mismo usuario y servidor + El usuario ingresado no corresponde con el usuario de esta cuenta + Versión del servidor no reconocida + Conexión establecida + Su servidor no devuelve una identificación de usuario correcta, comuníquese con un administrador. + Dirección del servidor https://… + El formato de dirección para el servidor es erróneo + El servidor no se encontró + No hay conexión de red + Conexión segura no disponible. + La configuración del servidor está mal formada. + Autorización no exitosa + Acceso denegado por el servidor de autorización + La conexión segura se está redirigiendo a través de una ruta insegura. + Conexión segura establecida + Falla en la inicialización de SSL + No fue posible verificar la identidad del servidor SSL + Probando conexión + El servidor tardó demasiado en responder + Intentando iniciar sesión… + Nombre de usuario o contraseña incorrecto + Error desconocido: %1$s + ¡Se presentó un error HTTP desconocido! + ¡Se presentó un error desconocido! + No fue posible encontrar el servidor + %1$s no soporta cuentas múltiples + No fue posible establecer la conexión + Guardado en el carpeta original, ya que es solo lectura + Solo cargar sobre una Wi-Fi no tarificada + /CargaAutomática + Configurar + Crear nueva configuración de carpeta personalizada + Configurar una carpeta personalizada + Ocultar carpeta + Avatar + Lejos + Cerrar + Deshabilitar + Favoritos + Todos los archivos + Calendario + Se presentó un problema al cargar el certificado. + Casilla de verificación + Elige la carpeta local… + Elige la carpeta remota… + Texto copiado desde %1$s + No se ha recibido texto para copiar al portapapeles + Se presentó un error inesperado al copiar al portapapeles + Atrás + Cancelar + Cancelar sincronización + Selecciona una cuenta + Confirmar + Copiar + Borrar + Error + Memoria insuficiente + Error desconocido + Cargando + Siguiente + No + OK + Pendiente + Eliminar + Renombrar + Guardar + Enviar + Compartir + Omitir + + Probar la versión de desarrollo + Esto incluye todas las últimas funcionalidades y es lo más nuevo. Fallas/errores pueden ocurrir y si es el caso, por favor repórtanoslo. + foro + Ayuda a otros en + Contribuye activamente + la aplicación + Traducir + Obtén la liberación de desarrollo directamente + Obtén la liberación de desarrollo de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de Google Play + Candidato a lanzamiento + El candidato a lanzamiento (RC) es una foto del lanzamiento más próximo y se espera que sea estable. Hacer preubas en tu configuración individual puede ayudarnos a asegurar ésto. Anótate para probar en la Play store o consulta manualmente la sección de \"Versión\" de F-Droid. + ¿Encontraste una falla? ¿Hay algo raro? + Ayúdanos probando + Reporta un tema en GitHub + Configurar + ¿Realmente deseas elminiar %1$s? + ¿Realmente deseas borrar los elementos seleccionados? + ¿Realmente quieres eliminar %1$s y sus contenidos? + ¿Reamente deseas eliminar los elementos seleccionados y sus contenidos? + Sólo local + Ícono de usuario para la lista de contactos + No se han otorgado privilegios, nada fue importado. + Contactos + Respaldar ahora + El respaldo está calendarizado y deberá iniciar en breve + La importación está calendarizada y deberá iniciar en breve + No se encontraron archivos + ¡No fue posible encontrar tu último respaldo! + Copiado al portapapeles + Se presentó un error al intentar copiar este archivo o carpeta + No es posible copiar una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta destino + Copiar liga + Copiar/ mover a la carpeta encriptada no se encuentra soportado por el momento. + Crear + No fue posible crear la carpeta + Nuevo + Carpeta nueva  + Cerrar sesión + Deseleccionar todo + Nueva versión disponible + No hay información disponible. + No hay una nueva versión disponible. + Cerrar + Este algoritmo de verificación no está disponible en tu teléfono + Deshabilitar + Descartar + Terminado + No fue posible descargar %1$s + La descarga falló, inicia sesión de nuevo + Falla en la descarga + El archivo ya no se encuentra disponible en el servidor + %1$d%% Descargando %2$s + Descargando… + %1$s descargado + Descargado + Aún no ha descargado + Imagen de fondo para el encabezado de la barra de navegación + Actividades + Todos los archivos + Favoritos + Inicio + Notificaciones + Disponibles sin conexión + Modificado recientemente + Compartido + Papelera + Cargas + Cerrar sesión + %1$s de %2$s usados + Carga automática + Hablar + Establecer como encriptado + Configurar la encripción + Desencriptando… + Cerrar + Por favor ingresa la contraseña para desencriptar la llave privada. + Esta carpeta no está vacía. + Generando nuevas llaves… + Las 12 palabras juntas hacer una contraseña muy fuerte, permitiéndote solo a ti ver y hacer uso de tus archivos encriptados. Por favor escríbelo y mantenlo en un lugar seguro. + La encripción de punta-a-punta está dehabilitada en el servidor. + Anota tu contraseña de encripción de 12 palabras + Contraseña… + Recuperando llaves… + Almacenando llaves + Configurar encripción + No se pudieron guardar las llaves, por favor vuelve a intentarlo. + Se presentó un error al desencriptar. ¿Contraseña equivocada? + %1$s no pudo ser copiado a la carpeta local %2$s + Error crítico: No se pueden realizar operaciones + Cuentas + Creado + Usuario + Trabajos en segundo plano + Descargar + Cargar + Agregar a tus favoritos + Hacer favorito + Borrar + Archivo + Carga algún contenido o sincroniza con tus dispositivos. + Aún no hay nada marcado como favorito + No hay archivos aquí + No hay resultados en esta carpeta + No hay resultados + No hay nada aquí. Puedes agregar una carpeta. + No se encontraron archivos modificados dentro de los últimos 7 días + ¿Tal vez está dentro de una carpeta diferente? + Aún no hay nada compartido + carpeta + Cargando… + No se cuenta con una aplicación que maneje este tipo de archivo. + hace algunos segundos + Verificando el destino… + Limpiando… + La carpeta de datos ya existe. Selecciona una de las siguientes: + La carpeta Nextcloud ya existe + Se necesita más espacio + No fue posible leer el archivo fuente + No fue posible escribir al archivo destino + Se presentó una falla durante la migración + Se presentó una falla al actualizar el índice + Moviendo los datos… + Terminado + Reemplazar + Preparando la migración… + Restaurando la configuración de la cuenta… + Guardando la configuración de la cuenta… + ¡No se puede leer la carpeta fuente! + Actualizando índice… + Usar + Aguardando sincronización completa… + Archivo no encontrado + El archivo no pudo ser sincronizado. Mostrando la última versión disponible. + Renombrar + Detalles + Descargar + Exportar + El archivo se renombró com %1$s durante la carga + Sincronizar + No se ha seleccionado algún archivo + El nombre del archivo no puede estar en blanco. + Caracteres inválidos: / \\ < > : \" | ? * + El nombre del archivo contiene al menos un carácter inválido + Nombre del archivo + Crear + No hay carpetas aquí + Seleccionar + Mover + No se te permite %s + para copiar este archivo + para crear este archivo + para borrar este archivo + para mover este archivo + para renombrar este archivo + Cargando archivos… + Algunos archivos no se pudieron mover + Local: %1$s + Mover todos + Remoto: %1$s + Se han movido todos los archivos + Adelante + Nombre + Contraseña + Cargar archivos sólo con el dispositivo conectado a la toma de corriente + /Cargas Automáticas + Invisible + Liga + Permitir carga y edición + Permitir carga + Vista de lista + No hay archivos en esta carpeta + No se encontró el archivo en el sistema de archivos local + No hay más carpetas. +  %1$s bitácora de aplicación Android + Iniciar sesión + Actualizar + Cargando... + Bitácoras + Borrar datos + Las configuraciones, base de datos y certificados del servidor de los datos de %1$s serán borrados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. + Administrar espacio + No fue posible leer el archivo de medios + El archivo de medios tiene una codificación incorrecta + El intento de reproducir el archivo sobrepasó el tiempo de espera + El reproductor de medios integrado es incapaz de reproducir el archivo de medios + Codec no soportado + Botón de avanzar rápido + Reproductor de música %1$s + Botón de reproducir o pausar + Botón de rebobinar + %1$s (reproduciendo) + Más reciente primero + Más antiguo primero + A - Z + Z - A + Más grande primero + Más pequeño primero + Más + Se presentó un error al intentar mover este archivo o carpeta + No es posible mover una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta de destino + Se presentó un error durante la conexión al servidor + foto + Muestra el progreso de la descarga + Descargas + Muestra el progreso de la sincronización de archivos y los resultados + Sincronizar archivo + Progreso del reproductor de música + Reproductor de medios + Mostrar las notificaciones push enviadas por el servidor: Menciones en comentarios, recepción de nuevos elementos compartidos remotos, anuncios publicados por el administrador, etc. + Notificaciones push + Muestra el progreso de la carga + Cargas + No hay notificaciones + Por favor verifica más tarde. + 1 hora + Ingresa tu código de seguridad + El código de seguridad será solicitado cada vez que inicie la aplicación + Por favor ingresa tu código de seguridad + Los códigos de seguridad no son iguales + Por favor reingresa el código de seguridad + Elimina tu código de seguirdad + Código de seguirdad eliminado + Código de seguridad almacenado + Código de seguridad incorrecto + Se requieren permisos adicionales para cargar y descargar archivos. + No se encontró una aplicación con la cual establecer la imagen + 389 KB + marcadordeposición.txt + 12:23:45 + Este es un marcador de posición + 2012/05/18 12:23 PM + Borrado + mantenido en la carpeta original + movido a la carpeta de la aplicación + Agregar cuenta + No ha sido instalado ni F-Droid o Google Play + Acerca de + Detalles + Desarrollo + General + Más + Sincronizar + Respaldo diario de tus contactos + GNU Licencia Pública General, versión 2 + Ayuda + Exención de responsabilidad + El archivo original será… + El archivo original será… + Usar sub carpetas + Licencia + Ninguno + Administrar cuentas + Mostrar archivos ocultos + Obtener el código fuente + Carpeta local + Carpeta remota + Tema + Oscuro + Claro + Vista previa de imagen + No existe un archivo local a previsualizar + No es posible mostrar la imagen + Disculpa + Privacidad + Las notificaciones push están deshabilitadas debido a dependencias de servicios propietarios de Google Play. + No hay notificaciones push debido a un inicio de sesión caduco. Por favor vuelve a ingresar a tu cuenta. + En este momento las notificaciones push no están disponibles. + ¡Prueba %1$s en tu dispositivo! + Quiero invitarte a usar %1$s en tu dispositivo\nDescárgalo aquí:%2$s + %1$s ó %2$s + Volver a cargar + Falla al eliminar + Eliminar + Eliminado + Ingresa un nombre nuevo + No se pudo renombrar la copia local, intenta con un nombre diferente + No fue posible renombrar, el nombre ya está ocupado + No hay una imagen a escala disponible. ¿Descargar la imagen completa? + Restaurar + Reintentar + Seleccionar todo + Enviar + Ícono de botón de envío + Establecer Como + Usar imagen como + Compartir + Compartiendo + Compartir %1$s + %1$s (grupo) + Compartir liga + Debes ingresar una contraseña + para compartir este archivo + Ingresa una contraseña + Establecer fecha de expiración + Establecer contraseña + Puede editar + %1$s (remoto) + Configuraciones + Compartir liga + Compartir con… + compartido + Ordenar por + Ocultar + Detalles + La identidad del servidor no pudo ser verificada + País: + Nombre común: + Ubicación: + Organización: + Unidad organizacional: + Estado: + Huella digital: + Emitido por: + Firma: + Algoritmo: + Emitido para: + Validez: + De: + Para: + - No hay información acerca del error + No fue posible guardar el certificado + El certificado no puede ser mostrado. + ¿Quieres confiar en este certificado de todas formas? + - El certificado del servidor expiró + - El certificado del servidor no es de confianza + - Las fechas del certificado del servidor están en el futuro + - La URL no corresponde con el nombre del servidor en el certificado + Mensaje de estado + Predeterminado + Descargas + Almacenamiento externo + \"%1$s\" ha sido compartido contigo + %1$s ha compartido \"%2$s\" contigo + Sincronizar + Se encontraron conflictos + La carpeta %1$s ya no existe + No fue posible sincronizar %1$s + Contraseña equivocada para %1$s + Falla en archivos mantenidos-en-sincronización. + Falla en la sincronización + La sincronización falló, inicia sesión de nuevo + Los contenidos del archivo ya han sido sincronizados + A partir de la versión 1.3.16, los archivos cargados desde este dispositivo serán copiados a la carpeta local %1$s para prevenir pérdidas de datos cuando un archivo se sincroniza entre múltiples cuentas. \n\nDerivado de este cambio, todos los archivos cargados con versiones anteriores de la aplicación fueron copiados a la carpeta %2$s. Sin embargo, un error evitó que se completara esta operación durante la sincronización de la cuenta. Puedes dejar el(los) archivo(s) como está(n) y eliminar la liga a %3$s, o bien, mover el(los) archivo(s) a la carpeta %1$s y mantener la liga a %4$s.\n\nSe enlistan a continuación los archivos locales así como los archivos remotos en %5$s a donde estaban ligados + Algunos archivos locales se han perdido + Obteniendo la versión más reciente del archivo. + Botón de status de sincronización + Archivos + Botón de configuración + Configurar carpetas + Las cargas instantáneas se han mejorado por completo. Re-configura tu carga automática desde el menú principal.\n\nDisfruta la nueva y mejorada carga automática. + Para %1$s + Tipo + Etiquetas + Probar la conexión del servidor + 30 minutos + Esta semana + Miniatura + Hoy + Papelera + No hay archivos borrados + Borrar permanentemente + Desestablecer encripción + para dejar de compartir este archivo + Accede a través de un dominio no de confianza. Por favor consulta la documentación para más información. + para actualizar este recurso compartido + Borrar cargas fallidas + Reintentar cargas fallidas + Cargar forma… + Cargar contenido de otras aplicaciones + Foto + Nombre de archivo + Tipo de archivo + Archivo de acceso directo a Google Maps(%s) + Archivo de acceso directo a Internet(%s) + Archivo snippet de texto(.txt) + Ingresa el nombre y el tipo del archivo a cargar + Cargar archivos + Botón de cargar elemento + Borrar + No hay cargas disponibles + Carga algún contenido o activa la carga automática + El espacio insuficiente evita que se copien los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría moverlos ahí en su lugar? + Error desconocido + Seleccionar + Cargar + La información recibida no contiene un archivo válido. + %1$s no tiene permitido leer un archivo recibido + No fue posible copiar el archivo a una carpeta temporal. Por favor intenta enviarlo de nuevo. + El archivo seleccionado para cargar no fue encontrado. Por favor verifica si el archivo existe. + No hay un archivo a cargar + Nombre de la carpeta + Selecciona la carpeta de cargas + No fue posible cargar %1$s + La carga falló, inicia sesión de nuevo + Falla en la carga + Opción de carga: + Mover el archivo a la carpeta %1$s + Mantener el archivo en la carpeta de origen + Borrar el archivo de la carpeta de origen + para cargar a esta carpeta + %1$d%% Cargando %2$s + Cargando + %1$s cargado + Salir + Ajustes + No existen cuentas %1$s en tu dispositivo. Por favor configura una cuenta primero. + No se encontró la cuenta + Actual + Fallido/pendiente de reinicio + Cargado + Cancelado + Esperando para cargar + Cargas + Cancelado + Conflicto + Error de conexión + Error de credenciales + Error de archivo + Error de carpeta + No se encontró el archivo local + Error de permisos + El certificado del servidor no es de confianza + La aplicación ha sido terminada + Completado + Error desconocido + Virus detectado. ¡La carga no puede ser completada! + Esperando a salir de modo de conservación de energía + Aguardando la recarga del dispositivo + Usuario + Dirección + Correo electrónico + Número telefónico + Twitter + Sitio web + Error al extraer la información del usuario + No se ha establecido la información personal + Agrega tu nombre, una imagen y detalles de contacto en tu página de perfil. + Usuario + Descargar + Aguarda un momento… + Verificando credenciales almacenadas + Copiando el archivo desde almacenamiento privado + Actualizar + Imagen de qué es nuevo + Omitir + Nuevo en %1$s + Descargando archivos… + Enviar correo electrónico + diff --git a/app/src/main/res/values-es-rGT/strings.xml b/app/src/main/res/values-es-rGT/strings.xml new file mode 100644 index 000000000000..c47d5491337e --- /dev/null +++ b/app/src/main/res/values-es-rGT/strings.xml @@ -0,0 +1,544 @@ + + + %1$s aplicación Android + Acerca de + versión %1$s + Ícono de la cuenta + ¡No se encontró la cuenta! + Editar + Enviar/Compartir + Vista de cuadrícula + Vista de lista + Nueva carpeta + Abrir con + Buscar + Detalles + Enviar + Configuraciones + Ordenar + Usuario activo + Aún no hay actividades + Enviar + Enviar liga a… + Actividad + Agregar a %1$s + Permitir volver a compartir + Todos + Completado + Desconocido + La cuenta aún no ha sido agregada a este dispositivo + Ya existe una cuenta en el dispositivo para el mismo usuario y servidor + El usuario ingresado no corresponde con el usuario de esta cuenta + Versión del servidor no reconocida + Conexión establecida + Dirección del servidor https://… + El formato de dirección para el servidor es erróneo + El servidor no se encontró + No hay conexión de red + Conexión segura no disponible. + La configuración del servidor está mal formada. + Autorización no exitosa + Acceso denegado por el servidor de autorización + La conexión segura se está redirigiendo a través de una ruta insegura. + Conexión segura establecida + Falla en la inicialización de SSL + No fue posible verificar la identidad del servidor SSL + Probando conexión + El servidor tardó demasiado en responder + Intentando iniciar sesión… + Nombre de usuario o contraseña incorrecto + Error desconocido: %1$s + ¡Se presentó un error HTTP desconocido! + ¡Se presentó un error desconocido! + No fue posible encontrar el servidor + %1$s no soporta cuentas múltiples + No fue posible establecer la conexión + Solo cargar sobre una Wi-Fi no tarificada + /CargaAutomática + Crear nueva configuración de carpeta personalizada + Configurar una carpeta personalizada + Avatar + Cerrar + Deshabilitar + Calendario + Se presentó un problema al cargar el certificado. + Casilla de verificación + Elige la carpeta local… + Elige la carpeta remota… + Texto copiado desde %1$s + No se ha recibido texto para copiar al portapapeles + Se presentó un error inesperado al copiar al portapapeles + Atrás + Cancelar + Cancelar sincronización + Selecciona una cuenta + Confirmar + Copiar + Borrar + Error + Memoria insuficiente + Error desconocido + Cargando + Siguiente + No + OK + Pendiente + Eliminar + Renombrar + Guardar + Enviar + Compartir + Omitir + + Probar la versión de desarrollo + Esto incluye todas las últimas funcionalidades y es lo más nuevo. Fallas/errores pueden ocurrir y si es el caso, por favor repórtanoslo. + foro + Ayuda a otros en + Contribuye activamente + la aplicación + Traducir + Obten la liberación de desarrollo directamente + Obten la liberación de desarrollo de la tienda de aplicaciones F-Droid + Obten el candidato a liberación de la tienda de aplicaciones F-Droid + Obten el candidato a liberación de la tienda de Google Play + Candidato a lanzamiento + El candidato a lanzamiento (RC) es una foto del lanzamiento más próximo y se espera que sea estable. Hacer preubas en tu configuración individual puede ayudarnos a asegurar ésto. Anótate para probar en la Play store o consulta manualmente la sección de \"Versión\" de F-Droid. + ¿Encontraste una falla? ¿Hay algo raro? + Ayúdanos probando + Reporta un tema en GitHub + ¿Realmente deseas elminiar %1$s? + ¿Realmente deseas borrar los elementos seleccionados? + ¿Realmente quieres eliminar %1$s y sus contenidos? + ¿Reamente deseas eliminar los elementos seleccionados y sus contenidos? + Sólo local + Ícono de usuario para la lista de contactos + No se han otorgado privilegios, nada fue importado. + Contactos + Respaldar ahora + El respaldo está calendarizado y deberá iniciar en breve + La importación está calendarizada y deberá iniciar en breve + No se encontraron archivos + ¡No fue posible encontrar tu último respaldo! + Copiado al portapapeles + Se presentó un error al intentar copiar este archivo o carpeta + No es posible copiar una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta destino + Copiar liga + Copiar/ mover a la carpeta encriptada no se encuentra soportado por el momento. + Crear + No fue posible crear la carpeta + Nuevo + Carpeta nueva  + Cerrar sesión + Deseleccionar todo + Nueva versión disponible + No hay información disponible. + No hay una nueva versión disponible. + Cerrar + Este algoritmo de verificación no está disponible en tu teléfono + Deshabilitar + Descartar + Terminado + No fue posible descargar %1$s + La descarga falló, inicia sesión de nuevo + Falla en la descarga + El archivo ya no se encuentra disponible en el servidor + %1$d%% Descargando %2$s + Descargando… + %1$s descargado + Descargado + Aún no ha descargado + Imagen de fondo para el encabezado de la barra de navegación + Actividades + Todos los archivos + Favoritos + Inicio + Notificaciones + Disponibles sin conexión + Modificado recientemente + Compartido + Papelera + Cargas + Cerrar sesión + %1$s de %2$s usados + Carga automática + Hablar + Establecer como encriptado + Configurar la encripción + Decriptando… + Cerrar + Por favor ingresa la contraseña para decrpitar la llave privada. + Esta carpeta no está vacía. + Generando nuevas llaves… + Las 12 palabras juntas hacer una contraseña muy fuerte, permitiendote solo a ti ver y hacer uso de tus archivos encriptados. Por favor escríbelo y mantenlo en un lugar seguro. + La encripción de punta-a-punta está dehabilitada en el servidor. + Anota tu contraseña de encripción de 12 palabras + Contraseña… + Recuperando llaves… + Almacenando llaves + Configurar encripción + No se pudieron guardar las llaves, por favor vuelve a intentarlo. + Se presentó un error al decriptar. ¿Contraseña equivocada? + %1$s no pudo ser copiado a la carpeta local %2$s + Error crítico: No se pueden realizar operaciones + Cuentas + Creado + Ususario + Trabajos en segundo plano + Descargar + Cargar + Agregar a tus favoritos + Hacer favorito + Borrar + Archivo + Carga algún contenido o sincroniza con tus dispositivos. + Aún no hay nada marcado como favorito + No hay archivos aquí + No hay resultados en esta carpeta + No hay resultados + No hay nada aquí. Puedes agregar una carpeta. + No se encontraron archivos modificados dentro de los últimos 7 días + ¿Tal vez está dentro de una carpeta diferente? + Aún no hay nada compartido + carpeta + Cargando… + No se cuenta con una aplicación que maneje este tipo de achivo. + hace algunos segundos + Verificando el destino… + Limpiando… + La carpeta de datos ya existe. Selecciona una de las siguientes: + La carpeta Nextcloud ya existe + Se necesita más espacio + No fue posible leer el archivo fuente + No fue posible escribir al archivo destino + Se presentó una falla durante la migración + Se presentó una falla al actualizar el índice + Moviendo los datos… + Terminado + Reemplazar + Preparando la migración… + Restaurando la configuración de la cuenta… + Guardando la configuración de la cuenta… + ¡No se puede leer la carpeta fuente! + Actualizando índice… + Usar + Agurardando sincronización completa… + Archivo no encontrado + El archivo no pudo ser sincronizado. Mostrando la última versión disponible. + Renombrar + Detalles + Descargar + Exportar + El archivo se renombró com %1$s durante la carga + Syncronizar + No se ha seleccionado algún archivo + El nombre del archivo no puede estar en blanco. + Caracteres inválidos: / \\ < > : \" | ? * + El nombre del archivo contiene al menos un carácter inválido + Nombre del archivo + Crear + No hay carpetas aquí + Seleccionar + Mover + No se te permite %s + para copiar este archivo + para crear este archivo + para borrar este archivo + para mover este archivo + para renombrar este archivo + Cargando archivos… + Algunos archivos no se pudieron mover + Local: %1$s + Mover todos + Remoto: %1$s + Se han movido todos los archivos + Adelante + Nombre + Contraseña + Cargar archivos sólo con el dispositivo conectado a la toma de corriente + /Cargas Automáticas + Invisible + Liga + Permitir carga y edición + Permitir carga + Vista de lista + No hay archivos en esta carpeta + No se encontró el archivo en el sistema de archivos local + No hay más carpetas. +  %1$s bitácora de aplicación Android + Iniciar sesión + Actualizar + Cargando... + Bitácoras + Borrar datos + Las configuraciones, base de datos y certificados del servior de los datos de %1$s serán borrados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. + Administrar espacio + No fue posible leer el archivo de medios + El archivo de medios tiene una codificación incorrecta + El intento de reproducir el archivo sobrepasó el tiempo de espera + El reproductor de medios integrado es incapaz de reproducir el archivo de medios + Codec no soportado + Botón de avanzar rápido + Reproductor de músca %1$s + Botón de reproducir o pausar + Botón de rebobinar + %1$s (reproduciendo) + Más reciente primero + Más antiguo primero + A - Z + Z - A + Más grande primero + Más pequeño primero + Más + Se presentó un error al intentar mover este archivo o carpeta + No es posible mover una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta de destino + Se presentó un error durante la conexión al servidor + foto + Muestra el progreso de la descarga + Descargas + Muestra el progreso de la sincronización de archivos y los resultados + Sincronizar archivo + Progreso del reproductor de música + Reproductor de medios + Mostrar las notificaciones push enviadas por el servidor: Menciones en comentarios, recepción de nuevos elementos compartidos remotos, anuncios publicados por el administrador, etc. + Notificaciones push + Muestra el progreso de la carga + Cargas + No hay notificaciones + Por favor verifica más tarde. + 1 hora + Ingresa tu código de seguridad + El código de seguridad será solicitado cada vez que inicie la aplicación + Por favor ingresa tu código de seguridad + Los códigos de seguridad no son iguales + Por favor reingresa el código de seguridad + Elimina tu código de seguirdad + Código de seguirdad eliminado + Código de seguridad almacenado + Código de seguridad incorrecto + Se requieren permisos adicionales para cargar y descargar archivos. + No se encontró una aplicación con la cual establecer la imagen + 389 KB + marcadordeposición.txt + 12:23:45 + Este es un marcador de posición + 2012/05/18 12:23 PM + Borrado + mantenido en la carpeta original + movido a la capreta de la aplicación + Agregar cuenta + No ha sido instalado ni F-Droid o Google Play + Acerca de + Detalles + Desarrollo + General + Más + Syncronizar + Respaldo diario de tus contactos + GNU Licencia Pública General, versión 2 + Ayuda + Excención de responsabilidad + El archivo original será… + El archivo original será… + Usar sub carpetas + Licencia + Ninguno + Administrar cuentas + Mostrar archivos ocultos + Obtener el código fuente + Carpeta local + Carpeta remota + Tema + Oscuro + Claro + Vista previa de imagen + No existe un archivo local a previsualizar + No es posible mostrar la imagen + Disculpa + Privacidad + Las notificaciones push están deshabilitadas debido a dependencias de servicios propietarios de Google Play. + No hay notificaciones push debido a un incio de sesión caduco. Por favor vuelve a ingresar a tu cuenta. + En este momento las notificaciones push no están disponibles. + ¡Prueba %1$s en tu dispositivo! + Quiero invitarte a usar %1$s en tu dispositivo\nDescargalo aquí:%2$s + %1$s ó %2$s + Volver a cargar + Falla al eliminar + Eliminar + Eliminado + Ingresa un nombre nuevo + No se pudo renombrar la copia local, intenta con un nombre diferente + No fue posible renombrar, el nombre ya esta ocupado + No se permite volver a compartir + No está permitido recompartir + No hay una imagen a escala disponible. ¿Descargar la imagen completa? + Reintentar + Seleccionar todo + Enviar + Ícono de botón de envío + Establecer Como + Usar imagen como + Compartir + Compartiendo + Compartir %1$s + %1$s (grupo) + Compartir liga + Debes ingresar una contraseña + para compartir este archivo + Ingresa una contraseña + Establecer fecha de expiración + Establecer contraseña + Puede editar + %1$s (remoto) + Configuraciones + Compartir liga + Compartir con… + compartido + Ordenar por + Ocultar + Detalles + La identidad del servidor no pudo ser verificada + País: + Nombre común: + Ubicación: + Organización: + Unidad organizacional: + Estado: + Huella digital: + Emitido por: + Firma: + Algoritmo: + Emitido para: + Validez: + De: + Para: + - No hay información acerca del error + No fue posible guardar el certificado + El certificado no puede ser mostrado. + ¿Quieres confiar en este certificado de todas formas? + - El certificado del servidor expiró + - El certificado del servidor no es de confianza + - Las fechas del certificado del servidor están en el futuro + - La URL no corresponde con el nombre del servidor en el certificado + Mensaje de estado + Predeterminado + Descargas + \"%1$s\" ha sido compartido contigo + %1$s ha compartido \"%2$s\" contigo + Syncronizar + Se encontraron conflictos + La carpeta %1$s ya no existe + No fue posible sincronizar %1$s + Contraseña equivocada para %1$s + Falla en archivos mantenidos-en-sincronización. + Falla en la sincronización + La sincronización falló, inicia sesión de nuevo + Los contenidos del archivo ya han sido sincronizados + A partir de la versión 1.3.16, los archivos cargados desde este dispositivo serán copiados a la carpeta local %1$spara prevenir perdidas de datos cuando un archivo se sincroniza entre múltiples cuentas. \n\nDerivado de este cambio, todos los archivos cargados con versiones anteriores de la aplicación fueron copiados a la carpeta %2$s. Sin embargo, un error evitó que se completara esta operación durante la sincronizacion de la cuenta. Puedes dejar el(los) archivo(s) como está(n) y eliminar la liga a %3$s, o bien, mover el(los) archivo(s) a la carpeta%1$s y mantener la liga a %4$s.\n\nSe enlistan a continuación los archivos locales así como los archivos remotos en %5$s a donde estaban ligados + Algunos archivos locales se han perdido + Obteniendo la versión más reciente del archivo. + Botón de status de sincronización + Archivos + Botón de configuración + Configurar carpetas + Las cargas instantaneas se han mejorado por completo. Re-configura tu carga automática desde el menú principal.\n\nDisfruta la nueva y mejorada carga automática. + Para %1$s + Tipo + Etiquetas + Probar la conexión del servidor + 30 minutos + Esta semana + Miniatura + Hoy + Papelera + No hay archivos borrados + Borrar permanentemente + Desestablecer encripción + para dejar de compartir este archivo + Accede a través de un dominio no de confianza. Por favor consulta la documentación para más información. + para actualizar este recurso compartido + Borrar cargas fallidas + Reintentar cargas fallidas + Cargar forma… + Cargar contenido de otras aplicaciones + Foto + Nombre de archivo + Tipo de archivo + Archivo de acceso directo a Google Maps(%s) + Archivo de acceso directo a Internet(%s) + Archivo snippet de texto(.txt) + Ingresa el nombre y el tipo del archivo a cargar + Cargar archivos + Botón de cargar elemento + Borrar + No hay cargas disponibles + Carga algún contenido o activa la carga automática + El espacio insuficiente evita que se copien los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría moverlos ahí en su lugar? + Error desconocido + Seleccionar + Cargar + La información recibida no contiene un archivo válido. + %1$s no tiene permitido leer un archivo recibido + No fue posible copiar el archivo a una carpeta temporal. Por favor intenta enviarlo de nuevo. + El archivo seleccionado para cargar no fue encontrado. Por favor verifica si el archivo existe. + No hay un archivo a cargar + Nombre de la carpeta + Selecciona la carpeta de cargas + No fue posible cargar %1$s + La carga falló, inicia sesión de nuevo + Falla en la carga + Opción de carga: + Mover el archivo a la carpeta %1$s + Mantener el archivo en la carpeta de origen + Borrar el archivo de la carpeta de origen + para cargar a esta carpeta + %1$d%% Cargando %2$s + Cargando + %1$s cargado + Salir + Ajustes + No existen cuentas %1$s en tu dispositivo. Por favor configura una cuenta primero. + No se encontró la cuenta + Actual + Fallido/pendiente de reinicio + Cargado + Cancelado + Esperando para cargar + Cargas + Cancelado + Conflicto + Error de conexión + Error de credenciales + Error de archivo + Error de carpeta + No se encontró el archivo local + Error de permisos + El certificado del servidor no es de confianza + La aplicación ha sido terminada + Completado + Error desconocido + Virus detectado. ¡La carga no puede ser completada! + Esperando a salir de modo de conservación de energía + Aguardando la recarga del dispositivo + Ususario + Dirección + Correo electrónico + Número telefónico + Twitter + Sitio web + Error al extraer la información del usuario + No se ha establecido la información personal + Agrega tu nombre, una imagen y detalles de contacto en tu página de perfil. + Usuario + Descargar + Agurarda un momento… + Verificando credenciales almacenadas + Copiando el archivo desde almacenamiento privado + Actualizar + Imagen de qué es nuevo + Omitir + Nuevo en %1$s + Descargando archivos… + Enviar correo electrónico + diff --git a/app/src/main/res/values-es-rSV/strings.xml b/app/src/main/res/values-es-rSV/strings.xml new file mode 100644 index 000000000000..6c80a6436bde --- /dev/null +++ b/app/src/main/res/values-es-rSV/strings.xml @@ -0,0 +1,544 @@ + + + %1$s aplicación Android + Acerca de + versión %1$s + Ícono de la cuenta + ¡No se encontró la cuenta! + Editar + Enviar/Compartir + Vista de cuadrícula + Vista de lista + Nueva carpeta + Abrir con + Buscar + Detalles + Enviar + Configuraciones + Ordenar + Usuario activo + Aún no hay actividades + Enviar + Enviar liga a… + Actividad + Agregar a %1$s + Permitir volver a compartir + Todos + Completado + Desconocido + La cuenta aún no ha sido agregada a este dispositivo + Ya existe una cuenta en el dispositivo para el mismo usuario y servidor + El usuario ingresado no corresponde con el usuario de esta cuenta + Versión del servidor no reconocida + Conexión establecida + Dirección del servidor https://… + El formato de dirección para el servidor es erróneo + El servidor no se encontró + No hay conexión de red + Conexión segura no disponible. + La configuración del servidor está mal formada. + Autorización no exitosa + Acceso denegado por el servidor de autorización + La conexión segura se está redirigiendo a través de una ruta insegura. + Conexión segura establecida + Falla en la inicialización de SSL + No fue posible verificar la identidad del servidor SSL + Probando conexión + El servidor tardó demasiado en responder + Intentando iniciar sesión… + Nombre de usuario o contraseña incorrecto + Error desconocido: %1$s + ¡Se presentó un error HTTP desconocido! + ¡Se presentó un error desconocido! + No fue posible encontrar el servidor + %1$s no soporta cuentas múltiples + No fue posible establecer la conexión + Solo cargar sobre una Wi-Fi no tarificada + /CargaAutomática + Crear nueva configuración de carpeta personalizada + Configurar una carpeta personalizada + Avatar + Cerrar + Deshabilitar + Calendario + Se presentó un problema al cargar el certificado. + Casilla de verificación + Elige la carpeta local… + Elige la carpeta remota… + Texto copiado desde %1$s + No se ha recibido texto para copiar al portapapeles + Se presentó un error inesperado al copiar al portapapeles + Atrás + Cancelar + Cancelar sincronización + Selecciona una cuenta + Confirmar + Copiar + Borrar + Error + Memoria insuficiente + Error desconocido + Cargando + Siguiente + No + OK + Pendiente + Eliminar + Renombrar + Guardar + Enviar + Compartir + Omitir + + Probar la versión de desarrollo + Esto incluye todas las últimas funcionalidades y es lo más nuevo. Fallas/errores pueden ocurrir y si es el caso, por favor repórtanoslo. + foro + Ayuda a otros en + Contribuye activamente + la aplicación + Traducir + Obtén la liberación de desarrollo directamente + Obtén la liberación de desarrollo de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de aplicaciones F-Droid + Obtén el candidato a liberación de la tienda de Google Play + Candidato a lanzamiento + El candidato a lanzamiento (RC) es una foto del lanzamiento más próximo y se espera que sea estable. Hacer preubas en tu configuración individual puede ayudarnos a asegurar ésto. Anótate para probar en la Play store o consulta manualmente la sección de \"Versión\" de F-Droid. + ¿Encontraste una falla? ¿Hay algo raro? + Ayúdanos probando + Reporta un tema en GitHub + ¿Realmente deseas elminiar %1$s? + ¿Realmente deseas borrar los elementos seleccionados? + ¿Realmente quieres eliminar %1$s y sus contenidos? + ¿Reamente deseas eliminar los elementos seleccionados y sus contenidos? + Sólo local + Ícono de usuario para la lista de contactos + No se han otorgado privilegios, nada fue importado. + Contactos + Respaldar ahora + El respaldo está calendarizado y deberá iniciar en breve + La importación está calendarizada y deberá iniciar en breve + No se encontraron archivos + ¡No fue posible encontrar tu último respaldo! + Copiado al portapapeles + Se presentó un error al intentar copiar este archivo o carpeta + No es posible copiar una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta destino + Copiar liga + Copiar/ mover a la carpeta encriptada no se encuentra soportado por el momento. + Crear + No fue posible crear la carpeta + Nuevo + Carpeta nueva  + Cerrar sesión + Deseleccionar todo + Nueva versión disponible + No hay información disponible. + No hay una nueva versión disponible. + Cerrar + Este algoritmo de verificación no está disponible en tu teléfono + Deshabilitar + Descartar + Terminado + No fue posible descargar %1$s + La descarga falló, inicia sesión de nuevo + Falla en la descarga + El archivo ya no se encuentra disponible en el servidor + %1$d%% Descargando %2$s + Descargando… + %1$s descargado + Descargado + Aún no ha descargado + Imagen de fondo para el encabezado de la barra de navegación + Actividades + Todos los archivos + Favoritos + Inicio + Notificaciones + Disponibles sin conexión + Modificado recientemente + Compartido + Papelera + Cargas + Cerrar sesión + %1$s de %2$s usados + Carga automática + Hablar + Establecer como encriptado + Configurar la encripción + Desencriptando… + Cerrar + Por favor ingresa la contraseña para desencriptar la llave privada. + Esta carpeta no está vacía. + Generando nuevas llaves… + Las 12 palabras juntas hacer una contraseña muy fuerte, permitiéndote solo a ti ver y hacer uso de tus archivos encriptados. Por favor escríbelo y mantenlo en un lugar seguro. + La encripción de punta-a-punta está dehabilitada en el servidor. + Anota tu contraseña de encripción de 12 palabras + Contraseña… + Recuperando llaves… + Almacenando llaves + Configurar encripción + No se pudieron guardar las llaves, por favor vuelve a intentarlo. + Se presentó un error al desencriptar. ¿Contraseña equivocada? + %1$s no pudo ser copiado a la carpeta local %2$s + Error crítico: No se pueden realizar operaciones + Cuentas + Creado + Usuario + Trabajos en segundo plano + Descargar + Cargar + Agregar a tus favoritos + Hacer favorito + Borrar + Archivo + Carga algún contenido o sincroniza con tus dispositivos. + Aún no hay nada marcado como favorito + No hay archivos aquí + No hay resultados en esta carpeta + No hay resultados + No hay nada aquí. Puedes agregar una carpeta. + No se encontraron archivos modificados dentro de los últimos 7 días + ¿Tal vez está dentro de una carpeta diferente? + Aún no hay nada compartido + carpeta + Cargando… + No se cuenta con una aplicación que maneje este tipo de archivo. + hace algunos segundos + Verificando el destino… + Limpiando… + La carpeta de datos ya existe. Selecciona una de las siguientes: + La carpeta Nextcloud ya existe + Se necesita más espacio + No fue posible leer el archivo fuente + No fue posible escribir al archivo destino + Se presentó una falla durante la migración + Se presentó una falla al actualizar el índice + Moviendo los datos… + Terminado + Reemplazar + Preparando la migración… + Restaurando la configuración de la cuenta… + Guardando la configuración de la cuenta… + ¡No se puede leer la carpeta fuente! + Actualizando índice… + Usar + Aguardando sincronización completa… + Archivo no encontrado + El archivo no pudo ser sincronizado. Mostrando la última versión disponible. + Renombrar + Detalles + Descargar + Exportar + El archivo se renombró com %1$s durante la carga + Sincronizar + No se ha seleccionado algún archivo + El nombre del archivo no puede estar en blanco. + Caracteres inválidos: / \\ < > : \" | ? * + El nombre del archivo contiene al menos un carácter inválido + Nombre del archivo + Crear + No hay carpetas aquí + Seleccionar + Mover + No se te permite %s + para copiar este archivo + para crear este archivo + para borrar este archivo + para mover este archivo + para renombrar este archivo + Cargando archivos… + Algunos archivos no se pudieron mover + Local: %1$s + Mover todos + Remoto: %1$s + Se han movido todos los archivos + Adelante + Nombre + Contraseña + Cargar archivos sólo con el dispositivo conectado a la toma de corriente + /Cargas Automáticas + Invisible + Liga + Permitir carga y edición + Permitir carga + Vista de lista + No hay archivos en esta carpeta + No se encontró el archivo en el sistema de archivos local + No hay más carpetas. +  %1$s bitácora de aplicación Android + Iniciar sesión + Actualizar + Cargando... + Bitácoras + Borrar datos + Las configuraciones, base de datos y certificados del servidor de los datos de %1$s serán borrados permanentemente.\n\nLos archivos descargados se mantendrán sin cambios.\n\nEste proceso puede tomar algo de tiempo. + Administrar espacio + No fue posible leer el archivo de medios + El archivo de medios tiene una codificación incorrecta + El intento de reproducir el archivo sobrepasó el tiempo de espera + El reproductor de medios integrado es incapaz de reproducir el archivo de medios + Codec no soportado + Botón de avanzar rápido + Reproductor de música %1$s + Botón de reproducir o pausar + Botón de rebobinar + %1$s (reproduciendo) + Más reciente primero + Más antiguo primero + A - Z + Z - A + Más grande primero + Más pequeño primero + Más + Se presentó un error al intentar mover este archivo o carpeta + No es posible mover una carpeta dentro de una de sus sub carpetas + El archivo ya existe en la carpeta de destino + Se presentó un error durante la conexión al servidor + foto + Muestra el progreso de la descarga + Descargas + Muestra el progreso de la sincronización de archivos y los resultados + Sincronizar archivo + Progreso del reproductor de música + Reproductor de medios + Mostrar las notificaciones push enviadas por el servidor: Menciones en comentarios, recepción de nuevos elementos compartidos remotos, anuncios publicados por el administrador, etc. + Notificaciones push + Muestra el progreso de la carga + Cargas + No hay notificaciones + Por favor verifica más tarde. + 1 hora + Ingresa tu código de seguridad + El código de seguridad será solicitado cada vez que inicie la aplicación + Por favor ingresa tu código de seguridad + Los códigos de seguridad no son iguales + Por favor reingresa el código de seguridad + Elimina tu código de seguirdad + Código de seguirdad eliminado + Código de seguridad almacenado + Código de seguridad incorrecto + Se requieren permisos adicionales para cargar y descargar archivos. + No se encontró una aplicación con la cual establecer la imagen + 389 KB + marcadordeposición.txt + 12:23:45 + Este es un marcador de posición + 2012/05/18 12:23 PM + Borrado + mantenido en la carpeta original + movido a la carpeta de la aplicación + Agregar cuenta + No ha sido instalado ni F-Droid o Google Play + Acerca de + Detalles + Desarrollo + General + Más + Sincronizar + Respaldo diario de tus contactos + GNU Licencia Pública General, versión 2 + Ayuda + Exención de responsabilidad + El archivo original será… + El archivo original será… + Usar sub carpetas + Licencia + Ninguno + Administrar cuentas + Mostrar archivos ocultos + Obtener el código fuente + Carpeta local + Carpeta remota + Tema + Oscuro + Claro + Vista previa de imagen + No existe un archivo local a previsualizar + No es posible mostrar la imagen + Disculpa + Privacidad + Las notificaciones push están deshabilitadas debido a dependencias de servicios propietarios de Google Play. + No hay notificaciones push debido a un inicio de sesión caduco. Por favor vuelve a ingresar a tu cuenta. + En este momento las notificaciones push no están disponibles. + ¡Prueba %1$s en tu dispositivo! + Quiero invitarte a usar %1$s en tu dispositivo\nDescárgalo aquí:%2$s + %1$s ó %2$s + Volver a cargar + Falla al eliminar + Eliminar + Eliminado + Ingresa un nombre nuevo + No se pudo renombrar la copia local, intenta con un nombre diferente + No fue posible renombrar, el nombre ya está ocupado + No se permite volver a compartir + No está permitido recompartir + No hay una imagen a escala disponible. ¿Descargar la imagen completa? + Reintentar + Seleccionar todo + Enviar + Ícono de botón de envío + Establecer Como + Usar imagen como + Compartir + Compartiendo + Compartir %1$s + %1$s (grupo) + Compartir liga + Debes ingresar una contraseña + para compartir este archivo + Ingresa una contraseña + Establecer fecha de expiración + Establecer contraseña + Puede editar + %1$s (remoto) + Configuraciones + Compartir liga + Compartir con… + compartido + Ordenar por + Ocultar + Detalles + La identidad del servidor no pudo ser verificada + País: + Nombre común: + Ubicación: + Organización: + Unidad organizacional: + Estado: + Huella digital: + Emitido por: + Firma: + Algoritmo: + Emitido para: + Validez: + De: + Para: + - No hay información acerca del error + No fue posible guardar el certificado + El certificado no puede ser mostrado. + ¿Quieres confiar en este certificado de todas formas? + - El certificado del servidor expiró + - El certificado del servidor no es de confianza + - Las fechas del certificado del servidor están en el futuro + - La URL no corresponde con el nombre del servidor en el certificado + Mensaje de estado + Predeterminado + Descargas + \"%1$s\" ha sido compartido contigo + %1$s ha compartido \"%2$s\" contigo + Sincronizar + Se encontraron conflictos + La carpeta %1$s ya no existe + No fue posible sincronizar %1$s + Contraseña equivocada para %1$s + Falla en archivos mantenidos-en-sincronización. + Falla en la sincronización + La sincronización falló, inicia sesión de nuevo + Los contenidos del archivo ya han sido sincronizados + A partir de la versión 1.3.16, los archivos cargados desde este dispositivo serán copiados a la carpeta local %1$s para prevenir pérdidas de datos cuando un archivo se sincroniza entre múltiples cuentas. \n\nDerivado de este cambio, todos los archivos cargados con versiones anteriores de la aplicación fueron copiados a la carpeta %2$s. Sin embargo, un error evitó que se completara esta operación durante la sincronización de la cuenta. Puedes dejar el(los) archivo(s) como está(n) y eliminar la liga a %3$s, o bien, mover el(los) archivo(s) a la carpeta %1$s y mantener la liga a %4$s.\n\nSe enlistan a continuación los archivos locales así como los archivos remotos en %5$s a donde estaban ligados + Algunos archivos locales se han perdido + Obteniendo la versión más reciente del archivo. + Botón de status de sincronización + Archivos + Botón de configuración + Configurar carpetas + Las cargas instantáneas se han mejorado por completo. Re-configura tu carga automática desde el menú principal.\n\nDisfruta la nueva y mejorada carga automática. + Para %1$s + Tipo + Etiquetas + Probar la conexión del servidor + 30 minutos + Esta semana + Miniatura + Hoy + Papelera + No hay archivos borrados + Borrar permanentemente + Desestablecer encripción + para dejar de compartir este archivo + Accede a través de un dominio no de confianza. Por favor consulta la documentación para más información. + para actualizar este recurso compartido + Borrar cargas fallidas + Reintentar cargas fallidas + Cargar forma… + Cargar contenido de otras aplicaciones + Foto + Nombre de archivo + Tipo de archivo + Archivo de acceso directo a Google Maps(%s) + Archivo de acceso directo a Internet(%s) + Archivo snippet de texto(.txt) + Ingresa el nombre y el tipo del archivo a cargar + Cargar archivos + Botón de cargar elemento + Borrar + No hay cargas disponibles + Carga algún contenido o activa la carga automática + El espacio insuficiente evita que se copien los archivos seleccionados dentro de la carpeta %1$s. ¿Te gustaría moverlos ahí en su lugar? + Error desconocido + Seleccionar + Cargar + La información recibida no contiene un archivo válido. + %1$s no tiene permitido leer un archivo recibido + No fue posible copiar el archivo a una carpeta temporal. Por favor intenta enviarlo de nuevo. + El archivo seleccionado para cargar no fue encontrado. Por favor verifica si el archivo existe. + No hay un archivo a cargar + Nombre de la carpeta + Selecciona la carpeta de cargas + No fue posible cargar %1$s + La carga falló, inicia sesión de nuevo + Falla en la carga + Opción de carga: + Mover el archivo a la carpeta %1$s + Mantener el archivo en la carpeta de origen + Borrar el archivo de la carpeta de origen + para cargar a esta carpeta + %1$d%% Cargando %2$s + Cargando + %1$s cargado + Salir + Ajustes + No existen cuentas %1$s en tu dispositivo. Por favor configura una cuenta primero. + No se encontró la cuenta + Actual + Fallido/pendiente de reinicio + Cargado + Cancelado + Esperando para cargar + Cargas + Cancelado + Conflicto + Error de conexión + Error de credenciales + Error de archivo + Error de carpeta + No se encontró el archivo local + Error de permisos + El certificado del servidor no es de confianza + La aplicación ha sido terminada + Completado + Error desconocido + Virus detectado. ¡La carga no puede ser completada! + Esperando a salir de modo de conservación de energía + Aguardando la recarga del dispositivo + Usuario + Dirección + Correo electrónico + Número telefónico + Twitter + Sitio web + Error al extraer la información del usuario + No se ha establecido la información personal + Agrega tu nombre, una imagen y detalles de contacto en tu página de perfil. + Usuario + Descargar + Aguarda un momento… + Verificando credenciales almacenadas + Copiando el archivo desde almacenamiento privado + Actualizar + Imagen de qué es nuevo + Omitir + Nuevo en %1$s + Descargando archivos… + Enviar correo electrónico + diff --git a/app/src/main/res/values-es/string.xml b/app/src/main/res/values-es/string.xml new file mode 100644 index 000000000000..d459b9a3cbb6 --- /dev/null +++ b/app/src/main/res/values-es/string.xml @@ -0,0 +1,31 @@ + + + + + + + Permisos de almacenamiento + Permisos de almacenamiento + %1$s necesita permiso para acceder a tus archivos para funcionar mejor. Puedes permitir o denegar el acceso. + %1$s necesita permiso para acceder a tus archivos para funcionar mejor. Puedes permitir o denegar el acceso. + + + Nombre o dirección de correo electrónico… + + + Configuración de la protección de datos + Esta aplicación utiliza cookies y tecnologías similares. Al hacer clic en Aceptar, consientes el procesamiento y la transferencia de tus datos a terceros. Encontrarás más información, incluida la relativa al procesamiento de datos por parte de terceros, en los ajustes y en nuestra política de privacidad Puedes rechazar la utilización de estas herramientas reject o modificar tu selección en cualquier momento a través de tus ajustes. + Ajustes + Aceptar + Para optimizar nuestra aplicación, recogemos datos anónimos. Para ello utilizamos soluciones de software de diferentes socios. Nos gustaría ofrecerte una transparencia y una ayuda en la toma de decisiones total sobre el procesamiento y la recopilación de tus datos de uso anonimizados. Posteriormente, puedes cambiar tu configuración en cualquier momento en el punto de menú Protección de datos. Sin embargo, ten en cuenta que la recopilación de datos contribuye de manera significativa a la optimización de esta aplicación y que si detienes el envío de datos impedirás estas optimizaciones. + La recopilación de estos datos es necesaria para poder utilizar las funciones esenciales de la aplicación. + Recopilación necesaria de datos + Estos datos nos ayudan a optimizar el uso de la aplicación y a identificar los fallos del sistema y los errores más rápidamente. + Análisis de la recopilación de datos para un diseño personalizado basado en las necesidades de cada usuario + Guardar ajustes + \ No newline at end of file diff --git a/app/src/main/res/values-fr/string.xml b/app/src/main/res/values-fr/string.xml new file mode 100644 index 000000000000..5c175e5172c8 --- /dev/null +++ b/app/src/main/res/values-fr/string.xml @@ -0,0 +1,32 @@ + + + + + + + Autorisations de stockage + Autorisations de stockage + %1$s a besoin d\'une autorisation pour accéder à vos fichiers. Vous pouvez autoriser ou refuser l\'accès. + %1$s a besoin d\'une autorisation pour accéder à vos fichiers. Vous pouvez autoriser ou refuser l\'accès. + + + Nom ou adresse e-mail… + + + Paramètres de confidentialité + Cette application utilise des cookies et des technologies similaires. En cliquant sur Accepter, vous acceptez le traitement et le transfert de vos données à des tiers. Vous trouverez plus d’informations, notamment sur le traitement des données par des tiers, dans les paramètres et dans notre Politique de confidentialité Vous pouvez refuser d\'utiliser les outils Refuser ou modifier votre sélection à tout moment via vos paramètres. + Paramétrages + Accepter + Pour optimiser notre application, nous recueillons des données anonymes. Pour ce faire, nous utilisons les solutions logicielles de différents partenaires. Nous souhaitons vous offrir une transparence et un pouvoir de décision entiers sur le traitement et la collecte de vos données d\'utilisation anonymes. Vous pouvez également modifier vos paramètres à tout moment par la suite dans le menu Protection des données. Veuillez toutefois noter que la collecte de données contribue de manière significative à l\'optimisation de cette application et que vous empêchez ces optimisations en arrêtant le transfert de données. + La collecte de ces données est nécessaire afin d\'utiliser les fonctions essentielles de l\'application. + Collecte de données nécessaire + Ces données nous aident à optimiser l\'utilisation de l\'application et à identifier plus rapidement les pannes du système et les erreurs. + Analyse de la collecte de données pour une conception basée sur les besoins + Sauvegarder les paramètres + + \ No newline at end of file diff --git a/app/src/main/res/values-land/integers.xml b/app/src/main/res/values-land/integers.xml new file mode 100644 index 000000000000..69325648f8cb --- /dev/null +++ b/app/src/main/res/values-land/integers.xml @@ -0,0 +1,11 @@ + + + + + 4 + diff --git a/app/src/main/res/values-large-land/integers.xml b/app/src/main/res/values-large-land/integers.xml new file mode 100644 index 000000000000..69325648f8cb --- /dev/null +++ b/app/src/main/res/values-large-land/integers.xml @@ -0,0 +1,11 @@ + + + + + 4 + diff --git a/app/src/main/res/values-large/dimen.xml b/app/src/main/res/values-large/dimen.xml new file mode 100644 index 000000000000..364b222d48a8 --- /dev/null +++ b/app/src/main/res/values-large/dimen.xml @@ -0,0 +1,29 @@ + + + + + + + 36dp + + + 48dp + 128dp + 35sp + 49sp + 32dp + 18sp + 24sp + 24dp + 24dp + 480dp + 16dp + 288dp + 12dp + + \ No newline at end of file diff --git a/app/src/main/res/values-large/integers.xml b/app/src/main/res/values-large/integers.xml new file mode 100644 index 000000000000..48b14899437c --- /dev/null +++ b/app/src/main/res/values-large/integers.xml @@ -0,0 +1,11 @@ + + + + + 3 + diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 8972d2bb6716..facb7222290d 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -37,5 +37,17 @@ #1E1E1E @android:color/white + @color/bg_default + + @color/white + @color/primary + @color/primary_dark + @color/disabled_text + + @color/primary + @color/white + + @color/primary + #101418 diff --git a/app/src/main/res/values-night/ionos_colors.xml b/app/src/main/res/values-night/ionos_colors.xml new file mode 100644 index 000000000000..15b2a2032a68 --- /dev/null +++ b/app/src/main/res/values-night/ionos_colors.xml @@ -0,0 +1,10 @@ + + + + @color/curious_blue + diff --git a/app/src/main/res/values-night/scanbot_theme.xml b/app/src/main/res/values-night/scanbot_theme.xml new file mode 100644 index 000000000000..709c3f4e2d95 --- /dev/null +++ b/app/src/main/res/values-night/scanbot_theme.xml @@ -0,0 +1,47 @@ + + + + + + diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 19b3ce692520..9f9379e7952c 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -5,11 +5,12 @@ ~ SPDX-FileCopyrightText: 2024 Alper Ozturk ~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only --> - + diff --git a/app/src/main/res/values-nl/string.xml b/app/src/main/res/values-nl/string.xml new file mode 100644 index 000000000000..f65880dd2c22 --- /dev/null +++ b/app/src/main/res/values-nl/string.xml @@ -0,0 +1,32 @@ + + + + + + + Opslag-toestemmingen + Opslag-toestemmingen + %1$s vereist toestemming voor toegang tot je bestanden voor een betere functionaliteit. Je kunt de toegang toestaan of weigeren. + %1$s vereist toestemming voor toegang tot je bestanden voor een betere functionaliteit. Je kunt de toegang toestaan of weigeren. + + + Naam of e-mailadres… + + + Privacyinstellingen + Deze toepassing gebruikt cookies en vergelijkbare technologie. Door akkoord te gaan, accepteer je de verwerking en de overdracht van je gegevens aan derden. privacybeleid . Je kunt het gebruik van de tools op elk moment weigeren of je keuze aanpassen via je instellingen. + Instellingen + Akkoord + Om onze app te optimaliseren, verzamelen we anonieme gegevens. Hiervoor gebruiken we softwareoplossingen van verschillende partners. Wij willen je volledige transparantie en beslissingsbevoegdheid geven over de verwerking en verzameling van je geanonimiseerde gebruiksgegevens. Je kunt je instellingen altijd wijzigen via het menu \'Privacy\'. Houd er rekening mee dat het verzamelen van gegevens een aanzienlijke bijdrage levert aan de optimalisatie van deze app. Als je de dataverzameling uitschakelt, zijn deze optimalisaties beperkt of niet meer mogelijk. + Het verzamelen van deze gegevens is noodzakelijk om essentiële functies van de app te kunnen gebruiken. + Noodzakelijke dataverzameling + Deze gegevens helpen ons om het gebruik van de app voor je te optimaliseren en om systeemcrashes en fouten sneller te identificeren. + Dataverzameling voor gebruikersgebaseerde app-optimalisatie + Instellingen opslaan + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 108443d3e383..d1f5cf26ba87 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -7,6 +7,9 @@ ~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only --> + + + @string/pref_behaviour_entries_keep_file @string/pref_behaviour_entries_move diff --git a/app/src/main/res/values/colors-palette.xml b/app/src/main/res/values/colors-palette.xml new file mode 100644 index 000000000000..d57ecff6ae4b --- /dev/null +++ b/app/src/main/res/values/colors-palette.xml @@ -0,0 +1,36 @@ + + + + + #0B2A63 + #003d8f + #02102B + #001B41 + #095BB1 + #465A75 + #DBEDF8 + #718095 + #1D2D42 + #F4F7FA + #33F4F7FA + #1474C4 + #C36B00 + #FFAA00 + #2E4360 + #97A3B4 + #DBE2E8 + #F2F5F8 + #95CAEB + #BCC8D4 + #0C8A44 + #BDCDD7 + #3196D6 + #586680 + #FF6159 + #80000000 + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e0da603d4f8a..907aab14cfe5 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -9,7 +9,7 @@ ~ SPDX-FileCopyrightText: 2012 Bartosz Przybylski ~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) --> - + @color/secondary_text_color #000000 #ffffff @@ -28,6 +28,8 @@ #00000000 #666666 #e53935 + #3672be + #d62e2b #757575 @@ -77,5 +79,38 @@ #666666 #A5A5A5 + @color/bg_default + + @color/white + @color/primary + @color/primary_dark + @color/disabled_text + + @color/primary + @color/black + + @color/bg_default + ?android:textColorPrimary + + @color/primary + @color/background_color_inverse + @color/color_transparent + @color/black + @color/black + @color/grey_900 + @color/primary_button_text_color + + @color/text_color + @color/primary + @color/primary + @color/disabled_text + @color/primary + @color/primary + + @color/primary + @color/primary + + @color/bg_default + #F7F9FF diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml new file mode 100644 index 000000000000..fdc32026e8a1 --- /dev/null +++ b/app/src/main/res/values/dimen.xml @@ -0,0 +1,29 @@ + + + + + + + 8dp + + + 16dp + 64dp + 18sp + 24sp + 32dp + 14sp + 19sp + 12dp + 24dp + 288dp + 16dp + 288dp + 12dp + + \ No newline at end of file diff --git a/app/src/main/res/values/dims.xml b/app/src/main/res/values/dims.xml index 2e8c6d58fe7b..534894b5bc04 100644 --- a/app/src/main/res/values/dims.xml +++ b/app/src/main/res/values/dims.xml @@ -9,7 +9,7 @@ ~ SPDX-FileCopyrightText: 2014 ownCloud Inc. ~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) --> - + 164dp 12sp @@ -18,7 +18,7 @@ 40dp 56dp 80dp - 40dp + 44dp 100dp 128dp 8dp @@ -45,7 +45,7 @@ 140dp 180dp 2dp - 56dp + 64dp 72dp 56dp 16sp @@ -158,6 +158,12 @@ 108dp 18dp 18dp + + 1dp + 8dp + 14sp + 16dp + 120dp 150dp diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml new file mode 100644 index 000000000000..4529d1a3c362 --- /dev/null +++ b/app/src/main/res/values/integers.xml @@ -0,0 +1,11 @@ + + + + + 2 + diff --git a/app/src/main/res/values/ionos_colors.xml b/app/src/main/res/values/ionos_colors.xml new file mode 100644 index 000000000000..97cb7d2c4aae --- /dev/null +++ b/app/src/main/res/values/ionos_colors.xml @@ -0,0 +1,10 @@ + + + + @color/dodger_blue + diff --git a/app/src/main/res/values/ionos_styles.xml b/app/src/main/res/values/ionos_styles.xml new file mode 100644 index 000000000000..ad614ec7593a --- /dev/null +++ b/app/src/main/res/values/ionos_styles.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/src/main/res/values/scanbot_theme.xml b/app/src/main/res/values/scanbot_theme.xml new file mode 100644 index 000000000000..3865b99fbe96 --- /dev/null +++ b/app/src/main/res/values/scanbot_theme.xml @@ -0,0 +1,47 @@ + + + + + + diff --git a/app/src/main/res/values/string.xml b/app/src/main/res/values/string.xml new file mode 100644 index 000000000000..496284a3c283 --- /dev/null +++ b/app/src/main/res/values/string.xml @@ -0,0 +1,32 @@ + + + + + + + Storage permissions + Storage permissions + %1$s needs permission to access your files for better functionality. You can allow or deny access. + %1$s needs permission to access your files for better functionality. You can allow or deny access. + + + Name or email address… + + + Privacy Settings + This application uses cookies and similar technologies. By clicking on Agree, you consent to the processing of your data and also to its transfer to third parties. Visit our Privacy Policy for more information, also on data processing by third party providers. Click on Reject to prevent use of the tool, or change your selection at any time in Settings. + Settings + Agree + We collect anonymized data to optimize our app. We use software solutions by various partners for this purpose. Our intention is to offer full transparency and allow you to decide how your anonymized data is collected and used. You can also change your settings at any time later on under the Privacy menu item. Please note, however, that data collection contributes significantly to optimizing this app and that you would prevent these improvements by rejecting the transfer of data. + Data collection is necessary in order to use key functions of the app. + Necessary data collection + This data helps us to optimize your user experience and to identify system crashes and bugs. + Data analysis for needs-based design + Save Settings + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 08ebf4b5f8c7..63bf50a67ffe 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,7 +11,7 @@ ~ SPDX-FileCopyrightText: 2012 Bartosz Przybylski ~ SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) --> - + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index cefa8e7856d8..c8cd63aeb43e 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -6,11 +6,12 @@ ~ SPDX-FileCopyrightText: 2022 Nextcloud GmbH ~ SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only --> - + + + + diff --git a/scanbot/src/main/res/values-nl/strings.xml b/scanbot/src/main/res/values-nl/strings.xml new file mode 100644 index 000000000000..f800e1159e12 --- /dev/null +++ b/scanbot/src/main/res/values-nl/strings.xml @@ -0,0 +1,58 @@ + + + + + Annuleren + Er is een fout opgetreden. Probeer het later nog eens. + Houd ingedrukt en versleep om pagina\'s opnieuw te sorteren + Toegang tot de camera is vereist om de code te scannen + Onvoldoende ruimte + "Op de smartphone is onvoldoende opslagruimte beschikbaar." + OK + Opslaan + Opslaan als + Er is een fout opgetreden. Probeer het later nog eens + Automatisch + Geen document + Slecht licht + Te veel ruis op achtergrond + Niet bewegen + Perspectief + Dichterbij brengen + Flits + Importeren + Fout tijdens maken van document + Document detecteren + scan_%1$tY%1$tm%1$td-%1$tH%1$tM%1$tS + Voortgang gaat verloren + Document scannen + Kan bestand %s niet importeren + Filter wordt toegepast op alle afbeeldingen + Zwart/wit + Kleur + Grijsschaal + Magische kleur + Magische tekst + Geen filter + Voor alle toepassen + %d van %d + Onvoldoende ruimte op apparaat om foto te nemen. Maak ruimte vrij. + Document wordt verwerkt… + Verwerken… + Pagina\'s opnieuw sorteren + Randen resetten + Bestandsnaam: + Bestandstype: + Ongeldige bestandsnaam + Opslaglocatie: + Bijsnijden + Filteren + Draaien + Herschikken + Verwijderen + diff --git a/scanbot/src/main/res/values/attrs.xml b/scanbot/src/main/res/values/attrs.xml new file mode 100644 index 000000000000..078446388b23 --- /dev/null +++ b/scanbot/src/main/res/values/attrs.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scanbot/src/main/res/values/colors-palette.xml b/scanbot/src/main/res/values/colors-palette.xml new file mode 100644 index 000000000000..43b859132093 --- /dev/null +++ b/scanbot/src/main/res/values/colors-palette.xml @@ -0,0 +1,26 @@ + + + + + #FFFFFF + #000000 + #333333 + #999999 + #dcdcdc + #EBEEEF + #222222 + #00FFFFFF + #0D000000 + #55FF8800 + #ccFF8800 + #a0c8e8 + #D9555555 + #8C0077BB + #0077BB + #003d8f + \ No newline at end of file diff --git a/scanbot/src/main/res/values/dimens.xml b/scanbot/src/main/res/values/dimens.xml new file mode 100644 index 000000000000..447b7f44876c --- /dev/null +++ b/scanbot/src/main/res/values/dimens.xml @@ -0,0 +1,58 @@ + + + + + 4dp + 8dp + 12dp + 16dp + 24dp + + 18sp + + 1dp + + 56dp + 48dp + + 2dp + 48dp + + 48dp + 10dp + 16dp + 36dp + + 64dp + + 20dp + 20dp + 30dp + + 4dp + 4dp + 24dp + 8dp + 11sp + 5dp + 16dp + 40dp + + 50dp + 250dp + 15dp + 20sp + 20dp + 10dp + 75dp + 18sp + + 480dp + + 20sp + \ No newline at end of file diff --git a/scanbot/src/main/res/values/preference_keys.xml b/scanbot/src/main/res/values/preference_keys.xml new file mode 100644 index 000000000000..def3f6a319f8 --- /dev/null +++ b/scanbot/src/main/res/values/preference_keys.xml @@ -0,0 +1,14 @@ + + + + + preference_scanbot_license_key + + preference_aes_gsm_key + preference_aes_gsm_initialization_vector + \ No newline at end of file diff --git a/scanbot/src/main/res/values/strings.xml b/scanbot/src/main/res/values/strings.xml new file mode 100644 index 000000000000..eabef060ff2c --- /dev/null +++ b/scanbot/src/main/res/values/strings.xml @@ -0,0 +1,60 @@ + + + + + Cancel + An error occurred. Please try again later. + Hold and drag to rearrange pages + Need use camera permissions to be granted to scan code + No enough space + "The smartphone does not have enough storage space available. " + OK + Save + Save as + An error occurred. Please try again later + + Automatic + No Document + Poor light + Background too noisy + Don\'t move + Perspective + Move closer + Flash + Import + Error while creating document + Detect document + scan_%1$tY%1$tm%1$td-%1$tH%1$tM%1$tS + Progress will be lost + Scan document + Can\'t import file %s + Applying filter for all images + Black & White + Color + Grayscale + Magic Color + Magic Text + No filter + Apply for all + %d of %d + Not enough space on device for taking photo. Please, clear storage. + Processing document… + Processing… + Rearrange pages + Reset borders + File name: + File type: + Invalid file name + Save location: + + Crop + Filter + Rotate + Rearrange + Delete + diff --git a/scanbot/src/main/res/values/styles.xml b/scanbot/src/main/res/values/styles.xml new file mode 100644 index 000000000000..a0f2eb4ff932 --- /dev/null +++ b/scanbot/src/main/res/values/styles.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + diff --git a/scanbot/src/main/res/values/theme.xml b/scanbot/src/main/res/values/theme.xml new file mode 100644 index 000000000000..fee2f03abf28 --- /dev/null +++ b/scanbot/src/main/res/values/theme.xml @@ -0,0 +1,71 @@ + + + + + diff --git a/scanbot/src/main/res/values/untranslatable_strings.xml b/scanbot/src/main/res/values/untranslatable_strings.xml new file mode 100644 index 000000000000..7d520ab5d97c --- /dev/null +++ b/scanbot/src/main/res/values/untranslatable_strings.xml @@ -0,0 +1,14 @@ + + + + + JPG + PDF + PDF (OCR) + PNG + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 352229bd93d9..4ab9dfae2ca9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,6 +8,8 @@ rootProject.name = 'Nextcloud' include ':app' include ':appscan' +include ':scanbot' + //includeBuild('../android-common') { // dependencySubstitution { diff --git a/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt b/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt new file mode 100644 index 000000000000..897d3a8d6721 --- /dev/null +++ b/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt @@ -0,0 +1,7 @@ +## 3.30.0 RC2 (September 10, 2024) + +- Bugfixes + +Minimum: NC 16 Server, Android 7.0 Nougat + +For a full list, please see https://github.com/nextcloud/android/milestone/94 \ No newline at end of file diff --git a/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt.license b/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt.license new file mode 100644 index 000000000000..dd29b5040ecd --- /dev/null +++ b/src/versionDev/fastlane/metadata/android/en-US/changelogs/30300052.txt.license @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later \ No newline at end of file