diff --git a/.cron.yml b/.cron.yml index 28a2c70bf..df4d6f8a5 100644 --- a/.cron.yml +++ b/.cron.yml @@ -36,4 +36,4 @@ jobs: type: decision-task treeherder-symbol: legacy-api-ui target-tasks-method: legacy_api_ui_tests - when: [{hour: 10, minute: 30}] + when: [] # temporarily unscheduled diff --git a/.editorconfig b/.editorconfig index 005d63ee9..7ea380af1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,4 @@ [*.{kt,kts}] -# Disabling rules that were added in the latest versions of ktlint -# tracking here: https://github.com/mozilla-mobile/fenix/issues/4861 - -ktlint_disabled_rules=import-ordering - ij_kotlin_allow_trailing_comma_on_call_site=true ij_kotlin_allow_trailing_comma=true diff --git a/.experimenter.yaml b/.experimenter.yaml index 46d1a1e16..d1790ace8 100644 --- a/.experimenter.yaml +++ b/.experimenter.yaml @@ -1,4 +1,12 @@ --- +growth-data: + description: A feature measuring campaign growth data + hasExposure: true + exposureDescription: "" + variables: + enabled: + type: boolean + description: "If true, the feature is active" homescreen: description: The homescreen that the user goes to when they press home or new tab. hasExposure: true diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 5f306c48a..22eeead02 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,5 @@ # .git-blame-ignore-revs -# 26901: Fix issues from ktlint baseline +# For #27667 - Remove import-ordering from the list of disabled ktlint rules (#27680) +9654b4dfb122b54b04369fe80a2f9c95811478e8 +# For #26844: Fix ktlint issues and remove them from baseline. (#26901) ffcef5ff2e3f78b6972dd16551f3f653b7035ccc diff --git a/.mergify.yml b/.mergify.yml index 73ed4d7c5..2fdb45cce 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,7 +1,7 @@ queue_rules: - name: default conditions: - - status-success=pr-complete + - status-success=complete-pr pull_request_rules: - name: Resolve conflict conditions: @@ -110,7 +110,7 @@ pull_request_rules: - name: Needs landing - Squash conditions: - check-success=pr-complete - - label=pr:needs-landing-squashed + - label=pr:needs-landing-squashed - "#approved-reviews-by>=1" - -draft - label!=pr:work-in-progress diff --git a/.taskcluster.yml b/.taskcluster.yml index 2a62f95e1..e803a2845 100644 --- a/.taskcluster.yml +++ b/.taskcluster.yml @@ -14,7 +14,10 @@ tasks: then: '${tasks_for}@noreply.mozilla.org' else: $if: 'tasks_for == "github-push"' - then: '${event.pusher.email}' + then: + $if: 'event.pusher.email' + then: '${event.pusher.email}' + else: '${event.pusher.name}@users.noreply.github.com' else: $if: 'tasks_for == "github-pull-request"' then: '${event.pull_request.user.login}@users.noreply.github.com' diff --git a/app/build.gradle b/app/build.gradle index 6baa35576..f03f31095 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ import org.mozilla.fenix.gradle.tasks.ApkSizeTask plugins { id "com.jetbrains.python.envs" version "0.0.26" - id "com.google.protobuf" version "0.8.17" + id "com.google.protobuf" version "0.8.19" } apply plugin: 'com.android.application' @@ -183,7 +183,6 @@ android { buildConfigField "String", "AMO_COLLECTION_USER", "\"16201230\"" buildConfigField "String", "AMO_COLLECTION_NAME", "\"What-I-want-on-Fenix\"" } - } buildFeatures { @@ -272,7 +271,7 @@ android.applicationVariants.all { variant -> // Generate version codes for builds // ------------------------------------------------------------------------------------------------- - def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false + def isDebug = variant.buildType.resValues['bool/IS_DEBUG']?.value ?: false def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false println("----------------------------------------------") @@ -403,6 +402,21 @@ android.applicationVariants.all { variant -> println("--") } +// ------------------------------------------------------------------------------------------------- +// Glean: Read custom server URL from local.properties of a local file if it exists +// ------------------------------------------------------------------------------------------------- + + print("Glean custom server URL: ") + + if (gradle.hasProperty("localProperties.glean.custom.server.url")) { + def url=gradle.getProperty("localProperties.glean.custom.server.url") + buildConfigField 'String', 'GLEAN_CUSTOM_URL', url + println "(Added from local.properties file)" + } else { + buildConfigField 'String', 'GLEAN_CUSTOM_URL', 'null' + println("--") + } + // ------------------------------------------------------------------------------------------------- // BuildConfig: Set flag for official builds; similar to MOZILLA_OFFICIAL in mozilla-central. // ------------------------------------------------------------------------------------------------- @@ -487,7 +501,7 @@ configurations { tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions { - freeCompilerArgs += "-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" + freeCompilerArgs += "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi" } } @@ -598,6 +612,7 @@ dependencies { debugImplementation Deps.leakcanary forkDebugImplementation Deps.leakcanary + implementation Deps.androidx_annotation implementation Deps.androidx_compose_ui implementation Deps.androidx_compose_ui_tooling implementation Deps.androidx_compose_foundation @@ -623,6 +638,15 @@ dependencies { implementation Deps.protobuf_javalite implementation Deps.google_material + implementation Deps.adjust + implementation Deps.installreferrer // Required by Adjust + + implementation Deps.google_ads_id // Required for the Google Advertising ID + + // Required for in-app reviews + implementation Deps.google_play_review + implementation Deps.google_play_review_ktx + androidTestImplementation Deps.uiautomator androidTestImplementation "tools.fastlane:screengrab:2.0.0" // This Falcon version is added to maven central now required for Screengrab diff --git a/app/metrics.yaml b/app/metrics.yaml index 5a8f6d539..afc6256d4 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -158,11 +158,12 @@ events: - https://github.com/mozilla-mobile/fenix/pull/18143 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21316#issuecomment-944615938 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 108 + expires: 122 default_browser_changed: type: event description: | @@ -197,6 +198,35 @@ events: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + default_browser_notif_shown: + type: event + description: | + Default browser notification was shown to the user + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27779 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27780 + data_sensitivity: + - technical + notification_emails: + - android-probes@mozilla.com + expires: 122 + marketing_notification_allowed: + type: boolean + description: | + True if marketing notifications are allowed, otherwise false. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27795 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27797 + data_sensitivity: + - technical + notification_emails: + - android-probes@mozilla.com + expires: 122 + metadata: + tags: + - Notifications toolbar_menu_visible: type: event description: | @@ -314,11 +344,12 @@ events: - https://github.com/mozilla-mobile/fenix/pull/18143 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21316#issuecomment-944615938 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 108 + expires: 122 opened_link: type: event description: | @@ -422,11 +453,12 @@ events: - https://github.com/mozilla-mobile/fenix/pull/19936 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21316#issuecomment-944615938 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 108 + expires: 122 tab_view_changed: type: event description: | @@ -449,6 +481,39 @@ events: notification_emails: - android-probes@mozilla.com expires: 113 + save_to_pdf_tapped: + type: event + description: | + A user tapped the save to pdf option in the share sheet. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/3709 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27257 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 122 + metadata: + tags: + - Sharing + save_to_pdf_failure: + type: event + description: | + A user tapped the save pdf but an error ocurred + and the process failed. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27635 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27661#issuecomment-1300505370 + data_sensitivity: + - technical + notification_emails: + - android-probes@mozilla.com + expires: 122 + metadata: + tags: + - Sharing onboarding: syn_cfr_shown: @@ -1279,6 +1344,7 @@ metrics: `other` option for the source but it should never enter on this case. send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/1158 - https://github.com/mozilla-mobile/fenix/issues/6556 @@ -1297,6 +1363,8 @@ metrics: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING metadata: tags: - Search @@ -1700,6 +1768,24 @@ metrics: metadata: tags: - Wallpapers + notifications_allowed: + type: boolean + description: | + True if notifications are allowed, otherwise false. + send_in_pings: + - metrics + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27795 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27797 + data_sensitivity: + - technical + notification_emails: + - android-probes@mozilla.com + expires: 122 + metadata: + tags: + - Notifications customize_home: most_visited_sites: @@ -1867,11 +1953,12 @@ customize_home: - https://github.com/mozilla-mobile/fenix/issues/22145 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22333 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 preferences: studies_enabled: @@ -1885,11 +1972,12 @@ preferences: - https://github.com/mozilla-mobile/fenix/issues/22192 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22193 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 studies_preference_enabled: type: event description: > @@ -1898,11 +1986,12 @@ preferences: - https://github.com/mozilla-mobile/fenix/issues/22192 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22193 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_suggestions_enabled: type: boolean description: | @@ -2307,11 +2396,12 @@ preferences: - https://github.com/mozilla-mobile/fenix/issues/21903 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21908 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search.default_engine: code: @@ -2324,6 +2414,7 @@ search.default_engine: value will be "custom" send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/800 data_reviews: @@ -2340,6 +2431,8 @@ search.default_engine: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING name: type: string lifetime: application @@ -2350,6 +2443,7 @@ search.default_engine: value will be "custom" send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/800 data_reviews: @@ -2366,6 +2460,8 @@ search.default_engine: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING search_url: type: url lifetime: application @@ -2456,6 +2552,22 @@ bookmarks_management: metadata: tags: - Bookmarks + open_all_in_new_tabs: + type: event + description: | + A user opened all the bookmarks in a folder in new tabs. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/11404 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27138 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 120 + metadata: + tags: + - Bookmarks open_in_private_tab: type: event description: | @@ -2500,6 +2612,22 @@ bookmarks_management: metadata: tags: - Bookmarks + open_all_in_private_tabs: + type: event + description: | + A user opened all the bookmarks in a folder in new private tabs. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/11404 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27138 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 120 + metadata: + tags: + - Bookmarks edited: type: event description: | @@ -2676,6 +2804,39 @@ bookmarks_management: metadata: tags: - Bookmarks + search_icon_tapped: + type: event + description: | + A user tapped on the search icon in bookmarks management. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27147 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27268 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 120 + metadata: + tags: + - Bookmarks + search_result_tapped: + type: event + description: | + A user tapped on the search result in bookmarks management. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27147 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27268 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 120 + metadata: + tags: + - Bookmarks + activation: identifier: type: string @@ -2751,11 +2912,12 @@ error_page: - https://github.com/mozilla-mobile/fenix/pull/18143 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21316#issuecomment-944615938 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 108 + expires: 122 metadata: tags: - ErrorMessages @@ -3316,11 +3478,12 @@ history: - https://github.com/mozilla-mobile/fenix/issues/22172 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22173 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_term_group_tapped: type: event description: | @@ -3329,11 +3492,12 @@ history: - https://github.com/mozilla-mobile/fenix/issues/22299 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22300 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_term_group_open_tab: type: event description: | @@ -3342,11 +3506,12 @@ history: - https://github.com/mozilla-mobile/fenix/issues/22147 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22368#issuecomment-964223263 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_term_group_remove_tab: type: event description: | @@ -3355,11 +3520,12 @@ history: - https://github.com/mozilla-mobile/fenix/issues/22147 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22368#issuecomment-964223263 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_term_group_remove_all: type: event description: | @@ -3368,11 +3534,12 @@ history: - https://github.com/mozilla-mobile/fenix/issues/22147 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22368#issuecomment-964223263 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_icon_tapped: type: event description: | @@ -3409,11 +3576,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 closed: type: event description: | @@ -3422,11 +3590,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 show_full_history: type: event description: | @@ -3435,11 +3604,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 open_tab: type: event description: | @@ -3448,11 +3618,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 delete_tab: type: event description: | @@ -3461,11 +3632,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 menu_close: type: event description: | @@ -3474,11 +3646,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 menu_share: type: event description: | @@ -3487,11 +3660,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 menu_delete: type: event description: | @@ -3500,11 +3674,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 menu_open_in_normal_tab: type: event description: | @@ -3513,11 +3688,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 menu_open_in_private_tab: type: event description: | @@ -3526,11 +3702,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 enter_multiselect: type: event description: | @@ -3539,11 +3716,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 exit_multiselect: type: event description: | @@ -3553,11 +3731,12 @@ recently_closed_tabs: - https://github.com/mozilla-mobile/fenix/issues/21009 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22588#issuecomment-1024352995 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 reader_mode: available: @@ -3982,11 +4161,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/21903 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21908 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 close_all_inactive_tabs: type: event description: | @@ -3995,11 +4175,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/21903 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21908 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 auto_close_seen: type: event description: | @@ -4008,11 +4189,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22170 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22171 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 auto_close_turn_on_clicked: type: event description: | @@ -4021,11 +4203,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22170 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22171 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 auto_close_dimissed: type: event description: | @@ -4034,11 +4217,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22170 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22171 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 close_inactive_tab: type: counter description: | @@ -4047,11 +4231,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/21903 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21908 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 open_inactive_tab: type: counter description: | @@ -4060,11 +4245,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/21903 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21908 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 inactive_tabs_cfr_settings: type: event description: | @@ -4073,11 +4259,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22298 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22301 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 inactive_tabs_cfr_dismissed: type: event description: | @@ -4086,11 +4273,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22298 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22301 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 inactive_tabs_cfr_visible: type: event description: | @@ -4099,11 +4287,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/22298 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22301 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 enter_multiselect_mode: type: event description: | @@ -4112,11 +4301,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/23399 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/23964#issuecomment-1051128057 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 metadata: tags: - Tabs @@ -4132,11 +4322,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/23399 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/23964#issuecomment-1051128057 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 metadata: tags: - Tabs @@ -4152,11 +4343,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/23399 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/23964#issuecomment-1051128057 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 metadata: tags: - Tabs @@ -4172,11 +4364,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/23399 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/23964#issuecomment-1051128057 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 metadata: tags: - Tabs @@ -4192,11 +4385,12 @@ tabs_tray: - https://github.com/mozilla-mobile/fenix/issues/23399 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/23964#issuecomment-1051128057 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 metadata: tags: - Tabs @@ -5617,11 +5811,12 @@ app_theme: - https://github.com/mozilla-mobile/fenix/pull/18143 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21316#issuecomment-944615938 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 108 + expires: 122 metadata: tags: - Themes @@ -5742,6 +5937,28 @@ pocket: metadata: tags: - PocketIntegration + spoc_shim: + type: text + description: | + Shim data of the Pocket sponsored story the user just + interacted with. + The shim is a unique base64 string identifying each story and + type of user interaction: story impression or click. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27549 + - https://mozilla-hub.atlassian.net/browse/FNXV2-21791 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27550#issuecomment-1295027631 + data_sensitivity: + - web_activity + notification_emails: + - android-probes@mozilla.com + expires: never + send_in_pings: + - spoc + metadata: + tags: + - PocketIntegration home_recs_spoc_shown: type: event description: | @@ -5986,6 +6203,7 @@ browser.search: The key format is ``. send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/6558 data_reviews: @@ -6000,6 +6218,8 @@ browser.search: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING ad_clicks: type: labeled_counter description: | @@ -6007,6 +6227,7 @@ browser.search: The key format is ``. send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/6558 data_reviews: @@ -6021,12 +6242,15 @@ browser.search: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING in_content: type: labeled_counter description: | Records the type of interaction a user has on SERP pages. send_in_pings: - metrics + - baseline bugs: - https://github.com/mozilla-mobile/fenix/issues/6557 data_reviews: @@ -6041,6 +6265,8 @@ browser.search: - android-probes@mozilla.com - kbrosnan@mozilla.com expires: never + no_lint: + - BASELINE_PING addons: open_addons_in_settings: @@ -6395,12 +6621,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 bookmark_suggestions: send_in_pings: - metrics @@ -6414,12 +6641,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 search_engine_suggestions: send_in_pings: - metrics @@ -6433,12 +6661,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 session_suggestions: send_in_pings: - metrics @@ -6452,12 +6681,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 synced_tabs_suggestions: send_in_pings: - metrics @@ -6471,12 +6701,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 clipboard_suggestions: send_in_pings: - metrics @@ -6490,12 +6721,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 shortcuts_suggestions: send_in_pings: - metrics @@ -6509,12 +6741,13 @@ perf.awesomebar: - https://github.com/mozilla-mobile/fenix/pull/10276#pullrequestreview-411101979 - https://github.com/mozilla-mobile/fenix/pull/19924#issuecomment-861423789 - https://github.com/mozilla-mobile/fenix/pull/21315#issuecomment-920848442 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - technical - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 autoplay: visited_setting: @@ -7148,11 +7381,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - technical notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 enabled: type: boolean description: | @@ -7163,11 +7397,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 request_matching_logins: type: event description: | @@ -7178,11 +7413,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 request_no_matching_logins: type: event description: | @@ -7193,11 +7429,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 search_displayed: type: event description: | @@ -7208,11 +7445,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 search_item_selected: type: event description: | @@ -7222,11 +7460,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 unlock_cancelled: type: event description: | @@ -7237,11 +7476,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 unlock_successful: type: event description: | @@ -7251,11 +7491,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 confirm_cancelled: type: event description: | @@ -7266,11 +7507,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 confirm_successful: type: event description: | @@ -7280,11 +7522,12 @@ android_autofill: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/20547#issuecomment-889051503 - https://github.com/mozilla-mobile/fenix/pull/22871#issuecomment-995092496 + - https://github.com/mozilla-mobile/fenix/pull/27295 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 109 + expires: 122 home_menu: settings_item_clicked: @@ -7334,11 +7577,12 @@ home_screen: - https://github.com/mozilla-mobile/fenix/issues/22146 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22377 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 customize_home_clicked: type: event description: A user clicked on Customize home from the home screen menu. @@ -7347,7 +7591,6 @@ home_screen: data_reviews: - https://github.com/mozilla-mobile/fenix/pull/21344 - https://github.com/mozilla-mobile/fenix/pull/21344#issuecomment-923198787 - - https://github.com/mozilla-mobile/fenix/pull/26123#issuecomment-1190794469 data_sensitivity: - interaction notification_emails: @@ -7451,11 +7694,12 @@ recent_tabs: - https://github.com/mozilla-mobile/fenix/issues/22107 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22166 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 jump_back_in_cfr_shown: type: event description: | @@ -7505,11 +7749,12 @@ recent_bookmarks: - https://github.com/mozilla-mobile/fenix/issues/22103 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22104 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 bookmark_clicked: type: counter lifetime: application @@ -7557,11 +7802,12 @@ recent_bookmarks: - https://github.com/mozilla-mobile/fenix/issues/22075 data_reviews: - https://github.com/mozilla-mobile/fenix/pull/22293 + - https://github.com/mozilla-mobile/fenix/pull/27068#issuecomment-1251509973 data_sensitivity: - interaction notification_emails: - android-probes@mozilla.com - expires: 107 + expires: 120 unit: integer recent_searches: @@ -8226,46 +8472,6 @@ recently_visited_homepage: data_sensitivity: - interaction expires: 114 -downloads: - pdf_download_count: - type: counter - lifetime: application - description: | - A counter that indicates how many times a pdf has been downloaded. - send_in_pings: - - metrics - bugs: - - https://github.com/mozilla-mobile/fenix/issues/24075 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/24061 - data_sensitivity: - - interaction - notification_emails: - - android-probes@mozilla.com - expires: 107 - metadata: - tags: - - Download - downloaded_pdf_open_count: - type: counter - lifetime: application - description: | - A counter that indicates how many times open button has been clicked - for a downloaded pdf. - send_in_pings: - - metrics - bugs: - - https://github.com/mozilla-mobile/fenix/issues/24075 - data_reviews: - - https://github.com/mozilla-mobile/fenix/pull/- - data_sensitivity: - - interaction - notification_emails: - - android-probes@mozilla.com - expires: 107 - metadata: - tags: - - Download recent_synced_tabs: recent_synced_tab_shown: @@ -8337,3 +8543,31 @@ recent_synced_tabs: data_sensitivity: - interaction expires: 114 +review_prompt: + prompt_attempt: + type: event + description: | + Data captured for each attempt to display the review prompt. + extra_keys: + prompt_was_displayed: + description: | + Whether the prompt was displayed to the user. Value + reported will be: 'true', 'false' or 'error'. + type: string + local_datetime: + description: | + The local datetime. + type: string + number_of_app_launches: + description: | + The total number of times the app has been launched. + type: quantity + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27472 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27596 + notification_emails: + - android-probes@mozilla.com + data_sensitivity: + - interaction + expires: 121 diff --git a/app/pings.yaml b/app/pings.yaml index ef205112c..981168f5b 100644 --- a/app/pings.yaml +++ b/app/pings.yaml @@ -43,3 +43,22 @@ topsites-impression: - https://github.com/mozilla-mobile/fenix/pull/23945 notification_emails: - android-probes@mozilla.com + +spoc: + description: | + Contains data identifying with which Pocket sponsored story the user + interacted with and the type of interaction: story impression or click. + include_client_id: false + reasons: + impression: | + A sponsored story had more than 50% of it's content visible + on the screen. + click: | + A sponsored story was clicked by the user. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/27549 + - https://mozilla-hub.atlassian.net/browse/FNXV2-21791 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/27550#issuecomment-1295027631 + notification_emails: + - android-probes@mozilla.com diff --git a/app/src/androidTest/assets/pages/cross-site-cookies.html b/app/src/androidTest/assets/pages/cross-site-cookies.html new file mode 100644 index 000000000..1ff5ce938 --- /dev/null +++ b/app/src/androidTest/assets/pages/cross-site-cookies.html @@ -0,0 +1,8 @@ + + +

Cross-site cookies storage access test

+

anti-tracker-test.com

+

different site, cross-origin iframe

+ + + diff --git a/app/src/androidTest/assets/pages/externalLinks.html b/app/src/androidTest/assets/pages/externalLinks.html new file mode 100644 index 000000000..adf03cffc --- /dev/null +++ b/app/src/androidTest/assets/pages/externalLinks.html @@ -0,0 +1,22 @@ + + + + Html_Control_Form + + + + +

Misc Link Types

+
+ External link +
+ +
+ Email link +
+ +
+ Telephone link +
+ + diff --git a/app/src/androidTest/assets/pages/htmlControls.html b/app/src/androidTest/assets/pages/htmlControls.html new file mode 100644 index 000000000..a094974fc --- /dev/null +++ b/app/src/androidTest/assets/pages/htmlControls.html @@ -0,0 +1,74 @@ + + + + Html_Control_Form + + + + +

Calendar Form

+
+ + +
+
+ +

Clock Form

+
+ + +
+
+ +

Color Form

+
+ + +
+
+ +

Drop-down Form

+ + +
+ + + + + + + + + + diff --git a/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt b/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt index f67d862b4..bb0c3b687 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/components/FxaServer.kt @@ -5,8 +5,8 @@ package org.mozilla.fenix.components import android.content.Context -import mozilla.components.service.fxa.ServerConfig.Server import mozilla.components.service.fxa.ServerConfig +import mozilla.components.service.fxa.ServerConfig.Server /** * Utility to configure Firefox Account stage servers. diff --git a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt index 59c89de0d..700dd438a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/glean/BaselinePingTest.kt @@ -24,8 +24,8 @@ import mozilla.components.service.glean.net.ConceptFetchHttpUploader import mozilla.components.service.glean.testing.GleanTestLocalServer import okhttp3.mockwebserver.RecordedRequest import org.json.JSONObject -import org.junit.Assert.assertTrue import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.BeforeClass import org.junit.Rule @@ -36,9 +36,9 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.MockWebServerHelper -import java.util.concurrent.TimeUnit import java.io.BufferedReader import java.io.ByteArrayInputStream +import java.util.concurrent.TimeUnit import java.util.zip.GZIPInputStream /** diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/Assert.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/Assert.kt index b960f132b..0fc65f27a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/Assert.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Assert.kt @@ -5,11 +5,6 @@ package org.mozilla.fenix.helpers import android.graphics.Bitmap - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - import android.graphics.Color import org.junit.Assert.assertEquals diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt index 2162531d4..d0e69cb86 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/Constants.kt @@ -21,4 +21,10 @@ object Constants { const val LONG_CLICK_DURATION: Long = 5000 const val LISTS_MAXSWIPES: Int = 3 const val RETRY_COUNT = 3 + + val searchEngineCodes = mapOf( + "Google" to "client=firefox-b-m", + "Bing" to "firefox&pc=MOZB&form=MOZMBA", + "DuckDuckGo" to "t=fpas", + ) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt index 5cb27ea94..d9a56df8a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt @@ -4,72 +4,84 @@ package org.mozilla.fenix.helpers -import android.content.Context import androidx.test.platform.app.InstrumentationRegistry import org.mozilla.fenix.ext.settings -class FeatureSettingsHelper { - private val context: Context = InstrumentationRegistry.getInstrumentation().targetContext - private val settings = context.settings() - - // saving default values of feature flags - private var isPocketEnabled: Boolean = settings.showPocketRecommendationsFeature - private var isJumpBackInCFREnabled: Boolean = settings.shouldShowJumpBackInCFR - private var isRecentTabsFeatureEnabled: Boolean = settings.showRecentTabsFeature - private var isRecentlyVisitedFeatureEnabled: Boolean = settings.historyMetadataUIFeature - private var isUserKnowsAboutPwasTrue: Boolean = settings.userKnowsAboutPwas - private var isTCPCFREnabled: Boolean = settings.shouldShowTotalCookieProtectionCFR - private var isWallpaperOnboardingEnabled: Boolean = settings.showWallpaperOnboarding - - fun setPocketEnabled(enabled: Boolean) { - settings.showPocketRecommendationsFeature = enabled - } +/** + * Helper for querying the status and modifying various features and settings in the application. + */ +interface FeatureSettingsHelper { + /** + * Whether the onboarding for existing users should be shown or not. + * It should appear only once on the first visit to homescreen. + */ + var isHomeOnboardingDialogEnabled: Boolean - fun setJumpBackCFREnabled(enabled: Boolean) { - settings.shouldShowJumpBackInCFR = enabled - } + /** + * Whether the Pocket stories feature is enabled or not. + */ + var isPocketEnabled: Boolean - fun setShowWallpaperOnboarding(enabled: Boolean) { - settings.showWallpaperOnboarding = enabled - } + /** + * Whether the "Jump back in" CFR should be shown or not. + * It should appear on the first visit to homescreen given that there is a tab opened. + */ + var isJumpBackInCFREnabled: Boolean - fun setRecentTabsFeatureEnabled(enabled: Boolean) { - settings.showRecentTabsFeature = enabled - } + /** + * Whether the onboarding dialog for choosing wallpapers should be shown or not. + */ + var isWallpaperOnboardingEnabled: Boolean - fun setRecentlyVisitedFeatureEnabled(enabled: Boolean) { - settings.historyMetadataUIFeature = enabled - } + /** + * Whether the "Jump back in" homescreen section is enabled or not. + * It shows the last visited tab on this device and on other synced devices. + */ + var isRecentTabsFeatureEnabled: Boolean - fun setStrictETPEnabled() { - settings.setStrictETP() - } + /** + * Whether the "Recently visited" homescreen section is enabled or not. + * It can show up to 9 history highlights and history groups. + */ + var isRecentlyVisitedFeatureEnabled: Boolean - fun disablePwaCFR(disable: Boolean) { - settings.userKnowsAboutPwas = disable - } + /** + * Whether the onboarding dialog for PWAs should be shown or not. + * It can show the first time a website that can be installed as a PWA is accessed. + */ + var isPWAsPromptEnabled: Boolean - fun deleteSitePermissions(delete: Boolean) { - settings.deleteSitePermissions = delete - } + /** + * Whether the "Site permissions" option is checked in the "Delete browsing data" screen or not. + */ + var isDeleteSitePermissionsEnabled: Boolean /** * Enable or disable showing the TCP CFR when accessing a webpage for the first time. */ - fun setTCPCFREnabled(shouldShowCFR: Boolean) { - settings.shouldShowTotalCookieProtectionCFR = shouldShowCFR - } + var isTCPCFREnabled: Boolean + + /** + * The current "Enhanced Tracking Protection" policy. + * @see ETPPolicy + */ + var etpPolicy: ETPPolicy - // Important: - // Use this after each test if you have modified these feature settings - // to make sure the app goes back to the default state - fun resetAllFeatureFlags() { - settings.showPocketRecommendationsFeature = isPocketEnabled - settings.shouldShowJumpBackInCFR = isJumpBackInCFREnabled - settings.showRecentTabsFeature = isRecentTabsFeatureEnabled - settings.historyMetadataUIFeature = isRecentlyVisitedFeatureEnabled - settings.userKnowsAboutPwas = isUserKnowsAboutPwasTrue - settings.shouldShowTotalCookieProtectionCFR = isTCPCFREnabled - settings.showWallpaperOnboarding = isWallpaperOnboardingEnabled + fun applyFlagUpdates() + + fun resetAllFeatureFlags() + + companion object { + val settings = InstrumentationRegistry.getInstrumentation().targetContext.settings() } } + +/** + * All "Enhanced Tracking Protection" modes. + */ +enum class ETPPolicy { + STANDARD, + STRICT, + CUSTOM, + ; +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt new file mode 100644 index 000000000..a7869382d --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelperDelegate.kt @@ -0,0 +1,159 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.helpers + +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.getPreferenceKey +import org.mozilla.fenix.helpers.ETPPolicy.CUSTOM +import org.mozilla.fenix.helpers.ETPPolicy.STANDARD +import org.mozilla.fenix.helpers.ETPPolicy.STRICT +import org.mozilla.fenix.helpers.FeatureSettingsHelper.Companion.settings +import org.mozilla.fenix.helpers.TestHelper.appContext +import org.mozilla.fenix.onboarding.FenixOnboarding +import org.mozilla.fenix.utils.Settings + +/** + * Helper for querying the status and modifying various features and settings in the application. + */ +class FeatureSettingsHelperDelegate : FeatureSettingsHelper { + /** + * The current feature flags used inside the app before the tests start. + * These will be restored when the tests end. + */ + private val initialFeatureFlags = FeatureFlags( + isHomeOnboardingDialogEnabled = settings.showHomeOnboardingDialog, + homeOnboardingDialogVersion = getHomeOnboardingVersion(), + isPocketEnabled = settings.showPocketRecommendationsFeature, + isJumpBackInCFREnabled = settings.shouldShowJumpBackInCFR, + isRecentTabsFeatureEnabled = settings.showRecentTabsFeature, + isRecentlyVisitedFeatureEnabled = settings.historyMetadataUIFeature, + isPWAsPromptEnabled = !settings.userKnowsAboutPwas, + isTCPCFREnabled = settings.shouldShowTotalCookieProtectionCFR, + isWallpaperOnboardingEnabled = settings.showWallpaperOnboarding, + isDeleteSitePermissionsEnabled = settings.deleteSitePermissions, + etpPolicy = getETPPolicy(settings), + ) + + /** + * The current feature flags updated in tests. + */ + private var updatedFeatureFlags = initialFeatureFlags.copy() + + override var isHomeOnboardingDialogEnabled: Boolean + get() = updatedFeatureFlags.isHomeOnboardingDialogEnabled && + FenixOnboarding(appContext).userHasBeenOnboarded() + set(value) { + updatedFeatureFlags.isHomeOnboardingDialogEnabled = value + updatedFeatureFlags.homeOnboardingDialogVersion = when (value) { + true -> FenixOnboarding.CURRENT_ONBOARDING_VERSION + false -> 0 + } + } + override var isPocketEnabled: Boolean by updatedFeatureFlags::isPocketEnabled + override var isJumpBackInCFREnabled: Boolean by updatedFeatureFlags::isJumpBackInCFREnabled + override var isWallpaperOnboardingEnabled: Boolean by updatedFeatureFlags::isWallpaperOnboardingEnabled + override var isRecentTabsFeatureEnabled: Boolean by updatedFeatureFlags::isRecentTabsFeatureEnabled + override var isRecentlyVisitedFeatureEnabled: Boolean by updatedFeatureFlags::isRecentlyVisitedFeatureEnabled + override var isPWAsPromptEnabled: Boolean by updatedFeatureFlags::isPWAsPromptEnabled + override var isTCPCFREnabled: Boolean by updatedFeatureFlags::isTCPCFREnabled + override var etpPolicy: ETPPolicy by updatedFeatureFlags::etpPolicy + + override fun applyFlagUpdates() { + applyFeatureFlags(updatedFeatureFlags) + } + + override fun resetAllFeatureFlags() { + applyFeatureFlags(initialFeatureFlags) + } + override var isDeleteSitePermissionsEnabled: Boolean by updatedFeatureFlags::isDeleteSitePermissionsEnabled + + private fun applyFeatureFlags(featureFlags: FeatureFlags) { + settings.showHomeOnboardingDialog = featureFlags.isHomeOnboardingDialogEnabled + setHomeOnboardingVersion(featureFlags.homeOnboardingDialogVersion) + settings.showPocketRecommendationsFeature = featureFlags.isPocketEnabled + settings.shouldShowJumpBackInCFR = featureFlags.isJumpBackInCFREnabled + settings.showRecentTabsFeature = featureFlags.isRecentTabsFeatureEnabled + settings.historyMetadataUIFeature = featureFlags.isRecentlyVisitedFeatureEnabled + settings.userKnowsAboutPwas = !featureFlags.isPWAsPromptEnabled + settings.shouldShowTotalCookieProtectionCFR = featureFlags.isTCPCFREnabled + settings.showWallpaperOnboarding = featureFlags.isWallpaperOnboardingEnabled + settings.deleteSitePermissions = featureFlags.isDeleteSitePermissionsEnabled + setETPPolicy(featureFlags.etpPolicy) + } +} + +private data class FeatureFlags( + var isHomeOnboardingDialogEnabled: Boolean, + var homeOnboardingDialogVersion: Int, + var isPocketEnabled: Boolean, + var isJumpBackInCFREnabled: Boolean, + var isRecentTabsFeatureEnabled: Boolean, + var isRecentlyVisitedFeatureEnabled: Boolean, + var isPWAsPromptEnabled: Boolean, + var isTCPCFREnabled: Boolean, + var isWallpaperOnboardingEnabled: Boolean, + var isDeleteSitePermissionsEnabled: Boolean, + var etpPolicy: ETPPolicy, +) + +internal fun getETPPolicy(settings: Settings): ETPPolicy { + return when { + settings.useStrictTrackingProtection -> STRICT + settings.useCustomTrackingProtection -> CUSTOM + else -> STANDARD + } +} + +private fun setETPPolicy(policy: ETPPolicy) { + when (policy) { + STRICT -> settings.setStrictETP() + // The following two cases update ETP in the same way "setStrictETP" does. + STANDARD -> { + settings.preferences.edit() + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict_default), + false, + ) + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_custom_option), + false, + ) + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard_option), + true, + ) + .commit() + } + CUSTOM -> { + settings.preferences.edit() + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_strict_default), + false, + ) + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_standard_option), + true, + ) + .putBoolean( + appContext.getPreferenceKey(R.string.pref_key_tracking_protection_custom_option), + true, + ) + .commit() + } + } +} + +private fun getHomeOnboardingVersion(): Int { + return FenixOnboarding(appContext) + .preferences + .getInt(FenixOnboarding.LAST_VERSION_ONBOARDING_KEY, 0) +} + +private fun setHomeOnboardingVersion(version: Int) { + FenixOnboarding(appContext) + .preferences.edit() + .putInt(FenixOnboarding.LAST_VERSION_ONBOARDING_KEY, version) + .commit() +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt index 368443b10..efda02186 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/HomeActivityTestRule.kt @@ -6,12 +6,12 @@ package org.mozilla.fenix.helpers -import android.app.Activity import android.view.ViewConfiguration.getLongPressTimeout import androidx.test.espresso.intent.rule.IntentsTestRule import androidx.test.rule.ActivityTestRule import androidx.test.uiautomator.UiSelector import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.helpers.FeatureSettingsHelper.Companion.settings import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.onboarding.FenixOnboarding @@ -27,34 +27,91 @@ class HomeActivityTestRule( initialTouchMode: Boolean = false, launchActivity: Boolean = true, private val skipOnboarding: Boolean = false, -) : - ActivityTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) { +) : ActivityTestRule(HomeActivity::class.java, initialTouchMode, launchActivity), + FeatureSettingsHelper by FeatureSettingsHelperDelegate() { + + // Using a secondary constructor allows us to easily delegate the settings to FeatureSettingsHelperDelegate. + // Otherwise if wanting to use the same names we would have to override these settings in the primary + // constructor and in that elide the FeatureSettingsHelperDelegate. + constructor( + initialTouchMode: Boolean = false, + launchActivity: Boolean = true, + skipOnboarding: Boolean = false, + isHomeOnboardingDialogEnabled: Boolean = settings.showHomeOnboardingDialog && + FenixOnboarding(appContext).userHasBeenOnboarded(), + isPocketEnabled: Boolean = settings.showPocketRecommendationsFeature, + isJumpBackInCFREnabled: Boolean = settings.shouldShowJumpBackInCFR, + isRecentTabsFeatureEnabled: Boolean = settings.showRecentTabsFeature, + isRecentlyVisitedFeatureEnabled: Boolean = settings.historyMetadataUIFeature, + isPWAsPromptEnabled: Boolean = !settings.userKnowsAboutPwas, + isTCPCFREnabled: Boolean = settings.shouldShowTotalCookieProtectionCFR, + isWallpaperOnboardingEnabled: Boolean = settings.showWallpaperOnboarding, + isDeleteSitePermissionsEnabled: Boolean = settings.deleteSitePermissions, + etpPolicy: ETPPolicy = getETPPolicy(settings), + ) : this(initialTouchMode, launchActivity, skipOnboarding) { + this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled + this.isPocketEnabled = isPocketEnabled + this.isJumpBackInCFREnabled = isJumpBackInCFREnabled + this.isRecentTabsFeatureEnabled = isRecentTabsFeatureEnabled + this.isRecentlyVisitedFeatureEnabled = isRecentlyVisitedFeatureEnabled + this.isPWAsPromptEnabled = isPWAsPromptEnabled + this.isTCPCFREnabled = isTCPCFREnabled + this.isWallpaperOnboardingEnabled = isWallpaperOnboardingEnabled + this.isDeleteSitePermissionsEnabled = isDeleteSitePermissionsEnabled + this.etpPolicy = etpPolicy + } /** - * Helper for updating various app settings that could interfere with the tests. - * Tests that use [HomeActivityTestRule] are expected to rely on this [FeatureSettingsHelper] - * instead of instantiating their own. - * - * The main benefit this brings is better ordering of operations with the settings cleanup - * automatically happening just before the [Activity] under test finishes which may as opposed to - * cleanup happening earlier and modifying the app behavior. + * Update settings after the activity was created. */ - val featureSettingsHelper = FeatureSettingsHelper() + fun applySettingsExceptions(settings: (FeatureSettingsHelper) -> Unit) { + FeatureSettingsHelperDelegate().also { + settings(it) + applyFlagUpdates() + } + } private val longTapUserPreference = getLongPressTimeout() override fun beforeActivityLaunched() { super.beforeActivityLaunched() setLongTapTimeout(3000) + applyFlagUpdates() if (skipOnboarding) { skipOnboardingBeforeLaunch() } } override fun afterActivityFinished() { super.afterActivityFinished() setLongTapTimeout(longTapUserPreference) - featureSettingsHelper.resetAllFeatureFlags() + resetAllFeatureFlags() closeNotificationShade() } + + companion object { + /** + * Create a new instance of [HomeActivityTestRule] which by default will disable specific + * app features that would otherwise negatively impact most tests. + * + * The disabled features are: + * - the Jump back in CFR, + * - the Total Cookie Protection CFR, + * - the PWA prompt dialog, + * - the wallpaper onboarding. + */ + fun withDefaultSettingsOverrides( + initialTouchMode: Boolean = false, + launchActivity: Boolean = true, + skipOnboarding: Boolean = false, + ) = HomeActivityTestRule( + initialTouchMode = initialTouchMode, + launchActivity = launchActivity, + skipOnboarding = skipOnboarding, + isJumpBackInCFREnabled = false, + isPWAsPromptEnabled = false, + isTCPCFREnabled = false, + isWallpaperOnboardingEnabled = false, + ) + } } /** @@ -65,17 +122,59 @@ class HomeActivityTestRule( * @param launchActivity See [IntentsTestRule] */ -class HomeActivityIntentTestRule( +class HomeActivityIntentTestRule internal constructor( initialTouchMode: Boolean = false, launchActivity: Boolean = true, private val skipOnboarding: Boolean = false, -) : - IntentsTestRule(HomeActivity::class.java, initialTouchMode, launchActivity) { +) : IntentsTestRule(HomeActivity::class.java, initialTouchMode, launchActivity), + FeatureSettingsHelper by FeatureSettingsHelperDelegate() { + // Using a secondary constructor allows us to easily delegate the settings to FeatureSettingsHelperDelegate. + // Otherwise if wanting to use the same names we would have to override these settings in the primary + // constructor and in that elide the FeatureSettingsHelperDelegate. + constructor( + initialTouchMode: Boolean = false, + launchActivity: Boolean = true, + skipOnboarding: Boolean = false, + isHomeOnboardingDialogEnabled: Boolean = settings.showHomeOnboardingDialog && + FenixOnboarding(appContext).userHasBeenOnboarded(), + isPocketEnabled: Boolean = settings.showPocketRecommendationsFeature, + isJumpBackInCFREnabled: Boolean = settings.shouldShowJumpBackInCFR, + isRecentTabsFeatureEnabled: Boolean = settings.showRecentTabsFeature, + isRecentlyVisitedFeatureEnabled: Boolean = settings.historyMetadataUIFeature, + isPWAsPromptEnabled: Boolean = !settings.userKnowsAboutPwas, + isTCPCFREnabled: Boolean = settings.shouldShowTotalCookieProtectionCFR, + isWallpaperOnboardingEnabled: Boolean = settings.showWallpaperOnboarding, + isDeleteSitePermissionsEnabled: Boolean = settings.deleteSitePermissions, + etpPolicy: ETPPolicy = getETPPolicy(settings), + ) : this(initialTouchMode, launchActivity, skipOnboarding) { + this.isHomeOnboardingDialogEnabled = isHomeOnboardingDialogEnabled + this.isPocketEnabled = isPocketEnabled + this.isJumpBackInCFREnabled = isJumpBackInCFREnabled + this.isRecentTabsFeatureEnabled = isRecentTabsFeatureEnabled + this.isRecentlyVisitedFeatureEnabled = isRecentlyVisitedFeatureEnabled + this.isPWAsPromptEnabled = isPWAsPromptEnabled + this.isTCPCFREnabled = isTCPCFREnabled + this.isWallpaperOnboardingEnabled = isWallpaperOnboardingEnabled + this.isDeleteSitePermissionsEnabled = isDeleteSitePermissionsEnabled + this.etpPolicy = etpPolicy + } + private val longTapUserPreference = getLongPressTimeout() + /** + * Update settings after the activity was created. + */ + fun applySettingsExceptions(settings: (FeatureSettingsHelper) -> Unit) { + FeatureSettingsHelperDelegate().apply { + settings(this) + applyFlagUpdates() + } + } + override fun beforeActivityLaunched() { super.beforeActivityLaunched() setLongTapTimeout(3000) + applyFlagUpdates() if (skipOnboarding) { skipOnboardingBeforeLaunch() } } @@ -83,6 +182,53 @@ class HomeActivityIntentTestRule( super.afterActivityFinished() setLongTapTimeout(longTapUserPreference) closeNotificationShade() + resetAllFeatureFlags() + } + + /** + * Update the settings values from when this rule was first instantiated to account for any changes + * done while running the tests. + * Useful in the scenario about the activity being restarted which would otherwise set the initial + * settings and override any changes made in the meantime. + */ + fun updateCachedSettings() { + isHomeOnboardingDialogEnabled = + settings.showHomeOnboardingDialog && FenixOnboarding(appContext).userHasBeenOnboarded() + isPocketEnabled = settings.showPocketRecommendationsFeature + isJumpBackInCFREnabled = settings.shouldShowJumpBackInCFR + isRecentTabsFeatureEnabled = settings.showRecentTabsFeature + isRecentlyVisitedFeatureEnabled = settings.historyMetadataUIFeature + isPWAsPromptEnabled = !settings.userKnowsAboutPwas + isTCPCFREnabled = settings.shouldShowTotalCookieProtectionCFR + isWallpaperOnboardingEnabled = settings.showWallpaperOnboarding + isDeleteSitePermissionsEnabled = settings.deleteSitePermissions + etpPolicy = getETPPolicy(settings) + } + + companion object { + /** + * Create a new instance of [HomeActivityIntentTestRule] which by default will disable specific + * app features that would otherwise negatively impact most tests. + * + * The disabled features are: + * - the Jump back in CFR, + * - the Total Cookie Protection CFR, + * - the PWA prompt dialog, + * - the wallpaper onboarding. + */ + fun withDefaultSettingsOverrides( + initialTouchMode: Boolean = false, + launchActivity: Boolean = true, + skipOnboarding: Boolean = false, + ) = HomeActivityIntentTestRule( + initialTouchMode = initialTouchMode, + launchActivity = launchActivity, + skipOnboarding = skipOnboarding, + isJumpBackInCFREnabled = false, + isPWAsPromptEnabled = false, + isTCPCFREnabled = false, + isWallpaperOnboardingEnabled = false, + ) } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/MockLocationUpdatesRule.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/MockLocationUpdatesRule.kt index 3e8ca4d87..119803bec 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/MockLocationUpdatesRule.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/MockLocationUpdatesRule.kt @@ -12,9 +12,9 @@ import android.os.SystemClock import android.util.Log import androidx.test.core.app.ApplicationProvider import org.junit.rules.ExternalResource +import org.mozilla.fenix.helpers.TestHelper.mDevice import java.util.Date import kotlin.random.Random -import org.mozilla.fenix.helpers.TestHelper.mDevice private const val mockProviderName = LocationManager.GPS_PROVIDER diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt index 3efe5025d..5d90a06a4 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/SearchDispatcher.kt @@ -7,14 +7,14 @@ package org.mozilla.fenix.helpers import android.os.Handler import android.os.Looper import androidx.test.platform.app.InstrumentationRegistry -import java.io.IOException -import java.io.InputStream import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.RecordedRequest import okio.Buffer import okio.source +import java.io.IOException +import java.io.InputStream /** * A [MockWebServer] [Dispatcher] that will return a generic search results page in the body of diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt index 8b3c42387..fd3874b30 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt @@ -99,6 +99,18 @@ object TestAssetHelper { return TestAsset(url, "", "") } + fun getHTMLControlsFormAsset(server: MockWebServer): TestAsset { + val url = server.url("pages/htmlControls.html").toString().toUri()!! + + return TestAsset(url, "", "") + } + + fun getExternalLinksAsset(server: MockWebServer): TestAsset { + val url = server.url("pages/externalLinks.html").toString().toUri()!! + + return TestAsset(url, "", "") + } + fun getAudioPageAsset(server: MockWebServer): TestAsset { val url = server.url("pages/audioMediaPage.html").toString().toUri()!! val title = "Audio_Test_Page" diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt index bd5f764af..368cd8244 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt @@ -9,6 +9,8 @@ package org.mozilla.fenix.helpers import android.app.ActivityManager import android.app.PendingIntent import android.content.ActivityNotFoundException +import android.content.ClipData +import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -95,6 +97,7 @@ object TestHelper { fun restartApp(activity: HomeActivityIntentTestRule) { with(activity) { + updateCachedSettings() finishActivity() mDevice.waitForIdle() launchActivity(null) @@ -417,4 +420,14 @@ object TestHelper { Configuration::class.java, ).invoke(am, config) } + + /** + * Creates clipboard data. + */ + fun setTextToClipBoard(context: Context, message: String) { + val clipBoard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clipData = ClipData.newPlainText("label", message) + + clipBoard.setPrimaryClip(clipData) + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt index e1da90152..7e0c3bfc1 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/matchers/BitmapDrawableMatcher.kt @@ -5,13 +5,13 @@ package org.mozilla.fenix.helpers.matchers import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.StateListDrawable import android.view.View import android.widget.ImageView import androidx.test.espresso.matcher.BoundedMatcher import org.hamcrest.Description -import android.graphics.drawable.BitmapDrawable -import android.graphics.drawable.StateListDrawable -import android.graphics.drawable.Drawable class BitmapDrawableMatcher(private val bitmap: Bitmap, private val name: String) : BoundedMatcher(ImageView::class.java) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt index bab02da39..e2aae7321 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/perf/StartupExcessiveResourceUseTest.kt @@ -33,7 +33,7 @@ import org.mozilla.fenix.helpers.HomeActivityTestRule * * Say no to main thread IO! 🙅 */ -private const val EXPECTED_SUPPRESSION_COUNT = 17 +private const val EXPECTED_SUPPRESSION_COUNT = 19 /** * The number of times we call the `runBlocking` coroutine method on the main thread during this diff --git a/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt index 8f5e632eb..609c57650 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/screenshots/DefaultHomeScreenTest.kt @@ -14,8 +14,8 @@ import org.junit.After import org.junit.Before import org.junit.Rule import org.junit.Test -import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.ui.robots.homeScreen import tools.fastlane.screengrab.Screengrab @@ -43,7 +43,6 @@ class DefaultHomeScreenTest : ScreenshotTest() { @Test fun showDefaultHomeScreen() { homeScreen { - swipeToBottom() verifyAccountsSignInButton() Screengrab.screenshot("HomeScreenRobot_home-screen-scroll") TestAssetHelper.waitingTime diff --git a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt index 658280433..e73dfd640 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/screenshots/MenuScreenShotTest.kt @@ -43,8 +43,7 @@ class MenuScreenShotTest : ScreenshotTest() { val localeTestRule = LocaleTestRule() @get:Rule - var mActivityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = mActivityTestRule.featureSettingsHelper + var mActivityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Before fun setUp() { @@ -53,8 +52,6 @@ class MenuScreenShotTest : ScreenshotTest() { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setTCPCFREnabled(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt index e0c6f9fa5..3c776d238 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/BookmarksTest.kt @@ -13,7 +13,6 @@ import mozilla.appservices.places.BookmarkRoot import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R @@ -48,8 +47,7 @@ class BookmarksTest { } @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Rule @JvmField @@ -62,8 +60,6 @@ class BookmarksTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) } @After @@ -105,7 +101,7 @@ class BookmarksTest { verifyFolderTitle("Bookmarks Menu") verifyFolderTitle("Bookmarks Toolbar") verifyFolderTitle("Other Bookmarks") - verifySignInToSyncButton() + verifySyncSignInButton() } }.clickSingInToSyncButton { verifyTurnOnSyncToolbarTitle() @@ -222,7 +218,7 @@ class BookmarksTest { clickClearButton() longClickToolbar() clickPasteText() - verifyPastedToolbarText(defaultWebPage.url.toString()) + verifyTypedToolbarText(defaultWebPage.url.toString()) } } @@ -264,6 +260,83 @@ class BookmarksTest { } } + @Test + fun openAllInTabsTest() { + val webPages = listOf( + TestAssetHelper.getGenericAsset(mockWebServer, 1), + TestAssetHelper.getGenericAsset(mockWebServer, 2), + TestAssetHelper.getGenericAsset(mockWebServer, 3), + TestAssetHelper.getGenericAsset(mockWebServer, 4), + ) + + homeScreen { + }.openThreeDotMenu { + }.openBookmarks { + createFolder("root") + createFolder("sub", "root") + createFolder("empty", "root") + }.closeMenu { + } + + browserScreen { + createBookmark(webPages[0].url) + createBookmark(webPages[1].url, "root") + createBookmark(webPages[2].url, "root") + createBookmark(webPages[3].url, "sub") + }.openTabDrawer { + closeTab() + } + + browserScreen { + }.openThreeDotMenu { + }.openBookmarks { + }.openThreeDotMenu("root") { + }.clickOpenAllInTabs { + verifyTabTrayIsOpened() + verifyNormalModeSelected() + + verifyExistingOpenTabs("Test_Page_2", "Test_Page_3", "Test_Page_4") + + // Bookmark that is not under the root folder should not be opened + verifyNoExistingOpenTabs("Test_Page_1") + } + } + + @Test + fun openAllInPrivateTabsTest() { + val webPages = listOf( + TestAssetHelper.getGenericAsset(mockWebServer, 1), + TestAssetHelper.getGenericAsset(mockWebServer, 2), + ) + + homeScreen { + }.openThreeDotMenu { + }.openBookmarks { + createFolder("root") + createFolder("sub", "root") + createFolder("empty", "root") + }.closeMenu { + } + + browserScreen { + createBookmark(webPages[0].url, "root") + createBookmark(webPages[1].url, "sub") + }.openTabDrawer { + closeTab() + } + + browserScreen { + }.openThreeDotMenu { + }.openBookmarks { + }.openThreeDotMenu("root") { + }.clickOpenAllInPrivateTabs { + verifyTabTrayIsOpened() + verifyPrivateModeSelected() + + verifyExistingOpenTabs("Test_Page_1", "Test_Page_2") + } + } + @Test fun openBookmarkInPrivateTabTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -354,7 +427,6 @@ class BookmarksTest { @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openSelectionInNewTabTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -384,7 +456,6 @@ class BookmarksTest { @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openSelectionInPrivateTabTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/BrowsingErrorPagesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/BrowsingErrorPagesTest.kt index c1728fbf7..2dde0c8f8 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/BrowsingErrorPagesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/BrowsingErrorPagesTest.kt @@ -5,7 +5,6 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri -import org.junit.Before import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R @@ -26,20 +25,12 @@ class BrowsingErrorPagesTest { private val harmfulSiteWarning = getStringResource(R.string.mozac_browser_errorpages_safe_harmful_uri_title) @get: Rule - val mActivityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = mActivityTestRule.featureSettingsHelper + val mActivityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Rule @JvmField val retryTestRule = RetryTestRule(3) - @Before - fun setUp() { - // disabling the jump-back-in pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - } - @SmokeTest @Test fun blockMalwarePageTest() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt index d2fc9d0c5..4499583a3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CollectionTest.kt @@ -15,7 +15,6 @@ import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset import org.mozilla.fenix.ui.robots.browserScreen @@ -35,23 +34,21 @@ class CollectionTest { private val firstCollectionName = "testcollection_1" private val secondCollectionName = "testcollection_2" private val collectionName = "First Collection" - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule val composeTestRule = AndroidComposeTestRule( - HomeActivityIntentTestRule(), - { it.activity }, - ) - - @Before - fun setUp() { // disabling these features to have better visibility of Collections, // and to avoid multiple matches on tab items - featureSettingsHelper.setRecentTabsFeatureEnabled(false) - featureSettingsHelper.setPocketEnabled(false) - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setRecentlyVisitedFeatureEnabled(false) + HomeActivityIntentTestRule( + isPocketEnabled = false, + isJumpBackInCFREnabled = false, + isRecentTabsFeatureEnabled = false, + isRecentlyVisitedFeatureEnabled = false, + ), + ) { it.activity } + @Before + fun setUp() { mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() @@ -62,9 +59,6 @@ class CollectionTest { @After fun tearDown() { mockWebServer.shutdown() - - // resetting modified features enabled setting to default - featureSettingsHelper.resetAllFeatureFlags() } @SmokeTest diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt index 96c357382..087121e39 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextMenusTest.kt @@ -9,13 +9,11 @@ import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper @@ -42,14 +40,12 @@ class ContextMenusTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() @Rule @JvmField val retryTestRule = RetryTestRule(3) - private val featureSettingsHelper = FeatureSettingsHelper() - @Before fun setUp() { activityIntentTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false @@ -58,19 +54,15 @@ class ContextMenusTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setTCPCFREnabled(false) } @After fun tearDown() { mockWebServer.shutdown() - featureSettingsHelper.resetAllFeatureFlags() } @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun verifyContextOpenLinkNewTab() { val pageLinks = TestAssetHelper.getGenericAsset(mockWebServer, 4) @@ -80,7 +72,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("Link 1") + longClickLink("Link 1") verifyLinkContextMenuItems(genericURL.url) clickContextOpenLinkInNewTab() verifySnackBarText("New tab opened") @@ -95,7 +87,6 @@ class ContextMenusTest { @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun verifyContextOpenLinkPrivateTab() { val pageLinks = TestAssetHelper.getGenericAsset(mockWebServer, 4) @@ -105,7 +96,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("Link 2") + longClickLink("Link 2") verifyLinkContextMenuItems(genericURL.url) clickContextOpenLinkInPrivateTab() verifySnackBarText("New private tab opened") @@ -127,7 +118,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("Link 3") + longClickLink("Link 3") verifyLinkContextMenuItems(genericURL.url) clickContextCopyLink() verifySnackBarText("Link copied to clipboard") @@ -147,7 +138,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("Link 1") + longClickLink("Link 1") verifyLinkContextMenuItems(genericURL.url) clickContextShareLink(genericURL.url) // verify share intent is matched with associated URL } @@ -163,7 +154,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("test_link_image") + longClickLink("test_link_image") verifyLinkImageContextMenuItems(imageResource.url) clickContextOpenImageNewTab() verifySnackBarText("New tab opened") @@ -182,7 +173,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("test_link_image") + longClickLink("test_link_image") verifyLinkImageContextMenuItems(imageResource.url) clickContextCopyImageLocation() verifySnackBarText("Link copied to clipboard") @@ -202,7 +193,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("test_link_image") + longClickLink("test_link_image") verifyLinkImageContextMenuItems(imageResource.url) clickContextSaveImage() } @@ -215,7 +206,6 @@ class ContextMenusTest { } } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun verifyContextMixedVariations() { val pageLinks = @@ -228,13 +218,13 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(pageLinks.url) { mDevice.waitForIdle() - longClickMatchingText("Link 1") + longClickLink("Link 1") verifyLinkContextMenuItems(genericURL.url) dismissContentContextMenu(genericURL.url) - longClickMatchingText("test_link_image") + longClickLink("test_link_image") verifyLinkImageContextMenuItems(imageResource.url) dismissContentContextMenu(imageResource.url) - longClickMatchingText("test_no_link_image") + longClickLink("test_no_link_image") verifyNoLinkImageContextMenuItems(imageResource.url) } } @@ -246,7 +236,7 @@ class ContextMenusTest { navigationToolbar { }.enterURLAndEnterToBrowser(genericURL.url) { - longClickMatchingText(genericURL.content) + longClickLink(genericURL.content) }.clickShareSelectedText { verifyAndroidShareLayout() } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ContextualHintsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextualHintsTest.kt new file mode 100644 index 000000000..b5c16efc4 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ContextualHintsTest.kt @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui + +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.helpers.AndroidAssetDispatcher +import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset +import org.mozilla.fenix.helpers.TestHelper.mDevice +import org.mozilla.fenix.ui.robots.navigationToolbar + +/** + * Tests for verifying the new Cookie protection & homescreen feature hints. + * Note: This involves setting the feature flags On for CFRs which are disabled elsewhere. + * + */ +class ContextualHintsTest { + private lateinit var mockWebServer: MockWebServer + + @get:Rule + val activityTestRule = HomeActivityTestRule( + isJumpBackInCFREnabled = true, + isTCPCFREnabled = true, + isPocketEnabled = false, + isRecentlyVisitedFeatureEnabled = false, + ) + + @Before + fun setUp() { + mockWebServer = MockWebServer().apply { + dispatcher = AndroidAssetDispatcher() + start() + } + } + + @After + fun tearDown() { + mockWebServer.shutdown() + } + + @Test + fun jumpBackInCFRTest() { + val genericPage = getGenericAsset(mockWebServer, 1) + + navigationToolbar { + }.enterURLAndEnterToBrowser(genericPage.url) { + verifyCookiesProtectionHint() + // One back press to dismiss the TCP hint + mDevice.pressBack() + }.goToHomescreen { + verifyJumpBackInMessage() + } + } + + @Test + fun cookieProtectionHintTest() { + val genericPage = getGenericAsset(mockWebServer, 1) + + navigationToolbar { + }.enterURLAndEnterToBrowser(genericPage.url) { + verifyCookiesProtectionHint() + } + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt index b81f57169..4d6df1534 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt @@ -12,7 +12,6 @@ import org.junit.Test import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper.getStringResource @@ -22,21 +21,20 @@ import org.mozilla.fenix.ui.robots.navigationToolbar class CrashReportingTest { private lateinit var mDevice: UiDevice private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() private val tabCrashMessage = getStringResource(R.string.tab_crash_title_2) @get:Rule val activityTestRule = AndroidComposeTestRule( - HomeActivityIntentTestRule(), - { it.activity }, - ) + HomeActivityIntentTestRule( + isPocketEnabled = false, + isJumpBackInCFREnabled = false, + isWallpaperOnboardingEnabled = false, + isTCPCFREnabled = false, + ), + ) { it.activity } @Before fun setUp() { - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setPocketEnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) - mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() @@ -47,7 +45,6 @@ class CrashReportingTest { @After fun tearDown() { mockWebServer.shutdown() - featureSettingsHelper.resetAllFeatureFlags() } @Test @@ -77,7 +74,6 @@ class CrashReportingTest { } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/25029") @SmokeTest @Test fun useAppWhileTabIsCrashedTest() { @@ -110,7 +106,6 @@ class CrashReportingTest { @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun privateBrowsingUseAppWhileTabIsCrashedTest() { val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val secondWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 2) @@ -124,7 +119,6 @@ class CrashReportingTest { }.openNewTab { }.submitQuery(secondWebPage.url.toString()) { waitForPageToLoad() - verifyPageContent("Page content: 2") } navigationToolbar { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt index dbc52ad25..9b6b8ac7a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CustomTabsTest.kt @@ -14,7 +14,7 @@ import org.junit.Test import org.mozilla.fenix.IntentReceiverActivity import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper +import org.mozilla.fenix.helpers.FeatureSettingsHelperDelegate import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper.createCustomTabIntent @@ -47,7 +47,7 @@ class CustomTabsTest { false, ) - private val featureSettingsHelper = FeatureSettingsHelper() + private val featureSettingsHelper = FeatureSettingsHelperDelegate() @Before fun setUp() { @@ -57,7 +57,9 @@ class CustomTabsTest { start() } - featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.apply { + isTCPCFREnabled = false + }.applyFlagUpdates() } @After @@ -145,7 +147,7 @@ class CustomTabsTest { clickClearButton() longClickToolbar() clickPasteText() - verifyPastedToolbarText(customTabPage.url.toString()) + verifyTypedToolbarText(customTabPage.url.toString()) } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt index d5c4f9388..6545f4adc 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadFileTypesTest.kt @@ -5,14 +5,11 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri -import org.junit.After -import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import org.mozilla.fenix.customannotations.SmokeTest -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.ui.robots.navigationToolbar @@ -27,10 +24,9 @@ class DownloadFileTypesTest(fileName: String) { /* Remote test page managed by Mozilla Mobile QA team at https://github.com/mozilla-mobile/testapp */ private val downloadTestPage = "https://storage.googleapis.com/mobile_test_assets/test_app/downloads.html" private var downloadFile: String = fileName - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityTestRule = HomeActivityIntentTestRule() + val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() companion object { // Creating test data. The test will take each file name as a parameter and run it individually. @@ -48,21 +44,6 @@ class DownloadFileTypesTest(fileName: String) { ) } - @Before - fun setUp() { - // disabling the jump-back-in pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - // disable the TCP CFR that appears when loading webpages and interferes with the tests. - featureSettingsHelper.setTCPCFREnabled(false) - // disabling the PWA CFR on 3rd visit - featureSettingsHelper.disablePwaCFR(true) - } - - @After - fun tearDown() { - featureSettingsHelper.resetAllFeatureFlags() - } - @SmokeTest @Test fun downloadMultipleFileTypesTest() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt index 5fde9f0ab..d71c2b089 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/DownloadTest.kt @@ -4,9 +4,7 @@ package org.mozilla.fenix.ui -import android.os.Build import androidx.core.net.toUri -import androidx.test.filters.SdkSuppress import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.permission.PermissionRequester import androidx.test.uiautomator.UiDevice @@ -19,7 +17,6 @@ import org.junit.rules.TestRule import org.junit.rules.TestWatcher import org.junit.runner.Description import org.mozilla.fenix.customannotations.SmokeTest -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestHelper.deleteDownloadFromStorage import org.mozilla.fenix.ui.robots.browserScreen @@ -37,14 +34,13 @@ import org.mozilla.fenix.ui.robots.notificationShade **/ class DownloadTest { private lateinit var mDevice: UiDevice - private val featureSettingsHelper = FeatureSettingsHelper() /* Remote test page managed by Mozilla Mobile QA team at https://github.com/mozilla-mobile/testapp */ private val downloadTestPage = "https://storage.googleapis.com/mobile_test_assets/test_app/downloads.html" private var downloadFile: String = "" @get:Rule - val activityTestRule = HomeActivityIntentTestRule() + val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() // Making sure to grant storage access for this test running on API 28 @get: Rule @@ -65,12 +61,6 @@ class DownloadTest { @Before fun setUp() { mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - // disabling the jump-back-in pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - // disable the TCP CFR that appears when loading webpages and interferes with the tests. - featureSettingsHelper.setTCPCFREnabled(false) - // disabling the PWA CFR on 3rd visit - featureSettingsHelper.disablePwaCFR(true) // clear all existing notifications notificationShade { mDevice.openNotification() @@ -80,13 +70,11 @@ class DownloadTest { @After fun tearDown() { - featureSettingsHelper.resetAllFeatureFlags() notificationShade { cancelAllShownNotifications() } } - @Ignore("Failing with frequent ANR: https://github.com/mozilla-mobile/fenix/issues/25926") @Test fun testDownloadPrompt() { downloadFile = "web_icon.png" @@ -139,7 +127,6 @@ class DownloadTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun pauseResumeCancelDownloadTest() { @@ -171,6 +158,7 @@ class DownloadTest { - downloads appear in the list - deleting a download from device storage, removes it from the Downloads Menu too */ + @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/27220") @SmokeTest @Test fun manageDownloadsInDownloadsMenuTest() { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/EnhancedTrackingProtectionTest.kt similarity index 66% rename from app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt rename to app/src/androidTest/java/org/mozilla/fenix/ui/EnhancedTrackingProtectionTest.kt index 902f5d5ce..95ea1083f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/EnhancedTrackingProtectionTest.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.ui +import androidx.core.net.toUri import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before @@ -11,9 +12,12 @@ import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.helpers.TestHelper.appContext +import org.mozilla.fenix.helpers.TestHelper.exitMenu import org.mozilla.fenix.ui.robots.enhancedTrackingProtection import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar @@ -32,12 +36,15 @@ import org.mozilla.fenix.ui.robots.settingsSubMenuEnhancedTrackingProtection * - Verifying Enhanced Tracking Protection site exceptions */ -class StrictEnhancedTrackingProtectionTest { +class EnhancedTrackingProtectionTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule( + isJumpBackInCFREnabled = false, + isTCPCFREnabled = false, + isWallpaperOnboardingEnabled = false, + ) @Before fun setUp() { @@ -45,10 +52,6 @@ class StrictEnhancedTrackingProtectionTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setStrictETPEnabled() - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) } @After @@ -83,8 +86,8 @@ class StrictEnhancedTrackingProtectionTest { }.openEnhancedTrackingProtectionSubMenu { switchEnhancedTrackingProtectionToggle() verifyEnhancedTrackingProtectionOptionsEnabled(false) - }.goBack { - }.goBack { } + exitMenu() + } navigationToolbar { }.enterURLAndEnterToBrowser(genericPage.url) { } @@ -106,8 +109,8 @@ class StrictEnhancedTrackingProtectionTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun testStrictVisitProtectionSheet() { + appContext.settings().setStrictETP() val genericPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val trackingProtectionTest = TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer) @@ -127,9 +130,9 @@ class StrictEnhancedTrackingProtectionTest { } } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun testStrictVisitDisableExceptionToggle() { + appContext.settings().setStrictETP() val genericPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val trackingProtectionTest = TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer) @@ -162,9 +165,10 @@ class StrictEnhancedTrackingProtectionTest { } } + @Ignore("Permanent failure: https://github.com/mozilla-mobile/fenix/issues/27312") @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun testStrictVisitSheetDetails() { + appContext.settings().setStrictETP() val genericPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val trackingProtectionTest = TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer) @@ -192,4 +196,71 @@ class StrictEnhancedTrackingProtectionTest { viewTrackingContentBlockList() } } + + @Ignore("Permanent failure: https://github.com/mozilla-mobile/fenix/issues/27312") + @SmokeTest + @Test + fun customTrackingProtectionSettingsTest() { + val genericWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) + val trackingPage = TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer) + + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openEnhancedTrackingProtectionSubMenu { + verifyEnhancedTrackingProtectionOptionsEnabled() + selectTrackingProtectionOption("Custom") + verifyCustomTrackingProtectionSettings() + }.goBackToHomeScreen {} + + navigationToolbar { + // browsing a basic page to allow GV to load on a fresh run + }.enterURLAndEnterToBrowser(genericWebPage.url) { + }.openNavigationToolbar { + }.enterURLAndEnterToBrowser(trackingPage.url) {} + + enhancedTrackingProtection { + }.openEnhancedTrackingProtectionSheet { + }.openDetails { + verifyTrackingCookiesBlocked() + verifyCryptominersBlocked() + verifyFingerprintersBlocked() + verifyTrackingContentBlocked() + viewTrackingContentBlockList() + } + } + + @SmokeTest + @Test + fun blockCookiesStorageAccessTest() { + // With Standard TrackingProtection settings + val page = mockWebServer.url("pages/cross-site-cookies.html").toString().toUri() + val originSite = "https://mozilla-mobile.github.io" + val currentSite = "http://localhost:${mockWebServer.port}" + + navigationToolbar { + }.enterURLAndEnterToBrowser(page) { + }.clickRequestStorageAccessButton { + verifyCrossOriginCookiesPermissionPrompt(originSite, currentSite) + }.clickPagePermissionButton(allow = false) { + verifyPageContent("access denied") + } + } + + @SmokeTest + @Test + fun allowCookiesStorageAccessTest() { + // With Standard TrackingProtection settings + val page = mockWebServer.url("pages/cross-site-cookies.html").toString().toUri() + val originSite = "https://mozilla-mobile.github.io" + val currentSite = "http://localhost:${mockWebServer.port}" + + navigationToolbar { + }.enterURLAndEnterToBrowser(page) { + }.clickRequestStorageAccessButton { + verifyCrossOriginCookiesPermissionPrompt(originSite, currentSite) + }.clickPagePermissionButton(allow = true) { + verifyPageContent("access granted") + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt index 6243b5cec..742e68a71 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HistoryTest.kt @@ -13,7 +13,6 @@ import mozilla.components.browser.storage.sync.PlacesHistoryStorage import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R @@ -40,8 +39,7 @@ class HistoryTest { private lateinit var mDevice: UiDevice @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Before fun setUp() { @@ -53,8 +51,6 @@ class HistoryTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setTCPCFREnabled(false) } @After @@ -221,7 +217,6 @@ class HistoryTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openHistoryInNewTabTest() { val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -251,7 +246,6 @@ class HistoryTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openHistoryInPrivateTabTest() { val firstWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -336,9 +330,8 @@ class HistoryTest { } } - @Test // This test verifies the Recently Closed Tabs List and items - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") + @Test fun verifyRecentlyClosedTabsListTest() { val website = TestAssetHelper.getGenericAsset(mockWebServer, 1) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt index de3587719..e2bb8e865 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt @@ -36,8 +36,7 @@ class HomeScreenTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Rule @JvmField @@ -51,8 +50,6 @@ class HomeScreenTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setTCPCFREnabled(false) } @After @@ -144,8 +141,10 @@ class HomeScreenTest { @Test fun dismissOnboardingUsingHelpTest() { - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) + activityTestRule.applySettingsExceptions { + it.isJumpBackInCFREnabled = false + it.isWallpaperOnboardingEnabled = false + } homeScreen { verifyWelcomeHeader() @@ -172,8 +171,10 @@ class HomeScreenTest { @Test fun verifyPocketHomepageStoriesTest() { - featureSettingsHelper.setRecentTabsFeatureEnabled(false) - featureSettingsHelper.setRecentlyVisitedFeatureEnabled(false) + activityTestRule.applySettingsExceptions { + it.isRecentTabsFeatureEnabled = false + it.isRecentlyVisitedFeatureEnabled = false + } homeScreen { }.dismissOnboarding() @@ -193,8 +194,6 @@ class HomeScreenTest { @Test fun verifyCustomizeHomepageTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) navigationToolbar { }.enterURLAndEnterToBrowser(defaultWebPage.url) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt index 2380e770c..e9d4c754e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt @@ -11,7 +11,6 @@ import mozilla.components.concept.engine.mediasession.MediaSession import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.ext.components @@ -37,7 +36,7 @@ class MediaNotificationTest { private lateinit var mDevice: UiDevice @get:Rule - val activityTestRule = HomeActivityTestRule() + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() private lateinit var browserStore: BrowserStore @Rule @@ -62,7 +61,6 @@ class MediaNotificationTest { mockWebServer.shutdown() } - @Ignore("Failing with ANR: https://github.com/mozilla-mobile/fenix/issues/15754") @Test fun videoPlaybackSystemNotificationTest() { val videoTestPage = TestAssetHelper.getVideoPageAsset(mockWebServer) @@ -96,7 +94,6 @@ class MediaNotificationTest { mDevice.pressBack() } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun mediaSystemNotificationInPrivateModeTest() { val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt index e6e870621..d0629660a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NavigationToolbarTest.kt @@ -34,8 +34,7 @@ class NavigationToolbarTest { /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Before fun setUp() { @@ -44,9 +43,6 @@ class NavigationToolbarTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.disablePwaCFR(true) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt index 1b8c9950c..6f422c9ca 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt @@ -6,8 +6,6 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri import org.junit.After -import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R @@ -27,14 +25,7 @@ import org.mozilla.fenix.ui.robots.navigationToolbar class NoNetworkAccessStartupTests { @get:Rule - val activityTestRule = HomeActivityTestRule(launchActivity = false) - private val featureSettingsHelper = activityTestRule.featureSettingsHelper - - @Before - fun setUp() { - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) - } + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides(launchActivity = false) @After fun tearDown() { @@ -61,7 +52,6 @@ class NoNetworkAccessStartupTests { // Based on STR from https://github.com/mozilla-mobile/fenix/issues/16886 @Test fun networkInterruptedFromBrowserToHomeTest() { - featureSettingsHelper.setJumpBackCFREnabled(false) val url = "example.com" activityTestRule.launchActivity(null) @@ -93,7 +83,6 @@ class NoNetworkAccessStartupTests { }.refreshPage { } } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun testSignInPageWithNoNetworkConnection() { setNetworkEnabled(false) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/OnboardingFeaturesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/OnboardingFeaturesTest.kt new file mode 100644 index 000000000..83a616680 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/OnboardingFeaturesTest.kt @@ -0,0 +1,53 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui + +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.customannotations.SmokeTest +import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.TestHelper.mDevice +import org.mozilla.fenix.ui.robots.homeScreen + +/** + * Tests for verifying the new onboarding features. + * Note: This involves setting the feature flag On for the onboarding dialog + * + */ +class OnboardingFeaturesTest { + + @get:Rule + val activityTestRule = AndroidComposeTestRule( + HomeActivityTestRule(isHomeOnboardingDialogEnabled = true), + ) { it.activity } + + @SmokeTest + @Test + fun upgradingUsersOnboardingScreensTest() { + homeScreen { + verifyUpgradingUserOnboardingFirstScreen(activityTestRule) + clickGetStartedButton(activityTestRule) + verifyUpgradingUserOnboardingSecondScreen(activityTestRule) + clickSkipButton(activityTestRule) + verifyHomeScreen() + } + } + + @Test + fun upgradingUsersOnboardingSignInButtonTest() { + homeScreen { + verifyUpgradingUserOnboardingFirstScreen(activityTestRule) + clickGetStartedButton(activityTestRule) + verifyUpgradingUserOnboardingSecondScreen(activityTestRule) + }.clickUpgradingUserOnboardingSignInButton(activityTestRule) { + verifyTurnOnSyncMenu() + mDevice.pressBack() + } + homeScreen { + verifyHomeScreen() + } + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/PwaTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/PwaTest.kt index 54d661769..4cf9c8584 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/PwaTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/PwaTest.kt @@ -1,14 +1,11 @@ package org.mozilla.fenix.ui import androidx.core.net.toUri -import org.junit.After -import org.junit.Before import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.Constants.PackageName.GMAIL_APP import org.mozilla.fenix.helpers.Constants.PackageName.PHONE_APP -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestHelper.assertNativeAppOpens import org.mozilla.fenix.ui.robots.customTabScreen @@ -16,8 +13,6 @@ import org.mozilla.fenix.ui.robots.navigationToolbar import org.mozilla.fenix.ui.robots.pwaScreen class PwaTest { - private val featureSettingsHelper = FeatureSettingsHelper() - /* Updated externalLinks.html to v2.0, changed the hypertext reference to mozilla-mobile.github.io/testapp/downloads for "External link" */ @@ -27,18 +22,7 @@ class PwaTest { private val shortcutTitle = "TEST_APP" @get:Rule - val activityTestRule = HomeActivityIntentTestRule() - - @Before - fun setUp() { - featureSettingsHelper.disablePwaCFR(true) - featureSettingsHelper.setTCPCFREnabled(false) - } - - @After - fun tearDown() { - featureSettingsHelper.resetAllFeatureFlags() - } + val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() @SmokeTest @Test diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt index 34a6a9c07..9a8a2b103 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ReaderViewTest.kt @@ -37,7 +37,7 @@ class ReaderViewTest { private val estimatedReadingTime = "1 - 2 minutes" @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() @Rule @JvmField diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index 94928d8a5..28a49e45b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -6,11 +6,10 @@ package org.mozilla.fenix.ui import android.content.Context import android.hardware.camera2.CameraManager -import android.os.Build import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.core.net.toUri import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu -import androidx.test.filters.SdkSuppress +import androidx.test.espresso.Espresso.pressBack import mozilla.components.browser.icons.IconRequest import mozilla.components.browser.icons.generator.DefaultIconGenerator import mozilla.components.feature.search.ext.createSearchEngine @@ -23,16 +22,18 @@ import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.Constants.PackageName.ANDROID_SETTINGS +import org.mozilla.fenix.helpers.Constants.searchEngineCodes import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.SearchDispatcher +import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.helpers.TestHelper.assertNativeAppOpens import org.mozilla.fenix.helpers.TestHelper.denyPermission import org.mozilla.fenix.helpers.TestHelper.exitMenu import org.mozilla.fenix.helpers.TestHelper.grantPermission import org.mozilla.fenix.helpers.TestHelper.longTapSelectItem +import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.setCustomSearchEngine -import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.multipleSelectionToolbar @@ -48,13 +49,19 @@ import org.mozilla.fenix.ui.robots.multipleSelectionToolbar class SearchTest { lateinit var searchMockServer: MockWebServer + lateinit var queryString: String @get:Rule val activityTestRule = AndroidComposeTestRule( - HomeActivityTestRule(), - { it.activity }, - ) - private val featureSettingsHelper = activityTestRule.activityRule.featureSettingsHelper + HomeActivityTestRule( + skipOnboarding = true, + isPocketEnabled = false, + isJumpBackInCFREnabled = false, + isRecentTabsFeatureEnabled = false, + isTCPCFREnabled = false, + isWallpaperOnboardingEnabled = false, + ), + ) { it.activity } @Before fun setUp() { @@ -62,10 +69,6 @@ class SearchTest { dispatcher = SearchDispatcher() start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setPocketEnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) } @After @@ -84,7 +87,6 @@ class SearchTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun scanButtonDenyPermissionTest() { @@ -106,7 +108,6 @@ class SearchTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun scanButtonAllowPermissionTest() { @@ -122,64 +123,50 @@ class SearchTest { } @Test - fun shortcutButtonTest() { - val searchEngineURL = "bing.com/search?q=mozilla%20firefox" + fun setDefaultSearchEngineFromShortcutsTest() { + queryString = "firefox" homeScreen { }.openThreeDotMenu { }.openSettings { }.openSearchSubMenu { - enableShowSearchShortcuts() + toggleShowSearchShortcuts() }.goBack { }.goBack { }.openSearch { - verifySearchBarEmpty() - clickSearchEngineButton(activityTestRule, "Bing") - typeSearch("mozilla") - verifySearchEngineResults(activityTestRule, "mozilla firefox", "Bing") - clickSearchEngineResult(activityTestRule, "mozilla firefox") + scrollToSearchEngineSettings(activityTestRule) + }.clickSearchEngineSettings(activityTestRule) { + changeDefaultSearchEngine("DuckDuckGo") } - browserScreen { - waitForPageToLoad() - verifyUrl(searchEngineURL) - } - } + exitMenu() - @Test - fun shortcutSearchEngineSettingsTest() { homeScreen { - }.openThreeDotMenu { - }.openSettings { - }.openSearchSubMenu { - enableShowSearchShortcuts() - }.goBack { - }.goBack { }.openSearch { - scrollToSearchEngineSettings(activityTestRule) - clickSearchEngineSettings(activityTestRule) - verifySearchSettings() + }.submitQuery(queryString) { + verifyUrl("duckduckgo.com/?q=firefox") } } @Test fun clearSearchTest() { + queryString = "test" + homeScreen { }.openSearch { - typeSearch("test") + typeSearch(queryString) clickClearButton() verifySearchBarEmpty() } } - @Ignore("Failure caused by bugs: https://github.com/mozilla-mobile/fenix/issues/23818") @SmokeTest @Test fun searchGroupShowsInRecentlyVisitedTest() { - val firstPage = searchMockServer.url("generic1.html").toString() - val secondPage = searchMockServer.url("generic2.html").toString() + queryString = "test search" // setting our custom mockWebServer search URL - val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" val customSearchEngine = createSearchEngine( name = "TestSearchEngine", url = searchString, @@ -190,31 +177,81 @@ class SearchTest { // Performs a search and opens 2 dummy search results links to create a search group homeScreen { }.openSearch { - }.submitQuery("test search") { - longClickMatchingText("Link 1") + }.submitQuery(queryString) { + longClickLink("Link 1") clickContextOpenLinkInNewTab() - longClickMatchingText("Link 2") + snackBarButtonClick() + waitForPageToLoad() + pressBack() + longClickLink("Link 2") clickContextOpenLinkInNewTab() - }.goToHomescreen { - verifyJumpBackInSectionIsDisplayed() - verifyCurrentSearchGroupIsDisplayed(true, "test search", 3) - verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 3) - }.openTabDrawer { - }.openTabFromGroup(firstPage) { + snackBarButtonClick() + waitForPageToLoad() }.openTabDrawer { - }.openTabFromGroup(secondPage) { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + } + } + + @Test + fun verifySearchGroupHistoryWithNoDuplicatesTest() { + val firstPageUrl = getGenericAsset(searchMockServer, 1).url + val secondPageUrl = getGenericAsset(searchMockServer, 2).url + val originPageUrl = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search=test%20search".toUri() + queryString = "test search" + // setting our custom mockWebServer search URL + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap, + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + pressBack() + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + pressBack() + longClickLink("Link 2") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + pressBack() + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() }.openTabDrawer { }.openTabsListThreeDotMenu { }.closeAllTabs { - verifyRecentlyVisitedSearchGroupDisplayed(true, "test search", 3) + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + verifyTestPageUrl(firstPageUrl) + verifyTestPageUrl(secondPageUrl) + verifyTestPageUrl(originPageUrl) } } - @SmokeTest + @Ignore("Failing due to known bug, see https://github.com/mozilla-mobile/fenix/issues/23818") @Test - fun noCurrentSearchGroupFromPrivateBrowsingTest() { + fun searchGroupGeneratedInTheSameTabTest() { + queryString = "test search" // setting our custom mockWebServer search URL - val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" val customSearchEngine = createSearchEngine( name = "TestSearchEngine", url = searchString, @@ -225,27 +262,26 @@ class SearchTest { // Performs a search and opens 2 dummy search results links to create a search group homeScreen { }.openSearch { - }.submitQuery("test search") { - longClickMatchingText("Link 1") - clickContextOpenLinkInPrivateTab() - longClickMatchingText("Link 2") - clickContextOpenLinkInPrivateTab() - }.goToHomescreen { - verifyCurrentSearchGroupIsDisplayed(false, "test search", 3) - }.openThreeDotMenu { - }.openHistory { - verifyHistoryItemExists(false, "3 sites") + }.submitQuery(queryString) { + clickLinkMatchingText("Link 1") + waitForPageToLoad() + pressBack() + clickLinkMatchingText("Link 2") + waitForPageToLoad() + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) } } @SmokeTest @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") - fun noRecentlyVisitedSearchGroupInPrivateBrowsingTest() { - val firstPage = searchMockServer.url("generic1.html").toString() - val secondPage = searchMockServer.url("generic2.html").toString() + fun noSearchGroupFromPrivateBrowsingTest() { + queryString = "test search" // setting our custom mockWebServer search URL - val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" val customSearchEngine = createSearchEngine( name = "TestSearchEngine", url = searchString, @@ -255,35 +291,37 @@ class SearchTest { // Performs a search and opens 2 dummy search results links to create a search group homeScreen { - }.togglePrivateBrowsingMode() - homeScreen { }.openSearch { - }.submitQuery("test search") { - longClickMatchingText("Link 1") + }.submitQuery(queryString) { + longClickLink("Link 1") clickContextOpenLinkInPrivateTab() - longClickMatchingText("Link 2") + longClickLink("Link 2") clickContextOpenLinkInPrivateTab() }.openTabDrawer { - }.openTab(firstPage) { + }.toggleToPrivateTabs { + }.openTabWithIndex(0) { }.openTabDrawer { - }.openTab(secondPage) { + }.openTabWithIndex(1) { }.openTabDrawer { }.openTabsListThreeDotMenu { }.closeAllTabs { - homeScreen { - }.togglePrivateBrowsingMode() - verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 3) + togglePrivateBrowsingModeOnOff() + verifyRecentlyVisitedSearchGroupDisplayed(false, queryString, 3) + }.openThreeDotMenu { + }.openHistory { + verifyHistoryItemExists(false, "3 sites") } } - @Ignore("Failure caused by bugs: https://github.com/mozilla-mobile/fenix/issues/23818") @SmokeTest @Test - fun deleteItemsFromSearchGroupsHistoryTest() { - val firstPage = searchMockServer.url("generic1.html").toString() - val secondPage = searchMockServer.url("generic2.html").toString() + fun deleteItemsFromSearchGroupHistoryTest() { + queryString = "test search" + val firstPageUrl = getGenericAsset(searchMockServer, 1).url + val secondPageUrl = getGenericAsset(searchMockServer, 2).url // setting our custom mockWebServer search URL - val searchString = "http://localhost:${searchMockServer.port}/searchResults.html?search={searchTerms}" + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" val customSearchEngine = createSearchEngine( name = "TestSearchEngine", url = searchString, @@ -294,22 +332,23 @@ class SearchTest { // Performs a search and opens 2 dummy search results links to create a search group homeScreen { }.openSearch { - }.submitQuery("test search") { - longClickMatchingText("Link 1") + }.submitQuery(queryString) { + longClickLink("Link 1") clickContextOpenLinkInNewTab() - longClickMatchingText("Link 2") + snackBarButtonClick() + waitForPageToLoad() + mDevice.pressBack() + longClickLink("Link 2") clickContextOpenLinkInNewTab() - }.openTabDrawer { - }.openTabFromGroup(firstPage) { - }.openTabDrawer { - }.openTabFromGroup(secondPage) { + snackBarButtonClick() + waitForPageToLoad() }.openTabDrawer { }.openTabsListThreeDotMenu { }.closeAllTabs { - verifyRecentlyVisitedSearchGroupDisplayed(true, "test search", 3) - }.openRecentlyVisitedSearchGroupHistoryList("test search") { - clickDeleteHistoryButton(firstPage) - longTapSelectItem(secondPage.toUri()) + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + clickDeleteHistoryButton(firstPageUrl.toString()) + longTapSelectItem(secondPageUrl) multipleSelectionToolbar { openActionBarOverflowOrOptionsMenu(activityTestRule.activity) clickMultiSelectionDelete() @@ -318,7 +357,204 @@ class SearchTest { } homeScreen { // checking that the group is removed when only 1 item is left - verifyRecentlyVisitedSearchGroupDisplayed(false, "test search", 1) + verifyRecentlyVisitedSearchGroupDisplayed(false, queryString, 1) + } + } + + @Test + fun deleteSearchGroupFromHistoryTest() { + queryString = "test search" + val firstPageUrl = getGenericAsset(searchMockServer, 1).url + // setting our custom mockWebServer search URL + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap, + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + mDevice.pressBack() + longClickLink("Link 2") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + clickDeleteAllHistoryButton() + confirmDeleteAllHistory() + verifyDeleteSnackbarText("Group deleted") + verifyHistoryItemExists(false, firstPageUrl.toString()) + }.goBack {} + homeScreen { + verifyRecentlyVisitedSearchGroupDisplayed(false, queryString, 3) + }.openThreeDotMenu { + }.openHistory { + verifySearchGroupDisplayed(false, queryString, 3) + verifyEmptyHistoryView() + } + } + + @Test + fun reopenTabsFromSearchGroupTest() { + val firstPageUrl = getGenericAsset(searchMockServer, 1).url + val secondPageUrl = getGenericAsset(searchMockServer, 2).url + queryString = "test search" + // setting our custom mockWebServer search URL + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap, + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + mDevice.pressBack() + longClickLink("Link 2") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + }.openWebsite(firstPageUrl) { + verifyUrl(firstPageUrl.toString()) + }.goToHomescreen { + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + longTapSelectItem(firstPageUrl) + longTapSelectItem(secondPageUrl) + openActionBarOverflowOrOptionsMenu(activityTestRule.activity) + } + + multipleSelectionToolbar { + }.clickOpenNewTab { + verifyNormalModeSelected() + }.closeTabDrawer {} + openActionBarOverflowOrOptionsMenu(activityTestRule.activity) + multipleSelectionToolbar { + }.clickOpenPrivateTab { + verifyPrivateModeSelected() + } + } + + @Test + fun sharePageFromASearchGroupTest() { + val firstPageUrl = getGenericAsset(searchMockServer, 1).url + queryString = "test search" + // setting our custom mockWebServer search URL + val searchString = + "http://localhost:${searchMockServer.port}/pages/searchResults.html?search={searchTerms}" + val customSearchEngine = createSearchEngine( + name = "TestSearchEngine", + url = searchString, + icon = DefaultIconGenerator().generate(appContext, IconRequest(searchString)).bitmap, + ) + setCustomSearchEngine(customSearchEngine) + + // Performs a search and opens 2 dummy search results links to create a search group + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + longClickLink("Link 1") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + mDevice.pressBack() + longClickLink("Link 2") + clickContextOpenLinkInNewTab() + snackBarButtonClick() + waitForPageToLoad() + }.openTabDrawer { + }.openTabsListThreeDotMenu { + }.closeAllTabs { + verifyRecentlyVisitedSearchGroupDisplayed(true, queryString, 3) + }.openRecentlyVisitedSearchGroupHistoryList(queryString) { + longTapSelectItem(firstPageUrl) + } + + multipleSelectionToolbar { + clickShareHistoryButton() + verifyShareOverlay() + verifyShareTabFavicon() + verifyShareTabTitle() + verifyShareTabUrl() + } + } + + // Default search code for Google-US + @Test + fun defaultSearchCodeGoogleUS() { + queryString = "firefox" + + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + verifyUrl(searchEngineCodes["Google"]!!) + } + } + + // Default search code for Bing-US + @Test + fun defaultSearchCodeBingUS() { + queryString = "firefox" + + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + changeDefaultSearchEngine("Bing") + } + + exitMenu() + + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + verifyUrl(searchEngineCodes["Bing"]!!) + } + } + + // Default search code for DuckDuckGo-US + @Test + fun defaultSearchCodeDuckDuckGoUS() { + queryString = "firefox" + + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + changeDefaultSearchEngine("DuckDuckGo") + } + + exitMenu() + + homeScreen { + }.openSearch { + }.submitQuery(queryString) { + verifyUrl(searchEngineCodes["DuckDuckGo"]!!) } } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt index 11e141c99..417d54bd3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAboutTest.kt @@ -10,11 +10,9 @@ import androidx.test.uiautomator.UiSelector import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestHelper.mDevice @@ -31,7 +29,6 @@ class SettingsAboutTest { private lateinit var mDevice: UiDevice private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule val activityIntentTestRule = HomeActivityIntentTestRule() @@ -52,7 +49,6 @@ class SettingsAboutTest { @After fun tearDown() { mockWebServer.shutdown() - featureSettingsHelper.resetAllFeatureFlags() } // Walks through settings menu and sub-menus to ensure all items are present @@ -72,7 +68,9 @@ class SettingsAboutTest { // ABOUT @Test fun verifyRateOnGooglePlayRedirect() { - featureSettingsHelper.setTCPCFREnabled(false) + activityIntentTestRule.applySettingsExceptions { + it.isTCPCFREnabled = false + } homeScreen { }.openThreeDotMenu { @@ -85,10 +83,12 @@ class SettingsAboutTest { } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/25355") @Test fun verifyAboutFirefoxPreview() { - featureSettingsHelper.setJumpBackCFREnabled(false) + activityIntentTestRule.applySettingsExceptions { + it.isJumpBackInCFREnabled = false + it.isTCPCFREnabled = false + } homeScreen { }.openThreeDotMenu { }.openSettings { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt index c621a15c6..eac48d3b3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAddonsTest.kt @@ -14,7 +14,6 @@ import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper.getEnhancedTrackingProtectionAsset @@ -31,10 +30,9 @@ import org.mozilla.fenix.ui.robots.navigationToolbar */ class SettingsAddonsTest { private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityTestRule = HomeActivityIntentTestRule() + val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() @Before fun setUp() { @@ -42,15 +40,11 @@ class SettingsAddonsTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setTCPCFREnabled(false) } @After fun tearDown() { mockWebServer.shutdown() - - featureSettingsHelper.resetAllFeatureFlags() } // Walks through settings add-ons menu to ensure all items are present diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt index 5cbefd2ef..65c3dbea7 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsAdvancedTest.kt @@ -13,7 +13,6 @@ import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper @@ -30,10 +29,12 @@ class SettingsAdvancedTest { private lateinit var mDevice: UiDevice private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule( + isPocketEnabled = false, + isTCPCFREnabled = false, + ) @Before fun setUp() { @@ -42,15 +43,11 @@ class SettingsAdvancedTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setPocketEnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) } @After fun tearDown() { mockWebServer.shutdown() - - featureSettingsHelper.resetAllFeatureFlags() } // Walks through settings menu and sub-menus to ensure all items are present diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index 813dda636..24a6fc292 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -15,7 +15,6 @@ import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper @@ -23,8 +22,8 @@ import org.mozilla.fenix.helpers.TestAssetHelper.getLoremIpsumAsset import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.mDevice -import org.mozilla.fenix.helpers.TestHelper.runWithSystemLocaleChanged import org.mozilla.fenix.helpers.TestHelper.registerAndCleanupIdlingResources +import org.mozilla.fenix.helpers.TestHelper.runWithSystemLocaleChanged import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_CREDIT_CARD_NUMBER import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_EXPIRATION_MONTH import org.mozilla.fenix.ui.SettingsBasicsTest.CreditCard.MOCK_EXPIRATION_YEAR @@ -47,7 +46,6 @@ import java.util.Locale class SettingsBasicsTest { /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() object CreditCard { const val MOCK_CREDIT_CARD_NUMBER = "5555555555554444" @@ -58,7 +56,7 @@ class SettingsBasicsTest { } @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule() + val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides() @Before fun setUp() { @@ -66,18 +64,11 @@ class SettingsBasicsTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) } @After fun tearDown() { mockWebServer.shutdown() - - // resetting modified features enabled setting to default - featureSettingsHelper.resetAllFeatureFlags() } private fun getUiTheme(): Boolean { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt index 40dc48854..b9d978c6b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsDeveloperToolsTest.kt @@ -7,10 +7,10 @@ package org.mozilla.fenix.ui import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer -import org.junit.Rule -import org.junit.Before import org.junit.After +import org.junit.Before import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt index 0a72cd874..42ee74c5f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt @@ -12,7 +12,6 @@ import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset @@ -27,10 +26,9 @@ import org.mozilla.fenix.ui.robots.navigationToolbar */ class SettingsHomepageTest { private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule(skipOnboarding = true) + val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true) @Rule @JvmField @@ -42,17 +40,83 @@ class SettingsHomepageTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) } @After fun tearDown() { mockWebServer.shutdown() + } + + @Test + fun verifyHomepageSettingsTest() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openHomepageSubMenu { + verifyHomePageView() + } + } + + @Test + fun verifyShortcutOptionTest() { + // en-US defaults + val defaultTopSites = arrayOf( + "Top Articles", + "Wikipedia", + "Google", + ) - // resetting modified features enabled setting to default - featureSettingsHelper.resetAllFeatureFlags() + homeScreen { + defaultTopSites.forEach { item -> + verifyExistingTopSitesTabs(item) + } + }.openThreeDotMenu { + }.openCustomizeHome { + clickShortcutsButton() + }.goBack { + defaultTopSites.forEach { item -> + verifyNotExistingTopSitesList(item) + } + } + } + + @Test + fun verifyRecentlyVisitedOptionTest() { + activityIntentTestRule.applySettingsExceptions { + it.isRecentTabsFeatureEnabled = false + } + val genericURL = getGenericAsset(mockWebServer, 1) + + navigationToolbar { + }.enterURLAndEnterToBrowser(genericURL.url) { + }.goToHomescreen { + verifyRecentlyVisitedSectionIsDisplayed() + }.openThreeDotMenu { + }.openCustomizeHome { + clickRecentlyVisited() + }.goBack { + verifyRecentlyVisitedSectionIsNotDisplayed() + } + } + + @Test + fun verifyPocketOptionTest() { + activityIntentTestRule.applySettingsExceptions { + it.isRecentTabsFeatureEnabled = false + it.isRecentlyVisitedFeatureEnabled = false + } + val genericURL = getGenericAsset(mockWebServer, 1) + + navigationToolbar { + }.enterURLAndEnterToBrowser(genericURL.url) { + }.goToHomescreen { + verifyPocketSectionIsDisplayed() + }.openThreeDotMenu { + }.openCustomizeHome { + clickPocketButton() + }.goBack { + verifyPocketSectionIsNotDisplayed() + } } @SmokeTest diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt index bc22684f8..4e3e897be 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt @@ -13,13 +13,11 @@ import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.getStorageTestAsset @@ -48,10 +46,9 @@ class SettingsPrivacyTest { private lateinit var mDevice: UiDevice private lateinit var mockWebServer: MockWebServer private val pageShortcutName = generateRandomString(5) - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityTestRule = HomeActivityIntentTestRule(skipOnboarding = true) + val activityTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true) @Before fun setUp() { @@ -61,11 +58,6 @@ class SettingsPrivacyTest { start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) - featureSettingsHelper.disablePwaCFR(true) - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { val autofillManager: AutofillManager = appContext.getSystemService(AutofillManager::class.java) @@ -76,7 +68,6 @@ class SettingsPrivacyTest { @After fun tearDown() { mockWebServer.shutdown() - featureSettingsHelper.resetAllFeatureFlags() } // Walks through settings privacy menu and sub-menus to ensure all items are present @@ -358,7 +349,6 @@ class SettingsPrivacyTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun launchPageShortcutInPrivateModeTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -389,7 +379,6 @@ class SettingsPrivacyTest { } } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun launchLinksInPrivateToggleOffStateDoesntChangeTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -624,9 +613,13 @@ class SettingsPrivacyTest { @SmokeTest @Test fun deleteCookiesTest() { + val genericPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) val cookiesTestPage = getStorageTestAsset(mockWebServer, "storage_write.html").url + // Browsing a generic page to allow GV to load on a fresh run navigationToolbar { + }.enterURLAndEnterToBrowser(genericPage.url) { + }.openNavigationToolbar { }.enterURLAndEnterToBrowser(cookiesTestPage) { verifyPageContent("No cookies set") clickSetCookiesButton() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt index bfc1b71ed..bedae77e2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt @@ -7,24 +7,28 @@ import org.junit.Before import org.junit.Ignore import org.junit.Rule import org.junit.Test +import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule +import org.mozilla.fenix.helpers.RecyclerViewIdlingResource import org.mozilla.fenix.helpers.SearchDispatcher import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset +import org.mozilla.fenix.helpers.TestHelper +import org.mozilla.fenix.helpers.TestHelper.appContext import org.mozilla.fenix.helpers.TestHelper.exitMenu +import org.mozilla.fenix.helpers.TestHelper.setTextToClipBoard import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar +import org.mozilla.fenix.ui.util.ARABIC_LANGUAGE_HEADER class SettingsSearchTest { private lateinit var mockWebServer: MockWebServer private lateinit var searchMockServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule val activityTestRule = AndroidComposeTestRule( - HomeActivityIntentTestRule(), + HomeActivityIntentTestRule.withDefaultSettingsOverrides(), ) { it.activity } @Before @@ -33,17 +37,11 @@ class SettingsSearchTest { dispatcher = AndroidAssetDispatcher() start() } - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) - featureSettingsHelper.setTCPCFREnabled(false) } @After fun tearDown() { mockWebServer.shutdown() - - // resetting modified features enabled setting to default - featureSettingsHelper.resetAllFeatureFlags() } @Test @@ -55,6 +53,11 @@ class SettingsSearchTest { verifySearchToolbar() verifyDefaultSearchEngineHeader() verifySearchEngineList() + verifyShowSearchSuggestions() + verifyShowSearchShortcuts() + verifySearchBrowsingHistory() + verifySearchBookmarks() + verifyShowClipboardSuggestionsDefault() } } @@ -73,7 +76,27 @@ class SettingsSearchTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") + fun toggleSearchAutocomplete() { + homeScreen { + }.openSearch { + typeSearch("mo") + verifyTypedToolbarText("monster.com") + typeSearch("moz") + verifyTypedToolbarText("mozilla.org") + }.dismissSearchBar { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + toggleAutocomplete() + }.goBack { + }.goBack { + }.openSearch { + typeSearch("moz") + verifyTypedToolbarText("moz") + } + } + + @Test fun toggleSearchBookmarksAndHistoryTest() { // Bookmarks 2 websites, toggles the bookmarks and history search settings off, // then verifies if the websites do not show in the suggestions. @@ -101,8 +124,9 @@ class SettingsSearchTest { }.openSearch { typeSearch("test") expandSearchSuggestionsList() - verifySearchEngineSuggestionResults(activityTestRule, "Test_Page_1") - verifySearchEngineSuggestionResults(activityTestRule, "Test_Page_2") + verifyFirefoxSuggestResults(activityTestRule, "Firefox Suggest") + verifyFirefoxSuggestResults(activityTestRule, "Test_Page_1") + verifyFirefoxSuggestResults(activityTestRule, "Test_Page_2") }.dismissSearchBar { }.openThreeDotMenu { }.openSettings { @@ -118,6 +142,7 @@ class SettingsSearchTest { }.openSearch { typeSearch("test") expandSearchSuggestionsList() + verifyNoSuggestionsAreDisplayed(activityTestRule, "Firefox Suggest") verifyNoSuggestionsAreDisplayed(activityTestRule, "Test_Page_1") verifyNoSuggestionsAreDisplayed(activityTestRule, "Test_Page_2") } @@ -200,7 +225,48 @@ class SettingsSearchTest { }.openThreeDotMenu { }.openSettings { }.openSearchSubMenu { - disableShowSearchSuggestions() + toggleShowSearchSuggestions() + }.goBack { + }.goBack { + }.openSearch { + typeSearch("mozilla") + verifyNoSuggestionsAreDisplayed(activityTestRule, "mozilla firefox") + } + } + + // Tests the "Don't allow" option from private mode search suggestions onboarding dialog + @Test + fun blockSearchSuggestionsInPrivateModeOnboardingTest() { + homeScreen { + togglePrivateBrowsingModeOnOff() + }.openSearch { + typeSearch("mozilla") + verifyAllowSuggestionsInPrivateModeDialog() + denySuggestionsInPrivateMode() + verifyNoSuggestionsAreDisplayed(activityTestRule, "mozilla firefox") + }.dismissSearchBar { + togglePrivateBrowsingModeOnOff() + }.openSearch { + typeSearch("mozilla") + verifySearchEngineSuggestionResults(activityTestRule, "mozilla firefox") + } + } + + // Tests the "Allow" option from private mode search suggestions onboarding dialog + @Test + fun allowSearchSuggestionsInPrivateModeOnboardingTest() { + homeScreen { + togglePrivateBrowsingModeOnOff() + }.openSearch { + typeSearch("mozilla") + verifyAllowSuggestionsInPrivateModeDialog() + allowSuggestionsInPrivateMode() + verifySearchEngineSuggestionResults(activityTestRule, "mozilla firefox") + }.dismissSearchBar { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + toggleShowSuggestionsInPrivateSessions() }.goBack { }.goBack { }.openSearch { @@ -228,4 +294,194 @@ class SettingsSearchTest { verifyVoiceSearchButtonVisibility(false) } } + + @Test + fun toggleShowClipboardSuggestionsTest() { + val link = "https://www.mozilla.org/en-US/" + setTextToClipBoard(appContext, link) + + homeScreen { + }.openNavigationToolbar { + verifyClipboardSuggestionsAreDisplayed(link, true) + }.visitLinkFromClipboard { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + verifyShowClipboardSuggestionsDefault() + toggleClipboardSuggestion() + exitMenu() + } + homeScreen { + }.openNavigationToolbar { + verifyClipboardSuggestionsAreDisplayed(link, false) + } + } + + // Expected for en-us defaults + @Test + fun undoDeleteSearchEngineTest() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + verifyEngineListContains("Bing") + openEngineOverflowMenu("Bing") + clickDeleteSearchEngine() + clickUndoSnackBarButton() + verifyEngineListContains("Bing") + } + } + + // Expected for en-us defaults + @Test + fun deleteDefaultSearchEngineTest() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + verifyEngineListContains("Google") + verifyDefaultSearchEngine("Google") + openEngineOverflowMenu("Google") + clickDeleteSearchEngine() + verifyEngineListDoesNotContain("Google") + verifyDefaultSearchEngine("Bing") + } + } + + // Expected for en-us defaults + @Test + fun deleteAllSearchEnginesTest() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + deleteMultipleSearchEngines( + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + ) + verifyDefaultSearchEngine("Wikipedia") + verifyThreeDotButtonIsNotDisplayed("Wikipedia") + openAddSearchEngineMenu() + verifyAddSearchEngineListContains( + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + ) + } + } + + // Expected for en-us defaults + @Test + fun changeSearchEnginesBasedOnTextTest() { + homeScreen { + }.openSearch { + typeSearch("D") + verifySearchEnginePrompt(activityTestRule, "DuckDuckGo") + clickSearchEnginePrompt(activityTestRule, "DuckDuckGo") + }.submitQuery("firefox") { + verifyUrl("duckduckgo.com/?q=firefox") + } + } + + // Expected for app language set to Arabic + @Test + fun verifySearchEnginesWithRTLLocale() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + toggleShowSearchShortcuts() + }.goBack { + }.openLanguageSubMenu { + TestHelper.registerAndCleanupIdlingResources( + RecyclerViewIdlingResource( + activityTestRule.activity.findViewById(R.id.locale_list), + 2, + ), + ) { + selectLanguage("Arabic") + verifyLanguageHeaderIsTranslated(ARABIC_LANGUAGE_HEADER) + } + } + + exitMenu() + + homeScreen { + }.openSearch { + verifyTranslatedFocusedNavigationToolbar("ابحث أو أدخِل عنوانا") + verifySearchEngineShortcuts( + activityTestRule, + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + /* Disabled Arabic Wikipedia verification + until https://github.com/mozilla-mobile/fenix/issues/12236 gets fixed + "ويكيبيديا (ar)" + */ + ) + } + } + + // Expected for en-us defaults + @Test + fun toggleSearchEnginesShortcutListTest() { + homeScreen { + }.openThreeDotMenu { + }.openSettings { + }.openSearchSubMenu { + verifyShowSearchEnginesToggleState(false) + toggleShowSearchShortcuts() + verifyShowSearchEnginesToggleState(true) + } + + exitMenu() + + homeScreen { + }.openSearch { + verifySearchEngineShortcuts( + activityTestRule, + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + "Wikipedia", + ) + }.clickSearchEngineSettings(activityTestRule) { + toggleShowSearchShortcuts() + verifyShowSearchEnginesToggleState(false) + } + + exitMenu() + + homeScreen { + }.openSearch { + verifySearchEngineShortcutsAreNotDisplayed( + activityTestRule, + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + "Wikipedia", + ) + clickSearchEngineShortcutButton() + verifySearchEngineShortcuts( + activityTestRule, + "Google", + "Bing", + "Amazon.com", + "DuckDuckGo", + "eBay", + "Wikipedia", + ) + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt index 24eb93c80..bc479ea60 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSyncTest.kt @@ -7,10 +7,10 @@ package org.mozilla.fenix.ui import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer -import org.junit.Rule -import org.junit.Before import org.junit.After +import org.junit.Before import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt index bf2b1224f..facbc22ca 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsTest.kt @@ -7,10 +7,10 @@ package org.mozilla.fenix.ui import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer -import org.junit.Rule -import org.junit.Before import org.junit.After +import org.junit.Before import org.junit.Ignore +import org.junit.Rule import org.junit.Test import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt index 29f8f5e3f..03af517c3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SitePermissionsTest.kt @@ -13,7 +13,6 @@ import androidx.core.net.toUri import androidx.test.filters.SdkSuppress import androidx.test.rule.GrantPermissionRule import org.junit.Assume.assumeTrue -import org.junit.Before import org.junit.Rule import org.junit.Test import org.mozilla.fenix.customannotations.SmokeTest @@ -36,8 +35,12 @@ class SitePermissionsTest { private val micManager = appContext.getSystemService(Context.AUDIO_SERVICE) as AudioManager @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule( + isJumpBackInCFREnabled = false, + isPWAsPromptEnabled = false, + isTCPCFREnabled = false, + isDeleteSitePermissionsEnabled = true, + ) @get:Rule val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant( @@ -52,15 +55,6 @@ class SitePermissionsTest { @get: Rule val retryTestRule = RetryTestRule(3) - @Before - fun setUp() { - // disabling the new homepage pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.deleteSitePermissions(true) - featureSettingsHelper.disablePwaCFR(true) - } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test @@ -80,7 +74,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun rememberBlockAudioVideoPermissionChoiceTest() { @@ -104,7 +97,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @SmokeTest @Test fun rememberAllowAudioVideoPermissionChoiceTest() { @@ -128,7 +120,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun microphonePermissionChoiceOnEachRequestTest() { assumeTrue(micManager.microphones.isNotEmpty()) @@ -146,7 +137,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun rememberBlockMicrophonePermissionChoiceTest() { assumeTrue(micManager.microphones.isNotEmpty()) @@ -168,7 +158,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun rememberAllowMicrophonePermissionChoiceTest() { assumeTrue(micManager.microphones.isNotEmpty()) @@ -190,7 +179,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun cameraPermissionChoiceOnEachRequestTest() { assumeTrue(cameraManager.cameraIdList.isNotEmpty()) @@ -208,7 +196,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun rememberBlockCameraPermissionChoiceTest() { assumeTrue(cameraManager.cameraIdList.isNotEmpty()) @@ -230,7 +217,6 @@ class SitePermissionsTest { } } - @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.P, codeName = "P") @Test fun rememberAllowCameraPermissionChoiceTest() { assumeTrue(cameraManager.cameraIdList.isNotEmpty()) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index f59674e43..d0a85e27a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -25,8 +25,8 @@ import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.Constants -import org.mozilla.fenix.helpers.FeatureSettingsHelper +import org.mozilla.fenix.helpers.Constants.PackageName.YOUTUBE_APP +import org.mozilla.fenix.helpers.FeatureSettingsHelperDelegate import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource import org.mozilla.fenix.helpers.RetryTestRule @@ -36,12 +36,11 @@ import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.TestHelper.assertNativeAppOpens import org.mozilla.fenix.helpers.TestHelper.createCustomTabIntent import org.mozilla.fenix.helpers.TestHelper.generateRandomString -import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.TestHelper.registerAndCleanupIdlingResources +import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.customTabScreen -import org.mozilla.fenix.ui.robots.enhancedTrackingProtection import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar import org.mozilla.fenix.ui.robots.notificationShade @@ -62,22 +61,22 @@ class SmokeTest { private lateinit var mockWebServer: MockWebServer private val customMenuItem = "TestMenuItem" private lateinit var browserStore: BrowserStore - private val featureSettingsHelper = FeatureSettingsHelper() + private val featureSettingsHelper = FeatureSettingsHelperDelegate() - @get:Rule + @get:Rule(order = 0) val activityTestRule = AndroidComposeTestRule( HomeActivityIntentTestRule(), { it.activity }, ) - @get: Rule + @get: Rule(order = 1) val intentReceiverActivityTestRule = ActivityTestRule( IntentReceiverActivity::class.java, true, false, ) - @Rule + @Rule(order = 2) @JvmField val retryTestRule = RetryTestRule(3) @@ -88,9 +87,11 @@ class SmokeTest { browserStore = activityTestRule.activity.components.core.store // disabling the new homepage pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) + featureSettingsHelper.apply { + isJumpBackInCFREnabled = false + isTCPCFREnabled = false + isWallpaperOnboardingEnabled = false + }.applyFlagUpdates() mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { @@ -159,7 +160,6 @@ class SmokeTest { } } - @Test /* Verifies the nav bar: - opening a web page - the existence of nav bar items @@ -167,7 +167,7 @@ class SmokeTest { - the tab drawer button - opening a new search and dismissing the nav bar */ - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") + @Test fun verifyBasicNavigationToolbarFunctionality() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -188,13 +188,13 @@ class SmokeTest { } // Verifies the list of items in a tab's 3 dot menu - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/26711") @Test fun verifyPageMainMenuItemsTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) navigationToolbar { }.enterURLAndEnterToBrowser(defaultWebPage.url) { + waitForPageToLoad() }.openThreeDotMenu { verifyPageThreeDotMainMenuItems() } @@ -345,17 +345,16 @@ class SmokeTest { // Device or AVD requires a Google Services Android OS installation with Play Store installed // Verifies the Open in app button when an app is installed - @Ignore("Failing with frequent ANR: https://github.com/mozilla-mobile/fenix/issues/25926") @Test fun mainMenuOpenInAppTest() { - val playStoreUrl = "play.google.com/store/apps/details?id=org.mozilla.fenix" + val youtubeURL = "https://m.youtube.com/user/mozilla?cbrd=1" navigationToolbar { - }.enterURLAndEnterToBrowser(playStoreUrl.toUri()) { + }.enterURLAndEnterToBrowser(youtubeURL.toUri()) { verifyNotificationDotOnMainMenu() }.openThreeDotMenu { }.clickOpenInApp { - assertNativeAppOpens(Constants.PackageName.GOOGLE_PLAY_SERVICES, playStoreUrl) + assertNativeAppOpens(YOUTUBE_APP, youtubeURL) } } @@ -403,38 +402,6 @@ class SmokeTest { } } - @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/25345") - @Test - fun customTrackingProtectionSettingsTest() { - val genericWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) - val trackingPage = TestAssetHelper.getEnhancedTrackingProtectionAsset(mockWebServer) - - homeScreen { - }.openThreeDotMenu { - }.openSettings { - }.openEnhancedTrackingProtectionSubMenu { - verifyEnhancedTrackingProtectionOptionsEnabled() - selectTrackingProtectionOption("Custom") - verifyCustomTrackingProtectionSettings() - }.goBackToHomeScreen {} - - navigationToolbar { - // browsing a basic page to allow GV to load on a fresh run - }.enterURLAndEnterToBrowser(genericWebPage.url) { - }.openNavigationToolbar { - }.enterURLAndEnterToBrowser(trackingPage.url) {} - - enhancedTrackingProtection { - }.openEnhancedTrackingProtectionSheet { - }.openDetails { - verifyTrackingCookiesBlocked() - verifyCryptominersBlocked() - verifyFingerprintersBlocked() - verifyTrackingContentBlocked() - viewTrackingContentBlockList() - } - } - // Verifies changing the default engine from the Search Shortcut menu @Test fun selectSearchEnginesShortcutTest() { @@ -504,9 +471,8 @@ class SmokeTest { } } - @Test // Verifies that a recently closed item is properly opened - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") + @Test fun openRecentlyClosedItemTest() { val website = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -529,9 +495,8 @@ class SmokeTest { } } - @Test // Verifies that tapping the "x" button removes a recently closed item from the list - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") + @Test fun deleteRecentlyClosedTabsItemTest() { val website = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -678,7 +643,6 @@ class SmokeTest { // caution when making changes to it, so they don't block the builds @Test fun noHistoryInPrivateBrowsingTest() { - FeatureSettingsHelper().setTCPCFREnabled(false) val website = TestAssetHelper.getGenericAsset(mockWebServer, 1) homeScreen { @@ -816,7 +780,6 @@ class SmokeTest { } } - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun audioPlaybackSystemNotificationTest() { val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) @@ -884,7 +847,6 @@ class SmokeTest { mDevice.pressBack() } - @Ignore("Failing: https://github.com/mozilla-mobile/fenix/issues/26884") @Test fun copyTextTest() { val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -900,11 +862,10 @@ class SmokeTest { clickClearButton() longClickToolbar() clickPasteText() - verifyPastedToolbarText("content") + verifyTypedToolbarText("content") } } - @Ignore("Failing: https://github.com/mozilla-mobile/fenix/issues/26884") @Test fun selectAllAndCopyTextTest() { val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -920,7 +881,8 @@ class SmokeTest { clickClearButton() longClickToolbar() clickPasteText() - verifyPastedToolbarText("Page content: 1") + // with Select all, some white space is copied over, so we need to include that too + verifyTypedToolbarText(" Page content: 1 ") } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index 4748d3b80..1be555141 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -45,8 +45,7 @@ class TabbedBrowsingTest { /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. @get:Rule - val activityTestRule = HomeActivityTestRule() - private val featureSettingsHelper = activityTestRule.featureSettingsHelper + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Rule @JvmField @@ -54,11 +53,6 @@ class TabbedBrowsingTest { @Before fun setUp() { - // disabling the new homepage pop-up that interferes with the tests. - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) - mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() @@ -72,7 +66,6 @@ class TabbedBrowsingTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openNewTabTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -97,7 +90,6 @@ class TabbedBrowsingTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun openNewPrivateTabTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -118,7 +110,6 @@ class TabbedBrowsingTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun closeAllTabsTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) @@ -183,11 +174,12 @@ class TabbedBrowsingTest { } @Test - @Ignore("Failing after compose migration. See: https://github.com/mozilla-mobile/fenix/issues/26087") fun verifyUndoSnackBarTest() { // disabling these features because they interfere with the snackbar visibility - featureSettingsHelper.setPocketEnabled(false) - featureSettingsHelper.setRecentTabsFeatureEnabled(false) + activityTestRule.applySettingsExceptions { + it.isPocketEnabled = false + it.isRecentTabsFeatureEnabled = false + } val genericURL = TestAssetHelper.getGenericAsset(mockWebServer, 1) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt index b1a37eacb..a27ddc7b6 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/ThreeDotMenuMainTest.kt @@ -7,10 +7,8 @@ package org.mozilla.fenix.ui import okhttp3.mockwebserver.MockWebServer import org.junit.After import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test -import org.mozilla.fenix.ext.settings import org.mozilla.fenix.helpers.AndroidAssetDispatcher import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.ui.robots.homeScreen @@ -26,11 +24,10 @@ class ThreeDotMenuMainTest { private lateinit var mockWebServer: MockWebServer @get:Rule - val activityTestRule = HomeActivityTestRule() + val activityTestRule = HomeActivityTestRule.withDefaultSettingsOverrides() @Before fun setUp() { - activityTestRule.activity.applicationContext.settings().shouldShowJumpBackInCFR = false mockWebServer = MockWebServer().apply { dispatcher = AndroidAssetDispatcher() start() @@ -43,7 +40,6 @@ class ThreeDotMenuMainTest { } // Verifies the list of items in the homescreen's 3 dot main menu - @Ignore("Failing with frequent ANR: https://bugzilla.mozilla.org/show_bug.cgi?id=1764605") @Test fun homeThreeDotMenuItemsTest() { homeScreen { @@ -52,7 +48,8 @@ class ThreeDotMenuMainTest { verifyHistoryButton() verifyDownloadsButton() verifyAddOnsButton() - verifySyncSignInButton() + // Disabled step due to https://github.com/mozilla-mobile/fenix/issues/26788 + // verifySyncSignInButton() verifyDesktopSite() verifyWhatsNewButton() verifyHelpButton() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt index 72f80bef9..e0c94db21 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt @@ -14,7 +14,6 @@ import org.junit.Test import org.mozilla.fenix.R import org.mozilla.fenix.customannotations.SmokeTest import org.mozilla.fenix.helpers.AndroidAssetDispatcher -import org.mozilla.fenix.helpers.FeatureSettingsHelper import org.mozilla.fenix.helpers.HomeActivityIntentTestRule import org.mozilla.fenix.helpers.RetryTestRule import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset @@ -36,10 +35,9 @@ import org.mozilla.fenix.ui.robots.navigationToolbar class TopSitesTest { private lateinit var mDevice: UiDevice private lateinit var mockWebServer: MockWebServer - private val featureSettingsHelper = FeatureSettingsHelper() @get:Rule - val activityIntentTestRule = HomeActivityIntentTestRule(skipOnboarding = true) + val activityIntentTestRule = HomeActivityIntentTestRule.withDefaultSettingsOverrides(skipOnboarding = true) @get:Rule val retryTestRule = RetryTestRule(3) @@ -51,16 +49,11 @@ class TopSitesTest { dispatcher = AndroidAssetDispatcher() start() } - - featureSettingsHelper.setJumpBackCFREnabled(false) - featureSettingsHelper.setTCPCFREnabled(false) - featureSettingsHelper.setShowWallpaperOnboarding(false) } @After fun tearDown() { mockWebServer.shutdown() - featureSettingsHelper.resetAllFeatureFlags() } @SmokeTest @@ -225,7 +218,6 @@ class TopSitesTest { navigationToolbar { }.enterURLAndEnterToBrowser(defaultWebPage.url) { waitForPageToLoad() - verifyPageContent(defaultWebPage.content) } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/WebControlsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/WebControlsTest.kt new file mode 100644 index 000000000..fd06ab548 --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/WebControlsTest.kt @@ -0,0 +1,187 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui + +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.helpers.AndroidAssetDispatcher +import org.mozilla.fenix.helpers.Constants +import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.helpers.TestHelper.assertNativeAppOpens +import org.mozilla.fenix.ui.robots.navigationToolbar + +/** + * Tests for verifying basic interactions with web control elements + * + */ + +class WebControlsTest { + private lateinit var mockWebServer: MockWebServer + + private val hour = 10 + private val minute = 10 + private val colorHexValue = "#5b2067" + private val emailLink = "mailto://example@example.com" + private val phoneLink = "tel://1234567890" + + @get:Rule + val activityTestRule = HomeActivityTestRule( + isJumpBackInCFREnabled = false, + isTCPCFREnabled = false, + ) + + @Before + fun setUp() { + mockWebServer = MockWebServer().apply { + dispatcher = AndroidAssetDispatcher() + start() + } + } + + @After + fun tearDown() { + mockWebServer.shutdown() + } + + @Test + fun cancelCalendarFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Calendar Form") + clickFormViewButton("CANCEL") + clickSubmitDateButton() + verifyNoDateIsSelected() + } + } + + @Test + fun setAndClearCalendarFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Calendar Form") + selectDate() + clickFormViewButton("OK") + clickSubmitDateButton() + verifySelectedDate() + clickForm("Calendar Form") + clickFormViewButton("CLEAR") + clickSubmitDateButton() + verifyNoDateIsSelected() + } + } + + @Test + fun cancelClockFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Clock Form") + clickFormViewButton("CANCEL") + clickSubmitTimeButton() + verifyNoTimeIsSelected(hour, minute) + } + } + + @Test + fun setAndClearClockFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Clock Form") + selectTime(hour, minute) + clickFormViewButton("OK") + clickSubmitTimeButton() + verifySelectedTime(hour, minute) + clickForm("Clock Form") + clickFormViewButton("CLEAR") + clickSubmitTimeButton() + verifyNoTimeIsSelected(hour, minute) + } + } + + @Test + fun cancelColorFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Color Form") + selectColor(colorHexValue) + clickFormViewButton("CANCEL") + clickSubmitColorButton() + verifyColorIsNotSelected(colorHexValue) + } + } + + @Test + fun setColorFormTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Color Form") + selectColor(colorHexValue) + clickFormViewButton("SET") + clickSubmitColorButton() + verifySelectedColor(colorHexValue) + } + } + + @Test + fun verifyDropdownMenuTest() { + val htmlControlsPage = TestAssetHelper.getHTMLControlsFormAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(htmlControlsPage.url) { + clickForm("Drop-down Form") + selectDropDownOption("The National") + clickSubmitDropDownButton() + verifySelectedDropDownOption("The National") + } + } + + @Test + fun externalLinkTest() { + val externalLinksPage = TestAssetHelper.getExternalLinksAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(externalLinksPage.url) { + clickLinkMatchingText("External link") + verifyUrl("duckduckgo") + } + } + + @Test + fun emailLinkTest() { + val externalLinksPage = TestAssetHelper.getExternalLinksAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(externalLinksPage.url) { + clickLinkMatchingText("Email link") + assertNativeAppOpens(Constants.PackageName.GMAIL_APP, emailLink) + } + } + + @Test + fun telephoneLinkTest() { + val externalLinksPage = TestAssetHelper.getExternalLinksAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(externalLinksPage.url) { + clickLinkMatchingText("Telephone link") + assertNativeAppOpens(Constants.PackageName.PHONE_APP, phoneLink) + } + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt index 0b4a6d043..27e3b1fb4 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BookmarksRobot.kt @@ -138,8 +138,8 @@ class BookmarksRobot { mDevice.waitNotNull(Until.findObject(By.text(childFolderName)), waitingTime) } - fun verifySignInToSyncButton() = - signInToSyncButton().check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + fun verifySyncSignInButton() = + syncSignInButton().check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) fun verifyDeleteFolderConfirmationMessage() = assertDeleteFolderConfirmationMessage() @@ -150,12 +150,21 @@ class BookmarksRobot { .click() } - fun createFolder(name: String) { + fun createFolder(name: String, parent: String? = null) { clickAddFolderButton() addNewFolderName(name) + if (!parent.isNullOrBlank()) { + setParentFolder(parent) + } saveNewFolder() } + fun setParentFolder(parentName: String) { + clickParentFolderSelector() + selectFolder(parentName) + navigateUp() + } + fun clickAddFolderButton() { mDevice.waitNotNull( Until.findObject(By.desc("Add folder")), @@ -244,7 +253,7 @@ class BookmarksRobot { } fun clickSingInToSyncButton(interact: SettingsTurnOnSyncRobot.() -> Unit): SettingsTurnOnSyncRobot.Transition { - signInToSyncButton().click() + syncSignInButton().click() SettingsTurnOnSyncRobot().interact() return SettingsTurnOnSyncRobot.Transition() @@ -308,7 +317,7 @@ private fun saveBookmarkButton() = onView(withId(R.id.save_bookmark_button)) private fun deleteInEditModeButton() = onView(withId(R.id.delete_bookmark_button)) -private fun signInToSyncButton() = onView(withId(R.id.bookmark_folders_sign_in)) +private fun syncSignInButton() = onView(withId(R.id.bookmark_folders_sign_in)) private fun assertBookmarksView() { onView( diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index 702640fb4..7a5d4341e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -11,15 +11,17 @@ import android.content.Intent import android.net.Uri import android.os.SystemClock import android.util.Log -import android.widget.EditText +import android.widget.TimePicker import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.PickerActions import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.BundleMatchers import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility @@ -27,6 +29,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By import androidx.test.uiautomator.By.text +import androidx.test.uiautomator.UiObject import androidx.test.uiautomator.UiObjectNotFoundException import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until @@ -34,6 +37,7 @@ import mozilla.components.browser.state.selector.selectedTab import mozilla.components.browser.state.store.BrowserStore import mozilla.components.concept.engine.mediasession.MediaSession import org.hamcrest.CoreMatchers.allOf +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Assert.fail import org.mozilla.fenix.R @@ -43,11 +47,13 @@ import org.mozilla.fenix.helpers.Constants.RETRY_COUNT import org.mozilla.fenix.helpers.SessionLoadedIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong +import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.waitForObjects import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull +import java.time.LocalDate class BrowserRobot { private lateinit var sessionLoadedIdlingResource: SessionLoadedIdlingResource @@ -334,134 +340,54 @@ class BrowserRobot { menuSaveImage.click() } - fun createBookmark(url: Uri) { + fun createBookmark(url: Uri, folder: String? = null) { navigationToolbar { }.enterURLAndEnterToBrowser(url) { // needs to wait for the right url to load before saving a bookmark verifyUrl(url.toString()) }.openThreeDotMenu { - }.bookmarkPage { } - } - - fun clickLinkMatchingText(expectedText: String) { - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTimeLong) - - val element = mDevice.findObject(UiSelector().textContains(expectedText)) - element.click() - } - - fun longClickMatchingText(expectedText: String) { - try { - mDevice.waitForWindowUpdate(packageName, waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTime) - val link = mDevice.findObject(By.textContains(expectedText)) - link.click(LONG_CLICK_DURATION) - } catch (e: NullPointerException) { - println(e) - - // Refresh the page in case the first long click didn't succeed - navigationToolbar { - }.openThreeDotMenu { - }.refreshPage { - mDevice.waitForIdle() + }.bookmarkPage { + }.takeIf { !folder.isNullOrBlank() }?.let { + it.openThreeDotMenu { + }.editBookmarkPage { + setParentFolder(folder!!) + saveEditBookmark() } - - // Long click again the desired text - mDevice.waitForWindowUpdate(packageName, waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTime) - val link = mDevice.findObject(By.textContains(expectedText)) - link.click(LONG_CLICK_DURATION) } } - fun longClickAndCopyText(expectedText: String, selectAll: Boolean = false) { - try { - // Long click desired text - mDevice.waitForWindowUpdate(packageName, waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTime) - val link = mDevice.findObject(By.textContains(expectedText)) - link.click(LONG_CLICK_DURATION) - - // Click Select all from the text selection toolbar - if (selectAll) { - mDevice.findObject(UiSelector().textContains("Select all")).waitForExists(waitingTime) - val selectAllText = mDevice.findObject(By.textContains("Select all")) - selectAllText.click() - } + fun clickLinkMatchingText(expectedText: String) = + clickPageObject(webPageItemContainingText(expectedText)) - // Click Copy from the text selection toolbar - mDevice.findObject(UiSelector().textContains("Copy")).waitForExists(waitingTime) - val copyText = mDevice.findObject(By.textContains("Copy")) - copyText.click() - } catch (e: NullPointerException) { - println("Failed to long click desired text: ${e.localizedMessage}") - - // Refresh the page in case the first long click didn't succeed - navigationToolbar { - }.openThreeDotMenu { - }.refreshPage { - mDevice.waitForIdle() - } + fun longClickLink(expectedText: String) = + longClickPageObject(webPageItemWithText(expectedText)) - // Long click again the desired text - mDevice.waitForWindowUpdate(packageName, waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTime) - val link = mDevice.findObject(By.textContains(expectedText)) - link.click(LONG_CLICK_DURATION) - - // Click again Select all from the text selection toolbar - if (selectAll) { - mDevice.findObject(UiSelector().textContains("Select all")).waitForExists(waitingTime) - val selectAllText = mDevice.findObject(By.textContains("Select all")) - selectAllText.click() - } + fun longClickMatchingText(expectedText: String) = + longClickPageObject(webPageItemContainingText(expectedText)) + + fun longClickAndCopyText(expectedText: String, selectAll: Boolean = false) { + longClickPageObject(webPageItemContainingText(expectedText)) - // Click again Copy from the text selection toolbar - mDevice.findObject(UiSelector().textContains("Copy")).waitForExists(waitingTime) - val copyText = mDevice.findObject(By.textContains("Copy")) - copyText.click() + // Click Select all from the text selection toolbar + if (selectAll) { + mDevice.findObject(UiSelector().textContains("Select all")).waitForExists(waitingTime) + val selectAllText = mDevice.findObject(By.textContains("Select all")) + selectAllText.click() } + + // Click Copy from the text selection toolbar + mDevice.findObject(UiSelector().textContains("Copy")).waitForExists(waitingTime) + val copyText = mDevice.findObject(By.textContains("Copy")) + copyText.click() } fun longClickAndSearchText(searchButton: String, expectedText: String) { - var currentTries = 0 - while (currentTries++ < 3) { - try { - // Long click desired text - mDevice.waitForWindowUpdate(packageName, waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)).waitForExists(waitingTime) - val link = mDevice.findObject(By.textContains(expectedText)) - link.click(LONG_CLICK_DURATION) - - // Click search from the text selection toolbar - mDevice.findObject(UiSelector().textContains(searchButton)).waitForExists(waitingTime) - val searchText = mDevice.findObject(By.textContains(searchButton)) - searchText.click() + longClickPageObject(webPageItemContainingText(expectedText)) - break - } catch (e: NullPointerException) { - println("Failed to long click desired text: ${e.localizedMessage}") - - // Refresh the page in case the first long click didn't succeed - navigationToolbar { - }.openThreeDotMenu { - }.refreshPage { - mDevice.waitForIdle() - } - } - } + // Click search from the text selection toolbar + mDevice.findObject(UiSelector().textContains(searchButton)).waitForExists(waitingTime) + val searchText = mDevice.findObject(By.textContains(searchButton)) + searchText.click() } fun snackBarButtonClick() { @@ -474,18 +400,10 @@ class BrowserRobot { switchButton.clickAndWaitForNewWindow(waitingTime) } - fun verifySaveLoginPromptIsShown() { - mDevice.findObject(UiSelector().text("test@example.com")).waitForExists(waitingTime) - val submitButton = mDevice.findObject(By.res("submit")) - submitButton.clickAndWait(Until.newWindow(), waitingTime) - // Click save to save the login - mDevice.waitNotNull(Until.findObjects(text("Save"))) - } + fun verifySaveLoginPromptIsShown() = clickPageObject(webPageItemWithResourceId("submit")) fun verifyUpdateLoginPromptIsShown() { - val submitButton = mDevice.findObject(By.res("submit")) - submitButton.clickAndWait(Until.newWindow(), waitingTime) - + clickPageObject(webPageItemWithResourceId("submit")) mDevice.waitNotNull(Until.findObjects(text("Update"))) } @@ -499,49 +417,13 @@ class BrowserRobot { } fun enterPassword(password: String) { - val passwordField = mDevice.findObject( - UiSelector() - .resourceId("password") - .className(EditText::class.java), - ) - try { - passwordField.waitForExists(waitingTime) - mDevice.findObject( - By - .res("password") - .clazz(EditText::class.java), - ).click() - passwordField.clearTextField() - passwordField.text = password - // wait until the password is hidden - assertTrue(mDevice.findObject(UiSelector().text(password)).waitUntilGone(waitingTime)) - } catch (e: UiObjectNotFoundException) { - println(e) + clickPageObject(webPageItemWithResourceId("password")) + setPageObjectText(webPageItemWithResourceId("password"), password) - // Lets refresh the page and try again - browserScreen { - }.openThreeDotMenu { - }.refreshPage { - mDevice.waitForIdle() - } - } finally { - passwordField.waitForExists(waitingTime) - mDevice.findObject( - By - .res("password") - .clazz(EditText::class.java), - ).click() - passwordField.clearTextField() - passwordField.text = password - // wait until the password is hidden - assertTrue(mDevice.findObject(UiSelector().text(password)).waitUntilGone(waitingTime)) - } + assertTrue(mDevice.findObject(UiSelector().text(password)).waitUntilGone(waitingTime)) } - fun clickMediaPlayerPlayButton() { - mediaPlayerPlayButton().waitForExists(waitingTime) - mediaPlayerPlayButton().click() - } + fun clickMediaPlayerPlayButton() = clickPageObject(webPageItemWithText("Play")) /** * Get the current playback state of the currently selected tab. @@ -605,26 +487,17 @@ class BrowserRobot { } fun fillAndSubmitLoginCredentials(userName: String, password: String) { - var currentTries = 0 - while (currentTries++ < 3) { - try { - mDevice.waitForIdle(waitingTime) - userNameTextBox.setText(userName) - passwordTextBox.setText(password) - submitLoginButton.click() - - mDevice.waitForObjects(mDevice.findObject(UiSelector().resourceId("$packageName:id/save_confirm"))) + mDevice.waitForIdle(waitingTime) + setPageObjectText(webPageItemWithResourceId("username"), userName) + setPageObjectText(webPageItemWithResourceId("password"), password) + clickPageObject(webPageItemWithResourceId("submit")) - break - } catch (e: UiObjectNotFoundException) { - Log.e("BROWSER_ROBOT", "Failed to find locator: ${e.localizedMessage}") - } - } + mDevice.waitForObjects(mDevice.findObject(UiSelector().resourceId("$packageName:id/save_confirm"))) } fun clearUserNameLoginCredential() { - mDevice.waitForObjects(userNameTextBox) - userNameTextBox.clearTextField() + mDevice.waitForObjects(webPageItemWithResourceId("username")) + webPageItemWithResourceId("username").clearTextField() mDevice.waitForIdle(waitingTime) } @@ -637,25 +510,19 @@ class BrowserRobot { mDevice.waitForObjects(suggestedLogins) break } catch (e: UiObjectNotFoundException) { - userNameTextBox.click() + clickPageObject(webPageItemWithResourceId("username")) } } } - fun clickStreetAddressTextBox() { - streetAddressTextBox().waitForExists(waitingTime) - streetAddressTextBox().click() - } + fun clickStreetAddressTextBox() = clickPageObject(webPageItemWithResourceId("streetAddress")) fun clickSelectAddressButton() { selectAddressButton.waitForExists(waitingTime) selectAddressButton.clickAndWaitForNewWindow(waitingTime) } - fun clickCardNumberTextBox() { - creditCardNumberTextBox().waitForExists(waitingTime) - creditCardNumberTextBox().click() - } + fun clickCardNumberTextBox() = clickPageObject(webPageItemWithResourceId("cardNumber")) fun clickSelectCreditCardButton() { selectCreditCardButton.waitForExists(waitingTime) @@ -699,8 +566,8 @@ class BrowserRobot { // Sometimes the assertion of the pre-filled logins fails so we are re-trying after refreshing the page while (currentTries++ < 3) { try { - mDevice.waitForObjects(userNameTextBox) - assertTrue(userNameTextBox.text.equals(userName)) + mDevice.waitForObjects(webPageItemWithResourceId("username")) + assertTrue(webPageItemWithResourceId("username").text.equals(userName)) break } catch (e: AssertionError) { @@ -714,18 +581,24 @@ class BrowserRobot { } } } - mDevice.waitForObjects(userNameTextBox) - assertTrue(userNameTextBox.text.equals(userName)) + mDevice.waitForObjects(webPageItemWithResourceId("username")) + assertTrue(webPageItemWithResourceId("username").text.equals(userName)) } fun verifyAutofilledAddress(streetAddress: String) { - mDevice.waitForObjects(streetAddressTextBox(streetAddress)) - assertTrue(streetAddressTextBox(streetAddress).waitForExists(waitingTime)) + mDevice.waitForObjects(webPageItemContainingTextAndResourceId("streetAddress", streetAddress)) + assertTrue( + webPageItemContainingTextAndResourceId("streetAddress", streetAddress) + .waitForExists(waitingTime), + ) } fun verifyAutofilledCreditCard(creditCardNumber: String) { - mDevice.waitForObjects(creditCardNumberTextBox(creditCardNumber)) - assertTrue(creditCardNumberTextBox(creditCardNumber).waitForExists(waitingTime)) + mDevice.waitForObjects(webPageItemContainingTextAndResourceId("cardNumber", creditCardNumber)) + assertTrue( + webPageItemContainingTextAndResourceId("cardNumber", creditCardNumber) + .waitForExists(waitingTime), + ) } fun verifyPrefilledPWALoginCredentials(userName: String, shortcutTitle: String) { @@ -734,9 +607,9 @@ class BrowserRobot { var currentTries = 0 while (currentTries++ < 3) { try { - assertTrue(submitLoginButton.waitForExists(waitingTime)) - submitLoginButton.click() - assertTrue(userNameTextBox.text.equals(userName)) + assertTrue(webPageItemWithResourceId("submit").waitForExists(waitingTime)) + webPageItemWithResourceId("submit").click() + assertTrue(webPageItemWithResourceId("username").text.equals(userName)) break } catch (e: AssertionError) { addToHomeScreen { @@ -779,10 +652,236 @@ class BrowserRobot { } } - fun clickSetCookiesButton() { - val setCookiesButton = mDevice.findObject(UiSelector().resourceId("setCookies")) - setCookiesButton.waitForExists(waitingTimeLong) - setCookiesButton.click() + fun clickSetCookiesButton() = clickPageObject(webPageItemWithResourceId("setCookies")) + + fun verifyCookiesProtectionHint() { + val hintMessage = + mDevice.findObject( + UiSelector() + .textContains(getStringResource(R.string.tcp_cfr_message)), + ) + assertTrue(hintMessage.waitForExists(waitingTime)) + } + + fun clickForm(formType: String) { + when (formType) { + "Calendar Form" -> { + clickPageObject(webPageItemWithResourceId("calendar")) + mDevice.waitForIdle(waitingTime) + } + "Clock Form" -> { + clickPageObject(webPageItemWithResourceId("clock")) + mDevice.waitForIdle(waitingTime) + } + "Color Form" -> { + clickPageObject(webPageItemWithResourceId("colorPicker")) + mDevice.waitForIdle(waitingTime) + } + "Drop-down Form" -> { + clickPageObject(webPageItemWithResourceId("dropDown")) + mDevice.waitForIdle(waitingTime) + } + } + } + + fun clickFormViewButton(button: String) = mDevice.findObject(UiSelector().textContains(button)).click() + + fun selectDate() { + mDevice.findObject(UiSelector().resourceId("android:id/month_view")).waitForExists(waitingTime) + + mDevice.findObject( + UiSelector() + .textContains("$currentDay") + .descriptionContains("$currentDay $currentMonth $currentYear"), + ).click() + } + + fun selectTime(hour: Int, minute: Int) = + onView( + isAssignableFrom(TimePicker::class.java), + ).inRoot( + isDialog(), + ).perform(PickerActions.setTime(hour, minute)) + + fun selectColor(hexValue: String) { + mDevice.findObject( + UiSelector() + .textContains("Choose a color") + .resourceId("$packageName:id/alertTitle"), + ).waitForExists(waitingTime) + + val colorSelection = + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/color_item") + .descriptionContains(hexValue), + ) + colorSelection.click() + } + + fun selectDropDownOption(optionName: String) { + mDevice.findObject( + UiSelector().resourceId("$packageName:id/customPanel"), + ).waitForExists(waitingTime) + mDevice.findObject(UiSelector().textContains(optionName)).click() + } + + fun clickSubmitDateButton() = clickPageObject(webPageItemWithResourceId("submitDate")) + + fun clickSubmitTimeButton() = clickPageObject(webPageItemWithResourceId("submitTime")) + + fun clickSubmitColorButton() = clickPageObject(webPageItemWithResourceId("submitColor")) + + fun clickSubmitDropDownButton() = clickPageObject(webPageItemWithResourceId("submitOption")) + + fun verifySelectedDate() { + for (i in 1..RETRY_COUNT) { + try { + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected date is: $currentDate"), + ).waitForExists(waitingTime), + ) + + break + } catch (e: AssertionError) { + Log.e("TestLog", "Selected time isn't displayed ${e.localizedMessage}") + + clickForm("Calendar Form") + selectDate() + clickFormViewButton("OK") + clickSubmitDateButton() + } + } + + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected date is: $currentDate"), + ).waitForExists(waitingTime), + ) + } + + fun verifyNoDateIsSelected() { + assertFalse( + mDevice.findObject( + UiSelector() + .text("Selected date is: $currentDate"), + ).waitForExists(waitingTime), + ) + } + + fun verifySelectedTime(hour: Int, minute: Int) { + for (i in 1..RETRY_COUNT) { + try { + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected time is: $hour:$minute"), + ).waitForExists(waitingTime), + ) + + break + } catch (e: AssertionError) { + Log.e("TestLog", "Selected time isn't displayed ${e.localizedMessage}") + + clickForm("Clock Form") + clickFormViewButton("CLEAR") + clickForm("Clock Form") + selectTime(hour, minute) + clickFormViewButton("OK") + clickSubmitTimeButton() + } + } + + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected time is: $hour:$minute"), + ).waitForExists(waitingTime), + ) + } + + fun verifySelectedColor(hexValue: String) { + for (i in 1..RETRY_COUNT) { + try { + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected color is: $hexValue"), + ).waitForExists(waitingTime), + ) + + break + } catch (e: AssertionError) { + Log.e("TestLog", "Selected color isn't displayed ${e.localizedMessage}") + + clickForm("Color Form") + selectColor(hexValue) + clickFormViewButton("SET") + clickSubmitColorButton() + } + } + + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected color is: $hexValue"), + ).waitForExists(waitingTime), + ) + } + + fun verifySelectedDropDownOption(optionName: String) { + for (i in 1..RETRY_COUNT) { + try { + mDevice.findObject( + UiSelector() + .textContains("Submit drop down option") + .resourceId("submitOption"), + ).waitForExists(waitingTime) + + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected option is: $optionName"), + ).waitForExists(waitingTime), + ) + + break + } catch (e: AssertionError) { + Log.e("TestLog", "Selected option isn't displayed ${e.localizedMessage}") + + clickForm("Drop-down Form") + selectDropDownOption(optionName) + clickSubmitDropDownButton() + } + } + + assertTrue( + mDevice.findObject( + UiSelector() + .text("Selected option is: $optionName"), + ).waitForExists(waitingTime), + ) + } + + fun verifyNoTimeIsSelected(hour: Int, minute: Int) { + assertFalse( + mDevice.findObject( + UiSelector() + .text("Selected date is: $hour:$minute"), + ).waitForExists(waitingTime), + ) + } + + fun verifyColorIsNotSelected(hexValue: String) { + assertFalse( + mDevice.findObject( + UiSelector() + .text("Selected date is: $hexValue"), + ).waitForExists(waitingTime), + ) } class Transition { @@ -812,12 +911,22 @@ class BrowserRobot { } fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { - mDevice.findObject( - UiSelector().descriptionContains("Tap to switch tabs."), - ).waitForExists(waitingTime) + mDevice.waitForObjects( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/mozac_browser_toolbar_browser_actions"), + ), + waitingTime, + ) tabsCounter().click() - mDevice.waitNotNull(Until.findObject(By.res("$packageName:id/tab_layout"))) + + mDevice.waitForObjects( + mDevice.findObject( + UiSelector().resourceId("$packageName:id/new_tab_button"), + ), + waitingTime, + ) TabDrawerRobot().interact() return TabDrawerRobot.Transition() @@ -850,7 +959,12 @@ class BrowserRobot { assertTrue( mDevice.findObject(UiSelector().resourceId("$packageName:id/homeLayout")) - .waitForExists(waitingTime), + .waitForExists(waitingTime) || + mDevice.findObject( + UiSelector().text( + getStringResource(R.string.onboarding_home_screen_jump_back_contextual_hint_2), + ), + ).waitForExists(waitingTime), ) HomeScreenRobot().interact() @@ -888,13 +1002,12 @@ class BrowserRobot { } fun clickDownloadLink(title: String, interact: DownloadRobot.() -> Unit): DownloadRobot.Transition { - val downloadLink = mDevice.findObject(UiSelector().textContains(title)) - assertTrue( "$title download link not found", - downloadLink.waitForExists(waitingTime), + webPageItemContainingText(title).waitForExists(waitingTime), ) - downloadLink.click() + + clickPageObject(webPageItemContainingText(title)) DownloadRobot().interact() return DownloadRobot.Transition() @@ -902,8 +1015,7 @@ class BrowserRobot { fun clickStartCameraButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions - cameraButton.waitForExists(waitingTime) - cameraButton.click() + clickPageObject(webPageItemWithText("Open camera")) SitePermissionsRobot().interact() return SitePermissionsRobot.Transition() @@ -911,8 +1023,7 @@ class BrowserRobot { fun clickStartMicrophoneButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions - microphoneButton.waitForExists(waitingTime) - microphoneButton.click() + clickPageObject(webPageItemWithText("Open microphone")) SitePermissionsRobot().interact() return SitePermissionsRobot.Transition() @@ -920,8 +1031,7 @@ class BrowserRobot { fun clickStartAudioVideoButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions - audioVideoButton.waitForExists(waitingTime) - audioVideoButton.click() + clickPageObject(webPageItemWithText("Camera & Microphone")) SitePermissionsRobot().interact() return SitePermissionsRobot.Transition() @@ -929,8 +1039,7 @@ class BrowserRobot { fun clickOpenNotificationButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions - notificationButton.waitForExists(waitingTime) - notificationButton.click() + clickPageObject(webPageItemWithText("Open notifications dialogue")) mDevice.waitForObjects(mDevice.findObject(UiSelector().textContains("Allow to send notifications?"))) SitePermissionsRobot().interact() @@ -939,8 +1048,14 @@ class BrowserRobot { fun clickGetLocationButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { // Test page used for testing permissions located at https://mozilla-mobile.github.io/testapp/permissions - getLocationButton.waitForExists(waitingTime) - getLocationButton.click() + clickPageObject(webPageItemWithText("Get Location")) + + SitePermissionsRobot().interact() + return SitePermissionsRobot.Transition() + } + + fun clickRequestStorageAccessButton(interact: SitePermissionsRobot.() -> Unit): SitePermissionsRobot.Transition { + clickPageObject(webPageItemContainingText("requestStorageAccess()")) SitePermissionsRobot().interact() return SitePermissionsRobot.Transition() @@ -988,14 +1103,8 @@ private fun assertMenuButton() { .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun tabsCounter() = mDevice.findObject(By.res("$packageName:id/counter_root")) - -private fun mediaPlayerPlayButton() = - mDevice.findObject( - UiSelector() - .className("android.widget.Button") - .text("Play"), - ) +private fun tabsCounter() = + mDevice.findObject(By.res("$packageName:id/mozac_browser_toolbar_browser_actions")) private var progressBar = mDevice.findObject( @@ -1013,24 +1122,6 @@ private fun addressSuggestion(streetName: String) = .textContains(streetName), ) -private fun streetAddressTextBox(streetAddress: String = "") = - mDevice.findObject( - UiSelector() - .resourceId("streetAddress") - .textContains(streetAddress) - .className("android.widget.EditText") - .packageName("$packageName"), - ) - -private fun creditCardNumberTextBox(creditCardNumber: String = "") = - mDevice.findObject( - UiSelector() - .resourceId("cardNumber") - .textContains(creditCardNumber) - .className("android.widget.EditText") - .packageName("$packageName"), - ) - private fun creditCardSuggestion(creditCardNumber: String) = mDevice.findObject( UiSelector() @@ -1041,41 +1132,92 @@ private fun creditCardSuggestion(creditCardNumber: String) = private fun siteSecurityToolbarButton() = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_security_indicator")) -// Permissions test page elements & prompts -// Test page used located at https://mozilla-mobile.github.io/testapp/permissions -private val cameraButton = mDevice.findObject(UiSelector().text("Open camera")) +private fun clickPageObject(webPageItem: UiObject) { + for (i in 1..RETRY_COUNT) { + try { + webPageItem.also { + it.waitForExists(waitingTime) + it.click() + } -private val microphoneButton = mDevice.findObject(UiSelector().text("Open microphone")) + break + } catch (e: UiObjectNotFoundException) { + if (i == RETRY_COUNT) { + throw e + } else { + browserScreen { + }.openThreeDotMenu { + }.refreshPage { + progressBar.waitUntilGone(waitingTime) + } + } + } + } +} -private val audioVideoButton = mDevice.findObject(UiSelector().text("Camera & Microphone")) +fun longClickPageObject(webPageItem: UiObject) { + for (i in 1..RETRY_COUNT) { + try { + webPageItem.also { + it.waitForExists(waitingTime) + it.longClick() + } -private val notificationButton = mDevice.findObject(UiSelector().text("Open notifications dialogue")) + break + } catch (e: UiObjectNotFoundException) { + if (i == RETRY_COUNT) { + throw e + } else { + browserScreen { + }.openThreeDotMenu { + }.refreshPage { + } + progressBar.waitUntilGone(waitingTime) + } + } + } +} -private val getLocationButton = mDevice.findObject(UiSelector().text("Get Location")) +private fun webPageItemContainingText(itemText: String) = + mDevice.findObject(UiSelector().textContains(itemText)) -// Login form test page elements -// Test page used located at https://mozilla-mobile.github.io/testapp/loginForm -val userNameTextBox = - mDevice.findObject( - UiSelector() - .resourceId("username") - .className("android.widget.EditText") - .packageName("$packageName"), - ) +private fun webPageItemWithText(itemText: String) = + mDevice.findObject(UiSelector().text(itemText)) -private val submitLoginButton = - mDevice.findObject( - UiSelector() - .resourceId("submit") - .textContains("Submit Query") - .className("android.widget.Button") - .packageName("$packageName"), - ) +private fun webPageItemWithResourceId(resourceId: String) = + mDevice.findObject(UiSelector().resourceId(resourceId)) -val passwordTextBox = +private fun webPageItemContainingTextAndResourceId(resourceId: String, itemText: String) = mDevice.findObject( UiSelector() - .resourceId("password") - .className("android.widget.EditText") - .packageName("$packageName"), + .resourceId(resourceId) + .textContains(itemText), ) + +private fun setPageObjectText(webPageItem: UiObject, text: String) { + for (i in 1..RETRY_COUNT) { + try { + webPageItem.also { + it.waitForExists(waitingTime) + it.setText(text) + } + + break + } catch (e: UiObjectNotFoundException) { + if (i == RETRY_COUNT) { + throw e + } else { + browserScreen { + }.openThreeDotMenu { + }.refreshPage { + progressBar.waitUntilGone(waitingTime) + } + } + } + } +} + +private val currentDate = LocalDate.now() +private val currentDay = currentDate.dayOfMonth +private val currentMonth = currentDate.month +private val currentYear = currentDate.year diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt index 7730ec0d6..d4af3d7d4 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/CustomTabRobot.kt @@ -11,11 +11,13 @@ import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiObject import androidx.test.uiautomator.UiObjectNotFoundException import androidx.test.uiautomator.UiSelector import junit.framework.TestCase.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.Constants.LONG_CLICK_DURATION +import org.mozilla.fenix.helpers.Constants.RETRY_COUNT import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.TestHelper.mDevice @@ -92,49 +94,40 @@ class CustomTabRobot { } fun fillAndSubmitLoginCredentials(userName: String, password: String) { - var currentTries = 0 - while (currentTries++ < 3) { - try { - mDevice.waitForIdle(waitingTime) - userNameTextBox.setText(userName) - passwordTextBox.setText(password) - submitLoginButton.click() - mDevice.waitForObjects(mDevice.findObject(UiSelector().resourceId("$packageName:id/save_confirm"))) - break - } catch (e: UiObjectNotFoundException) { - customTabScreen { - }.openMainMenu { - refreshButton().click() - waitForPageToLoad() - } - } - } + mDevice.waitForIdle(waitingTime) + setPageObjectText(webPageItemWithResourceId("username"), userName) + setPageObjectText(webPageItemWithResourceId("password"), password) + clickPageObject(webPageItemWithResourceId("submit")) + mDevice.waitForObjects(mDevice.findObject(UiSelector().resourceId("$packageName:id/save_confirm"))) } - fun clickLinkMatchingText(expectedText: String) { - var currentTries = 0 - while (currentTries++ < 3) { + fun clickLinkMatchingText(expectedText: String) = clickPageObject(webPageItemContainingText(expectedText)) + + fun waitForPageToLoad() = progressBar.waitUntilGone(waitingTime) + + fun clickPageObject(webPageItem: UiObject) { + for (i in 1..RETRY_COUNT) { try { - mDevice.findObject(UiSelector().resourceId("$packageName:id/engineView")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().textContains(expectedText)) - .waitForExists(waitingTime) + webPageItem.also { + it.waitForExists(waitingTime) + it.click() + } - val element = mDevice.findObject(UiSelector().textContains(expectedText)) - element.click() break } catch (e: UiObjectNotFoundException) { - customTabScreen { - }.openMainMenu { - refreshButton().click() - waitForPageToLoad() + if (i == RETRY_COUNT) { + throw e + } else { + browserScreen { + }.openThreeDotMenu { + }.refreshPage { + progressBar.waitUntilGone(waitingTime) + } } } } } - fun waitForPageToLoad() = progressBar.waitUntilGone(waitingTime) - class Transition { fun openMainMenu(interact: CustomTabRobot.() -> Unit): Transition { mainMenuButton().waitForExists(waitingTime) @@ -176,16 +169,36 @@ private fun closeButton() = onView(withContentDescription("Return to previous ap private fun customTabToolbar() = mDevice.findObject(By.res("$packageName:id/toolbar")) +private fun setPageObjectText(webPageItem: UiObject, text: String) { + for (i in 1..RETRY_COUNT) { + try { + webPageItem.also { + it.waitForExists(waitingTime) + it.setText(text) + } + + break + } catch (e: UiObjectNotFoundException) { + if (i == RETRY_COUNT) { + throw e + } else { + browserScreen { + }.openThreeDotMenu { + }.refreshPage { + progressBar.waitUntilGone(waitingTime) + } + } + } + } +} + private val progressBar = mDevice.findObject( UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_progress"), ) -private val submitLoginButton = - mDevice.findObject( - UiSelector() - .resourceId("submit") - .textContains("Submit Query") - .className("android.widget.Button") - .packageName("$packageName"), - ) +private fun webPageItemContainingText(itemText: String) = + mDevice.findObject(UiSelector().textContains(itemText)) + +private fun webPageItemWithResourceId(resourceId: String) = + mDevice.findObject(UiSelector().resourceId(resourceId)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt index fc33ffd7a..52f87e576 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt @@ -28,8 +28,8 @@ import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.assertExternalAppOpens -import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.mDevice +import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt index b1c1c8876..d624671cd 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HistoryRobot.kt @@ -11,6 +11,7 @@ import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withParent @@ -23,6 +24,7 @@ import org.hamcrest.Matchers.allOf import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.R +import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.mDevice @@ -61,7 +63,7 @@ class HistoryRobot { fun verifyFirstTestPageTitle(title: String) = assertTestPageTitle(title) - fun verifyTestPageUrl(expectedUrl: Uri) = assertPageUrl(expectedUrl) + fun verifyTestPageUrl(expectedUrl: Uri) = pageUrl(expectedUrl.toString()).check(matches(isDisplayed())) fun verifyCopySnackBarText() = assertCopySnackBarText() @@ -99,9 +101,34 @@ class HistoryRobot { snackBarUndoButton().click() } + fun verifySearchGroupDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int) { + // checks if the search group exists in the Recently visited section + if (shouldBeDisplayed) { + assertTrue( + mDevice.findObject(UiSelector().text(searchTerm)) + .getFromParent(UiSelector().text("$groupSize sites")) + .waitForExists(TestAssetHelper.waitingTimeShort), + ) + } else { + assertFalse( + mDevice.findObject(UiSelector().text(searchTerm)) + .getFromParent(UiSelector().text("$groupSize sites")) + .waitForExists(TestAssetHelper.waitingTimeShort), + ) + } + } + class Transition { - fun goBackToBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - mDevice.pressBack() + fun goBack(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + onView(withContentDescription("Navigate up")).click() + + BrowserRobot().interact() + return BrowserRobot.Transition() + } + + fun openWebsite(url: Uri, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + assertHistoryListExists() + onView(withText(url.toString())).click() BrowserRobot().interact() return BrowserRobot.Transition() @@ -116,10 +143,10 @@ fun historyMenu(interact: HistoryRobot.() -> Unit): HistoryRobot.Transition { private fun testPageTitle() = onView(allOf(withId(R.id.title), withText("Test_Page_1"))) -private fun pageUrl() = onView(withId(R.id.url)) +private fun pageUrl(url: String) = onView(allOf(withId(R.id.url), withText(url))) private fun deleteButton(title: String) = - onView(allOf(withId(R.id.overflow_menu), hasSibling(withText(title)))) + onView(allOf(withContentDescription("Delete"), hasSibling(withText(title)))) private fun deleteButton() = onView(withId(R.id.history_delete)) @@ -142,7 +169,7 @@ private fun assertEmptyHistoryView() = .check(matches(withText("No history here"))) private fun assertHistoryListExists() = - mDevice.findObject(UiSelector().resourceId("R.id.history_list")).waitForExists(waitingTime) + mDevice.findObject(UiSelector().resourceId("$packageName:id/history_list")).waitForExists(waitingTime) private fun assertHistoryItemExists(shouldExist: Boolean, item: String) { if (shouldExist) { @@ -159,10 +186,6 @@ private fun assertTestPageTitle(title: String) = testPageTitle() .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withText(title))) -private fun assertPageUrl(expectedUrl: Uri) = pageUrl() - .check(matches(ViewMatchers.isCompletelyDisplayed())) - .check(matches(withText(Matchers.containsString(expectedUrl.toString())))) - private fun assertDeleteConfirmationMessage() { assertTrue(deleteHistoryPromptTitle().waitForExists(waitingTime)) assertTrue(deleteHistoryPromptSummary().waitForExists(waitingTime)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt index 7ff2efeaf..c3d6bf437 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt @@ -11,6 +11,7 @@ import android.widget.EditText import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.ComposeTestRule +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView @@ -37,7 +38,6 @@ import mozilla.components.browser.state.state.searchEngines import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.instanceOf -import org.hamcrest.CoreMatchers.not import org.hamcrest.Matchers import org.junit.Assert import org.junit.Assert.assertFalse @@ -56,7 +56,6 @@ import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull -import org.mozilla.fenix.helpers.matchers.hasItem import org.mozilla.fenix.helpers.withBitmapDrawable import org.mozilla.fenix.ui.util.STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER import org.mozilla.fenix.ui.util.STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER @@ -134,6 +133,44 @@ class HomeScreenRobot { fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton() fun verifyStartBrowsingButton() = assertStartBrowsingButton() + // Upgrading users onboarding dialog + fun verifyUpgradingUserOnboardingFirstScreen(testRule: ComposeTestRule) { + testRule.also { + it.onNodeWithText(getStringResource(R.string.onboarding_home_welcome_title_2)) + .assertIsDisplayed() + + it.onNodeWithText(getStringResource(R.string.onboarding_home_welcome_description)) + .assertIsDisplayed() + + it.onNodeWithText(getStringResource(R.string.onboarding_home_get_started_button)) + .assertIsDisplayed() + } + } + + fun clickGetStartedButton(testRule: ComposeTestRule) = + testRule.onNodeWithText(getStringResource(R.string.onboarding_home_get_started_button)).performClick() + + fun verifyUpgradingUserOnboardingSecondScreen(testRule: ComposeTestRule) { + testRule.also { + it.onNodeWithText(getStringResource(R.string.onboarding_home_sync_title_3)) + .assertIsDisplayed() + + it.onNodeWithText(getStringResource(R.string.onboarding_home_sync_description)) + .assertIsDisplayed() + + it.onNodeWithText(getStringResource(R.string.onboarding_home_sign_in_button)) + .assertIsDisplayed() + + it.onNodeWithText(getStringResource(R.string.onboarding_home_skip_button)) + .assertIsDisplayed() + } + } + + fun clickSkipButton(testRule: ComposeTestRule) = + testRule + .onNodeWithText(getStringResource(R.string.onboarding_home_skip_button)) + .performClick() + fun verifyPrivateSessionMessage() = assertPrivateSessionMessage() fun verifyExistingTopSitesList() = assertExistingTopSitesList() @@ -145,42 +182,27 @@ class HomeScreenRobot { fun verifyJumpBackInSectionIsDisplayed() = assertJumpBackInSectionIsDisplayed() fun verifyJumpBackInSectionIsNotDisplayed() = assertJumpBackInSectionIsNotDisplayed() + fun verifyRecentlyVisitedSectionIsDisplayed() = assertRecentlyVisitedSectionIsDisplayed() + fun verifyRecentlyVisitedSectionIsNotDisplayed() = assertRecentlyVisitedSectionIsNotDisplayed() fun verifyRecentBookmarksSectionIsDisplayed() = assertRecentBookmarksSectionIsDisplayed() fun verifyRecentBookmarksSectionIsNotDisplayed() = assertRecentBookmarksSectionIsNotDisplayed() + fun verifyPocketSectionIsDisplayed() = assertPocketSectionIsDisplayed() + fun verifyPocketSectionIsNotDisplayed() = assertPocketSectionIsNotDisplayed() fun verifyRecentlyVisitedSearchGroupDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int) { // checks if the search group exists in the Recently visited section if (shouldBeDisplayed) { - recentlyVisitedList.waitForExists(waitingTime) scrollToElementByText("Recently visited") - recentlyVisitedList.getChildByText(UiSelector().text(searchTerm), searchTerm, true) - .waitForExists(waitingTimeShort) assertTrue( mDevice.findObject(UiSelector().text(searchTerm)) .getFromParent(UiSelector().text("$groupSize sites")) .waitForExists(waitingTimeShort), ) } else { - assertFalse( + assertTrue( mDevice.findObject(UiSelector().text(searchTerm)) .getFromParent(UiSelector().text("$groupSize sites")) - .waitForExists(waitingTimeShort), - ) - } - } - - fun verifyCurrentSearchGroupIsDisplayed(shouldBeDisplayed: Boolean, searchTerm: String, groupSize: Int = 0) { - // checks search group in the Jump back in section - if (shouldBeDisplayed) { - assertTrue( - mDevice.findObject(UiSelector().text("""Your search for "$searchTerm"""")) - .getFromParent(UiSelector().textContains("$groupSize sites")) - .waitForExists(waitingTimeShort), - ) - } else { - assertFalse( - mDevice.findObject(UiSelector().text("""Your search for "$searchTerm"""")) - .waitForExists(waitingTimeShort), + .waitUntilGone(waitingTimeShort), ) } } @@ -292,7 +314,7 @@ class HomeScreenRobot { fun getSponsoredShortcutTitle(position: Int): String { val sponsoredShortcut = mDevice.findObject( UiSelector() - .className("android.widget.FrameLayout") + .resourceId("$packageName:id/top_site_item") .index(position - 1), ).getChild( UiSelector() @@ -302,6 +324,16 @@ class HomeScreenRobot { return sponsoredShortcut } + fun verifyJumpBackInMessage() { + assertTrue( + mDevice.findObject( + UiSelector().text( + getStringResource(R.string.onboarding_home_screen_jump_back_contextual_hint_2), + ), + ).waitForExists(waitingTime), + ) + } + class Transition { fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { @@ -352,6 +384,16 @@ class HomeScreenRobot { return SearchRobot.Transition() } + fun clickUpgradingUserOnboardingSignInButton( + testRule: ComposeTestRule, + interact: SyncSignInRobot.() -> Unit, + ): SyncSignInRobot.Transition { + testRule.onNodeWithText("Sign in").performClick() + + SyncSignInRobot().interact() + return SyncSignInRobot.Transition() + } + fun togglePrivateBrowsingMode() { mDevice.findObject(UiSelector().resourceId("$packageName:id/privateBrowsingButton")) .waitForExists( @@ -519,7 +561,8 @@ class HomeScreenRobot { } fun openRecentlyVisitedSearchGroupHistoryList(title: String, interact: HistoryRobot.() -> Unit): HistoryRobot.Transition { - val searchGroup = recentlyVisitedList.getChildByText(UiSelector().text(title), title, true) + scrollToElementByText("Recently visited") + val searchGroup = mDevice.findObject(UiSelector().text(title)) searchGroup.waitForExists(waitingTimeShort) searchGroup.click() @@ -645,9 +688,11 @@ private fun assertStartSyncHeader() { onView(allOf(withText(R.string.onboarding_account_sign_in_header))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) } -private fun assertAccountsSignInButton() = +private fun assertAccountsSignInButton() { + scrollToElementByText(getStringResource(R.string.onboarding_firefox_account_sign_in)) onView(ViewMatchers.withResourceName("fxa_sign_in_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +} private fun assertChooseThemeHeader() { scrollToElementByText("Choose your theme") @@ -798,7 +843,7 @@ private fun assertSponsoredSubtitleIsDisplayed(position: Int) = assertTrue( mDevice.findObject( UiSelector() - .className("android.widget.FrameLayout") + .resourceId("$packageName:id/top_site_item") .index(position - 1), ).getChild( UiSelector() @@ -810,7 +855,7 @@ private fun assertSponsoredShortcutTitle(sponsoredShortcutTitle: String, positio assertTrue( mDevice.findObject( UiSelector() - .className("android.widget.FrameLayout") + .resourceId("$packageName:id/top_site_item") .index(position - 1), ).getChild( UiSelector() @@ -820,11 +865,15 @@ private fun assertSponsoredShortcutTitle(sponsoredShortcutTitle: String, positio } private fun assertNotExistingTopSitesList(title: String) { - mDevice.findObject(UiSelector().text(title)) - .waitUntilGone(waitingTime) + mDevice.findObject(UiSelector().text(title)).waitUntilGone(waitingTime) - onView(allOf(withId(R.id.top_sites_list))) - .check(matches(not(hasItem(hasDescendant(withText(title)))))) + assertFalse( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/top_site_title") + .textContains(title), + ).waitForExists(waitingTime), + ) } private fun assertSponsoredTopSitesNotDisplayed() { @@ -852,12 +901,20 @@ private fun assertJumpBackInSectionIsDisplayed() = assertTrue(jumpBackInSection( private fun assertJumpBackInSectionIsNotDisplayed() = assertFalse(jumpBackInSection().waitForExists(waitingTimeShort)) +private fun assertRecentlyVisitedSectionIsDisplayed() = assertTrue(recentlyVisitedSection().waitForExists(waitingTime)) + +private fun assertRecentlyVisitedSectionIsNotDisplayed() = assertFalse(recentlyVisitedSection().waitForExists(waitingTime)) + private fun assertRecentBookmarksSectionIsDisplayed() = assertTrue(recentBookmarksSection().waitForExists(waitingTime)) private fun assertRecentBookmarksSectionIsNotDisplayed() = assertFalse(recentBookmarksSection().waitForExists(waitingTimeShort)) +private fun assertPocketSectionIsDisplayed() = assertTrue(pocketSection().waitForExists(waitingTime)) + +private fun assertPocketSectionIsNotDisplayed() = assertFalse(pocketSection().waitForExists(waitingTime)) + private fun privateBrowsingButton() = onView(withId(R.id.privateBrowsingButton)) private fun saveTabsToCollectionButton() = onView(withId(R.id.add_tabs_to_collections_button)) @@ -867,9 +924,15 @@ private fun tabsCounter() = onView(withId(R.id.tab_button)) private fun jumpBackInSection() = mDevice.findObject(UiSelector().textContains(getStringResource(R.string.recent_tabs_header))) +private fun recentlyVisitedSection() = + mDevice.findObject(UiSelector().textContains(getStringResource(R.string.history_metadata_header_2))) + private fun recentBookmarksSection() = mDevice.findObject(UiSelector().textContains(getStringResource(R.string.recently_saved_title))) +private fun pocketSection() = + mDevice.findObject(UiSelector().textContains(getStringResource(R.string.pocket_stories_header_1))) + private fun startBrowsingButton(): UiObject { val startBrowsingButton = mDevice.findObject(UiSelector().resourceId("$packageName:id/finish_button")) homeScreenList() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/LibrarySubMenusMultipleSelectionToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/LibrarySubMenusMultipleSelectionToolbarRobot.kt index 942a7f44a..02277d6c3 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/LibrarySubMenusMultipleSelectionToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/LibrarySubMenusMultipleSelectionToolbarRobot.kt @@ -9,22 +9,22 @@ import android.widget.TextView import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withChild import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withParent -import androidx.test.espresso.matcher.ViewMatchers.withChild +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until -import org.mozilla.fenix.R -import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime -import org.mozilla.fenix.helpers.click -import org.mozilla.fenix.helpers.ext.waitNotNull import org.hamcrest.Matchers.allOf +import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName +import org.mozilla.fenix.helpers.click +import org.mozilla.fenix.helpers.ext.waitNotNull /* * Implementation of Robot Pattern for the multiple selection toolbar of History and Bookmarks menus. diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index cddd0a982..ed09b5a9c 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -22,18 +22,19 @@ import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withParent -import androidx.test.espresso.matcher.ViewMatchers.withResourceName import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.not +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.SessionLoadedIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort +import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.click @@ -54,8 +55,6 @@ class NavigationToolbarRobot { fun verifyCloseReaderViewDetected(visible: Boolean = false) = assertCloseReaderViewDetected(visible) - fun typeSearchTerm(searchTerm: String) = awesomeBar().setText(searchTerm) - fun toggleReaderView() { mDevice.findObject( UiSelector() @@ -66,6 +65,33 @@ class NavigationToolbarRobot { readerViewToggle().click() } + fun verifyClipboardSuggestionsAreDisplayed(link: String, shouldBeDisplayed: Boolean) { + when (shouldBeDisplayed) { + true -> { + assertTrue( + mDevice.findObject(UiSelector().resourceId("$packageName:id/fill_link_from_clipboard")) + .waitForExists(waitingTime), + ) + + assertTrue( + mDevice.findObject(UiSelector().resourceId("$packageName:id/clipboard_url").text(link)) + .waitForExists(waitingTime), + ) + } + false -> { + assertFalse( + mDevice.findObject(UiSelector().resourceId("$packageName:id/fill_link_from_clipboard")) + .waitForExists(waitingTime), + ) + + assertFalse( + mDevice.findObject(UiSelector().resourceId("$packageName:id/clipboard_url").text(link)) + .waitForExists(waitingTime), + ) + } + } + } + class Transition { private lateinit var sessionLoadedIdlingResource: SessionLoadedIdlingResource @@ -98,12 +124,15 @@ class NavigationToolbarRobot { mDevice.pressEnter() runWithIdleRes(sessionLoadedIdlingResource) { - onView( - anyOf( - withResourceName("browserLayout"), - withResourceName("download_button"), - ), - ).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + assertTrue( + mDevice.findObject( + UiSelector().resourceId("$packageName:id/browserLayout"), + ).waitForExists(waitingTime) || mDevice.findObject( + UiSelector().resourceId("$packageName:id/download_button"), + ).waitForExists(waitingTime) || mDevice.findObject( + UiSelector().text(getStringResource(R.string.tcp_cfr_message)), + ).waitForExists(waitingTime), + ) } BrowserRobot().interact() @@ -149,14 +178,12 @@ class NavigationToolbarRobot { } fun visitLinkFromClipboard(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { - mDevice.waitNotNull( - Until.findObject(By.res("org.mozilla.fenix.debug:id/mozac_browser_toolbar_clear_view")), - waitingTime, - ) - clearAddressBar().click() + if (clearAddressBar().waitForExists(waitingTimeShort)) { + clearAddressBar().click() + } mDevice.waitNotNull( - Until.findObject(By.res("org.mozilla.fenix.debug:id/clipboard_title")), + Until.findObject(By.res("$packageName:id/clipboard_title")), waitingTime, ) @@ -164,7 +191,7 @@ class NavigationToolbarRobot { // See for mor information https://github.com/mozilla-mobile/fenix/issues/22271 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { mDevice.waitNotNull( - Until.findObject(By.res("org.mozilla.fenix.debug:id/clipboard_url")), + Until.findObject(By.res("$packageName:id/clipboard_url")), waitingTime, ) } @@ -284,7 +311,9 @@ private fun threeDotButton() = onView(withId(R.id.mozac_browser_toolbar_menu)) private fun tabTrayButton() = onView(withId(R.id.tab_button)) private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard)) private fun clearAddressBar() = - mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_clear_view")) + mDevice.findObject( + UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_clear_view"), + ) private fun goBackButton() = mDevice.pressBack() private fun readerViewToggle() = onView(withParent(withId(R.id.mozac_browser_toolbar_page_actions))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt index 0efe1131d..5466ec1bb 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt @@ -13,12 +13,12 @@ import androidx.test.uiautomator.Until import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.ext.waitNotNull import java.lang.AssertionError -import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort class NotificationRobot { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt index 7e3a54b70..592ce4d9d 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SearchRobot.kt @@ -8,17 +8,16 @@ package org.mozilla.fenix.ui.robots import android.os.Build import androidx.compose.ui.test.ExperimentalTestApi -import androidx.compose.ui.test.assertAny import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.ComposeTestRule import androidx.compose.ui.test.junit4.android.ComposeNotIdleException -import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onNodeWithTag import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.performClick import androidx.compose.ui.test.performScrollToIndex +import androidx.compose.ui.test.performScrollToNode import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions.closeSoftKeyboard import androidx.test.espresso.assertion.ViewAssertions.matches @@ -28,12 +27,9 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withSubstring import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By -import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector -import androidx.test.uiautomator.Until import org.hamcrest.CoreMatchers.allOf import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -41,16 +37,16 @@ import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.Constants import org.mozilla.fenix.helpers.Constants.LONG_CLICK_DURATION +import org.mozilla.fenix.helpers.Constants.RETRY_COUNT import org.mozilla.fenix.helpers.Constants.SPEECH_RECOGNITION import org.mozilla.fenix.helpers.SessionLoadedIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort +import org.mozilla.fenix.helpers.TestHelper.getStringResource import org.mozilla.fenix.helpers.TestHelper.isPackageInstalled import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName -import org.mozilla.fenix.helpers.TestHelper.waitForObjects import org.mozilla.fenix.helpers.click -import org.mozilla.fenix.helpers.ext.waitNotNull /** * Implementation of Robot Pattern for the search fragment. @@ -94,14 +90,95 @@ class SearchRobot { } fun verifySearchEngineButton() = assertSearchButton() - fun verifySearchWithText() = assertSearchWithText() - fun verifySearchEngineResults(rule: ComposeTestRule, searchSuggestion: String, searchEngineName: String) = - assertSearchEngineResults(rule, searchSuggestion, searchEngineName) - fun verifySearchEngineSuggestionResults(rule: ComposeTestRule, searchSuggestion: String) = - assertSearchEngineSuggestionResults(rule, searchSuggestion) - fun verifyNoSuggestionsAreDisplayed(rule: ComposeTestRule, searchSuggestion: String) = - assertNoSuggestionsAreDisplayed(rule, searchSuggestion) - fun verifySearchSettings() = assertSearchSettings() + + fun verifySearchEngineSuggestionResults(rule: ComposeTestRule, searchSuggestion: String) { + rule.waitForIdle() + for (i in 1..RETRY_COUNT) { + try { + assertTrue( + mDevice.findObject(UiSelector().textContains(searchSuggestion)) + .waitForExists(waitingTime), + ) + break + } catch (e: AssertionError) { + if (i == RETRY_COUNT) { + throw e + } else { + expandSearchSuggestionsList() + } + } + } + } + + fun verifyFirefoxSuggestResults(rule: ComposeTestRule, searchSuggestion: String) { + rule.waitForIdle() + for (i in 1..RETRY_COUNT) { + try { + rule.onNodeWithTag("mozac.awesomebar.suggestions") + .performScrollToNode(hasText(searchSuggestion)) + .assertExists() + break + } catch (e: AssertionError) { + if (i == RETRY_COUNT) { + throw e + } else { + expandSearchSuggestionsList() + } + } + } + } + + fun verifyNoSuggestionsAreDisplayed(rule: ComposeTestRule, searchSuggestion: String) { + rule.waitForIdle() + + assertFalse( + mDevice.findObject(UiSelector().textContains(searchSuggestion)) + .waitForExists(waitingTime), + ) + } + + fun verifyAllowSuggestionsInPrivateModeDialog() { + assertTrue( + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_title)), + ).waitForExists(waitingTime), + ) + assertTrue( + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_text)), + ).exists(), + ) + assertTrue( + mDevice.findObject( + UiSelector().text("Learn more"), + ).exists(), + ) + assertTrue( + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_allow_button)), + ).exists(), + ) + assertTrue( + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_do_not_allow_button)), + ).exists(), + ) + } + + fun denySuggestionsInPrivateMode() { + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_do_not_allow_button)), + ).click() + } + + fun allowSuggestionsInPrivateMode() { + mDevice.findObject( + UiSelector().text(getStringResource(R.string.search_suggestions_onboarding_allow_button)), + ).click() + } + + fun verifySearchEnginePrompt(rule: ComposeTestRule, searchEngineName: String) = + assertSearchEnginePrompt(rule, searchEngineName) fun verifySearchBarEmpty() = assertSearchBarEmpty() fun verifyKeyboardVisibility() = assertKeyboardVisibility(isExpectedToBeVisible = true) @@ -157,33 +234,6 @@ class SearchRobot { mDevice.waitForIdle() } - fun clickSearchEngineButton(rule: ComposeTestRule, searchEngineName: String) { - rule.waitForIdle() - - mDevice.waitForObjects( - mDevice.findObject( - UiSelector().textContains(searchEngineName), - ), - ) - - rule.onNodeWithText(searchEngineName) - .assertExists() - .assertHasClickAction() - .performClick() - } - - fun clickSearchEngineResult(rule: ComposeTestRule, searchSuggestion: String) { - mDevice.waitNotNull( - Until.findObjects(By.text(searchSuggestion)), - waitingTime, - ) - - rule.onNodeWithText(searchSuggestion) - .assertIsDisplayed() - .assertHasClickAction() - .performClick() - } - @OptIn(ExperimentalTestApi::class) fun scrollToSearchEngineSettings(rule: ComposeTestRule) { // Soft keyboard is visible on screen on view access; hide it @@ -198,13 +248,6 @@ class SearchRobot { .performScrollToIndex(5) } - fun clickSearchEngineSettings(rule: ComposeTestRule) { - rule.onNodeWithText("Search engine settings") - .assertIsDisplayed() - .assertHasClickAction() - .performClick() - } - fun clickClearButton() { clearButton().click() } @@ -225,11 +268,53 @@ class SearchRobot { pasteText.click() } + fun clickSearchEnginePrompt(rule: ComposeTestRule, searchEngineName: String) = + rule.onNodeWithText("Search $searchEngineName").performClick() + fun expandSearchSuggestionsList() { + onView(allOf(withId(R.id.search_wrapper))).perform( + closeSoftKeyboard(), + ) awesomeBar.swipeUp(2) } - fun verifyPastedToolbarText(expectedText: String) = assertPastedToolbarText(expectedText) + fun verifyTranslatedFocusedNavigationToolbar(toolbarHintString: String) = + assertTranslatedFocusedNavigationToolbar(toolbarHintString) + + fun verifySearchEngineShortcuts(rule: ComposeTestRule, vararg searchEngines: String) { + mDevice.findObject( + UiSelector().resourceId("$packageName:id/awesome_bar"), + ).swipeUp(1) + + for (searchEngine in searchEngines) { + rule.waitForIdle() + rule.onNodeWithText(searchEngine).assertIsDisplayed() + } + } + + fun verifySearchEngineShortcutsAreNotDisplayed(rule: ComposeTestRule, vararg searchEngines: String) { + mDevice.findObject( + UiSelector().resourceId("$packageName:id/pill_wrapper_divider"), + ).waitForExists(waitingTime) + + for (searchEngine in searchEngines) { + rule.waitForIdle() + rule.onNodeWithText(searchEngine).assertDoesNotExist() + } + } + + fun verifyTypedToolbarText(expectedText: String) { + mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar")) + .waitForExists(waitingTime) + mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_url_view")) + .waitForExists(waitingTime) + onView( + allOf( + withText(expectedText), + withId(R.id.mozac_browser_toolbar_edit_url_view), + ), + ).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + } class Transition { private lateinit var sessionLoadedIdlingResource: SessionLoadedIdlingResource @@ -276,9 +361,17 @@ class SearchRobot { return BrowserRobot.Transition() } - fun goToSearchEngine(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition { - NavigationToolbarRobot().interact() - return NavigationToolbarRobot.Transition() + fun clickSearchEngineSettings( + rule: ComposeTestRule, + interact: SettingsSubMenuSearchRobot.() -> Unit, + ): SettingsSubMenuSearchRobot.Transition { + rule.onNodeWithText("Search engine settings") + .assertIsDisplayed() + .assertHasClickAction() + .performClick() + + SettingsSubMenuSearchRobot().interact() + return SettingsSubMenuSearchRobot.Transition() } } } @@ -300,35 +393,12 @@ private fun clearButton() = private fun searchWrapper() = mDevice.findObject(UiSelector().resourceId("$packageName:id/search_wrapper")) -private fun assertSearchEngineResults(rule: ComposeTestRule, searchSuggestion: String, searchEngineName: String) { - rule.waitUntil(waitingTime, waitForSearchSuggestions(rule, searchSuggestion, searchEngineName)) - rule.onNodeWithText(searchSuggestion).assertIsDisplayed() -} - -private fun waitForSearchSuggestions(rule: ComposeTestRule, searchSuggestion: String, searchEngineName: String): () -> Boolean = - { - rule.waitForIdle() - mDevice.waitForObjects(mDevice.findObject(UiSelector().textContains(searchSuggestion))) - rule.onAllNodesWithTag("mozac.awesomebar.suggestion").assertAny(hasText(searchSuggestion) and hasText(searchEngineName)) - mDevice.findObject(UiSelector().textContains(searchSuggestion)).waitForExists(waitingTime) - } - -private fun assertSearchEngineSuggestionResults(rule: ComposeTestRule, searchResult: String) { - rule.waitForIdle() - - assertTrue( - mDevice.findObject(UiSelector().textContains(searchResult)) - .waitForExists(waitingTime), - ) -} - -private fun assertNoSuggestionsAreDisplayed(rule: ComposeTestRule, searchTerm: String) { +private fun assertSearchEnginePrompt(rule: ComposeTestRule, searchEngineName: String) { rule.waitForIdle() - - assertFalse( - mDevice.findObject(UiSelector().textContains(searchTerm)) - .waitForExists(waitingTime), - ) + rule.onNodeWithText("Search $searchEngineName").assertIsDisplayed() + rule.onNodeWithText( + getStringResource(R.string.search_engine_suggestions_description), + ).assertIsDisplayed() } private fun assertSearchView() = @@ -357,14 +427,6 @@ private fun assertSearchButton() = ).waitForExists(waitingTime), ) -private fun assertSearchWithText() = - onView(allOf(withText("THIS TIME, SEARCH WITH:"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - -private fun assertSearchSettings() = - onView(allOf(withText("Default search engine"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) - private fun assertSearchBarEmpty() = assertTrue( mDevice.findObject( @@ -462,25 +524,16 @@ private fun assertDefaultSearchEngine(expectedText: String) = ).waitForExists(waitingTime), ) -private fun assertPastedToolbarText(expectedText: String) { - mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar")) - .waitForExists(waitingTime) - mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_url_view")) - .waitForExists(waitingTime) - onView( - allOf( - withSubstring(expectedText), - withId(R.id.mozac_browser_toolbar_edit_url_view), - ), - ).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} +private fun assertTranslatedFocusedNavigationToolbar(toolbarHintString: String) = + assertTrue( + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view") + .textContains(toolbarHintString), + ).waitForExists(waitingTime), + ) private val awesomeBar = mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view")) private val voiceSearchButton = mDevice.findObject(UiSelector().description("Voice search")) - -private val searchSuggestionsList = - UiScrollable( - UiSelector().className("android.widget.ScrollView"), - ) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt index 1b390d29d..0ce2f375d 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsRobot.kt @@ -44,6 +44,7 @@ import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.Constants.LISTS_MAXSWIPES import org.mozilla.fenix.helpers.Constants.PackageName.GOOGLE_PLAY_SERVICES +import org.mozilla.fenix.helpers.Constants.RETRY_COUNT import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.TestHelper.appName import org.mozilla.fenix.helpers.TestHelper.getStringResource @@ -575,7 +576,21 @@ private fun rateOnGooglePlayHeading(): UiObject { } private fun aboutFirefoxHeading(): UiObject { - settingsList().scrollToEnd(LISTS_MAXSWIPES) + for (i in 1..RETRY_COUNT) { + try { + settingsList().scrollToEnd(LISTS_MAXSWIPES) + assertTrue( + mDevice.findObject(UiSelector().text("About $appName")) + .waitForExists(waitingTime), + ) + + break + } catch (e: AssertionError) { + if (i == RETRY_COUNT) { + throw e + } + } + } return mDevice.findObject(UiSelector().text("About $appName")) } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuHomepageRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuHomepageRobot.kt index 18953d0e4..64f3eb2ba 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuHomepageRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuHomepageRobot.kt @@ -6,22 +6,24 @@ package org.mozilla.fenix.ui.robots import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.isChecked import androidx.test.espresso.matcher.ViewMatchers.isNotChecked -import androidx.test.espresso.matcher.ViewMatchers.withChild import androidx.test.espresso.matcher.ViewMatchers.withClassName import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.UiSelector +import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.allOf -import org.hamcrest.CoreMatchers.endsWith +import org.hamcrest.Matchers import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort +import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.click @@ -30,25 +32,46 @@ import org.mozilla.fenix.helpers.click */ class SettingsSubMenuHomepageRobot { - fun verifyHomePageView() { - assertMostVisitedTopSitesButton() + fun verifyHomePageView( + shortcutsSwitchEnabled: Boolean = true, + sponsoredShortcutsCheckBox: Boolean = true, + jumpBackInSwitchEnabled: Boolean = true, + recentBookmarksSwitchEnabled: Boolean = true, + recentlyVisitedSwitchEnabled: Boolean = true, + pocketSwitchEnabled: Boolean = true, + sponsoredStoriesCheckBox: Boolean = true, + ) { + assertShortcutsButton() + assertShortcutsSwitchState(shortcutsSwitchEnabled) + assertSponsoredShortcutsButton() + assertSponsoredShortcutsCheckBox(sponsoredShortcutsCheckBox) assertJumpBackInButton() + assertJumpBackInSwitchState(jumpBackInSwitchEnabled) assertRecentBookmarksButton() - assertRecentSearchesButton() + assertRecentBookmarksSwitchState(recentBookmarksSwitchEnabled) + assertRecentlyVisitedButton() + assertRecentlyVisitedSwitchState(recentlyVisitedSwitchEnabled) assertPocketButton() + assertPocketSwitchState(pocketSwitchEnabled) + assertSponsoredStoriesButton() + assertSponsoredStoriesCheckBox(sponsoredStoriesCheckBox) assertOpeningScreenHeading() assertHomepageButton() assertLastTabButton() assertHomepageAfterFourHoursButton() } - fun clickSponsoredShortcuts() = sponsoredShortcuts().click() + fun clickShortcutsButton() = shortcutsButton().click() + + fun clickSponsoredShortcuts() = sponsoredShortcutsButton().click() fun clickJumpBackInButton() = jumpBackInButton().click() + fun clickRecentlyVisited() = recentlyVisitedButton().click() + fun clickRecentBookmarksButton() = recentBookmarksButton().click() - fun clickRecentSearchesButton() = recentSearchesButton().click() + fun clickRecentSearchesButton() = recentlyVisitedButton().click() fun clickPocketButton() = pocketButton().click() @@ -69,37 +92,7 @@ class SettingsSubMenuHomepageRobot { ).waitForExists(waitingTimeShort), ) - fun verifySponsoredShortcutsCheckBox(checked: Boolean) { - if (checked) { - sponsoredShortcuts() - .check( - matches( - hasSibling( - withChild( - allOf( - withClassName(endsWith("CheckBox")), - isChecked(), - ), - ), - ), - ), - ) - } else { - sponsoredShortcuts() - .check( - matches( - hasSibling( - withChild( - allOf( - withClassName(endsWith("CheckBox")), - isNotChecked(), - ), - ), - ), - ), - ) - } - } + fun verifySponsoredShortcutsCheckBox(checked: Boolean) = assertSponsoredShortcutsCheckBox(checked) class Transition { @@ -121,10 +114,10 @@ class SettingsSubMenuHomepageRobot { } } -private fun mostVisitedTopSitesButton() = +private fun shortcutsButton() = onView(allOf(withText(R.string.top_sites_toggle_top_recent_sites_4))) -private fun sponsoredShortcuts() = +private fun sponsoredShortcutsButton() = onView(allOf(withText(R.string.customize_toggle_contile))) private fun jumpBackInButton() = @@ -133,11 +126,14 @@ private fun jumpBackInButton() = private fun recentBookmarksButton() = onView(allOf(withText(R.string.customize_toggle_recent_bookmarks))) -private fun recentSearchesButton() = +private fun recentlyVisitedButton() = onView(allOf(withText(R.string.customize_toggle_recently_visited))) private fun pocketButton() = - onView(allOf(withText(R.string.customize_toggle_pocket))) + onView(allOf(withText(R.string.customize_toggle_pocket_2))) + +private fun sponsoredStoriesButton() = + onView(allOf(withText(R.string.customize_toggle_pocket_sponsored))) private fun openingScreenHeading() = onView(withText(R.string.preferences_opening_screen)) @@ -170,16 +166,20 @@ private fun homepageAfterFourHoursButton() = private fun goBackButton() = onView(allOf(withContentDescription(R.string.action_bar_up_description))) -private fun assertMostVisitedTopSitesButton() = - mostVisitedTopSitesButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertShortcutsButton() = + shortcutsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertSponsoredShortcutsButton() = + sponsoredShortcutsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertJumpBackInButton() = jumpBackInButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertRecentBookmarksButton() = recentBookmarksButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertRecentSearchesButton() = - recentSearchesButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertRecentlyVisitedButton() = + recentlyVisitedButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertPocketButton() = pocketButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertSponsoredStoriesButton() = + sponsoredStoriesButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertOpeningScreenHeading() = openingScreenHeading().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertHomepageButton() = @@ -189,4 +189,208 @@ private fun assertLastTabButton() = private fun assertHomepageAfterFourHoursButton() = homepageAfterFourHoursButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +fun assertShortcutsSwitchState(enabled: Boolean) { + if (enabled) { + shortcutsButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isChecked(), + ), + ), + ), + ) + } else { + shortcutsButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isNotChecked(), + ), + ), + ), + ) + } +} + +fun assertSponsoredShortcutsCheckBox(checked: Boolean) { + if (checked) { + sponsoredShortcutsButton() + .check( + matches( + hasSibling( + ViewMatchers.withChild( + allOf( + withClassName(CoreMatchers.endsWith("CheckBox")), + isChecked(), + ), + ), + ), + ), + ) + } else { + sponsoredShortcutsButton() + .check( + matches( + hasSibling( + ViewMatchers.withChild( + allOf( + withClassName(CoreMatchers.endsWith("CheckBox")), + isNotChecked(), + ), + ), + ), + ), + ) + } +} + +fun assertJumpBackInSwitchState(enabled: Boolean) { + if (enabled) { + jumpBackInButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isChecked(), + ), + ), + ), + ) + } else { + jumpBackInButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isNotChecked(), + ), + ), + ), + ) + } +} + +fun assertRecentBookmarksSwitchState(enabled: Boolean) { + if (enabled) { + recentBookmarksButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isChecked(), + ), + ), + ), + ) + } else { + recentBookmarksButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isNotChecked(), + ), + ), + ), + ) + } +} + +fun assertRecentlyVisitedSwitchState(enabled: Boolean) { + if (enabled) { + recentlyVisitedButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isChecked(), + ), + ), + ), + ) + } else { + recentlyVisitedButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isNotChecked(), + ), + ), + ), + ) + } +} + +fun assertPocketSwitchState(enabled: Boolean) { + if (enabled) { + pocketButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isChecked(), + ), + ), + ), + ) + } else { + pocketButton() + .check( + matches( + TestHelper.hasCousin( + Matchers.allOf( + withClassName(Matchers.endsWith("Switch")), + isNotChecked(), + ), + ), + ), + ) + } +} + +fun assertSponsoredStoriesCheckBox(checked: Boolean) { + if (checked) { + sponsoredStoriesButton() + .check( + matches( + hasSibling( + ViewMatchers.withChild( + allOf( + withClassName(CoreMatchers.endsWith("CheckBox")), + isChecked(), + ), + ), + ), + ), + ) + } else { + sponsoredStoriesButton() + .check( + matches( + hasSibling( + ViewMatchers.withChild( + allOf( + withClassName(CoreMatchers.endsWith("CheckBox")), + isNotChecked(), + ), + ), + ), + ), + ) + } +} + private val wallpapersMenuButton = onView(withText("Wallpapers")) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuLoginsAndPasswordRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuLoginsAndPasswordRobot.kt index 103f6e5fe..ddb1ff91b 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuLoginsAndPasswordRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuLoginsAndPasswordRobot.kt @@ -110,5 +110,5 @@ private fun assertDefaultValueAutofillLogins(context: Context) = onView( private fun assertDefaultValueExceptions() = onView(ViewMatchers.withText("Exceptions")) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -private fun assertDefaultValueSyncLogins() = onView(ViewMatchers.withText("Sign in to Sync")) +private fun assertDefaultValueSyncLogins() = onView(ViewMatchers.withText("Sync and save data")) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt index 935b8b70d..102283070 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSearchRobot.kt @@ -15,6 +15,7 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withChild +import androidx.test.espresso.matcher.ViewMatchers.withClassName import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId @@ -23,13 +24,18 @@ import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.uiautomator.By import androidx.test.uiautomator.UiSelector import org.hamcrest.CoreMatchers +import org.hamcrest.CoreMatchers.not import org.hamcrest.Matchers.allOf +import org.hamcrest.Matchers.endsWith import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestHelper.getStringResource +import org.mozilla.fenix.helpers.TestHelper.hasCousin import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.click +import org.mozilla.fenix.helpers.isChecked /** * Implementation of Robot Pattern for the settings search sub menu. @@ -38,18 +44,90 @@ class SettingsSubMenuSearchRobot { fun verifySearchToolbar() = assertSearchToolbar() fun verifyDefaultSearchEngineHeader() = assertDefaultSearchEngineHeader() fun verifySearchEngineList() = assertSearchEngineList() - fun verifyShowSearchSuggestions() = assertShowSearchSuggestions() + + fun verifyShowSearchSuggestions() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText("Show search suggestions")), + ), + ) + onView(withText("Show search suggestions")) + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + } + fun verifyShowSearchShortcuts() = assertShowSearchShortcuts() - fun verifyShowClipboardSuggestions() = assertShowClipboardSuggestions() - fun verifySearchBrowsingHistory() = assertSearchBrowsingHistory() - fun verifySearchBookmarks() = assertSearchBookmarks() + + fun verifyShowClipboardSuggestionsDefault() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText(getStringResource(R.string.preferences_show_clipboard_suggestions))), + ), + ) + onView(withText(getStringResource(R.string.preferences_show_clipboard_suggestions))) + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + .check(matches(hasCousin(allOf(withClassName(endsWith("Switch")), isChecked(true))))) + } + + fun toggleClipboardSuggestion() { + onView(withText(getStringResource(R.string.preferences_show_clipboard_suggestions))) + .click() + } + + fun verifySearchBrowsingHistory() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText("Search browsing history")), + ), + ) + searchHistoryToggle + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + } + + fun verifySearchBookmarks() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText("Search bookmarks")), + ), + ) + searchBookmarksToggle + .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + } fun changeDefaultSearchEngine(searchEngineName: String) = selectSearchEngine(searchEngineName) - fun disableShowSearchSuggestions() = toggleShowSearchSuggestions() + fun toggleAutocomplete() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText(getStringResource(R.string.preferences_enable_autocomplete_urls))), + ), + ) + + onView(withText(getStringResource(R.string.preferences_enable_autocomplete_urls))) + .click() + } + + fun toggleShowSearchSuggestions() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText("Show search suggestions")), + ), + ) - fun enableShowSearchShortcuts() = toggleShowSearchShortcuts() + onView(withText("Show search suggestions")) + .perform(click()) + } + + fun toggleShowSearchShortcuts() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText("Show search engines")), + ), + ) + + onView(withText("Show search engines")) + .perform(click()) + } fun toggleVoiceSearch() { onView(withId(androidx.preference.R.id.recycler_view)).perform( @@ -78,12 +156,34 @@ class SettingsSubMenuSearchRobot { searchBookmarksToggle.click() } + fun toggleShowSuggestionsInPrivateSessions() { + onView(withId(androidx.preference.R.id.recycler_view)).perform( + RecyclerViewActions.scrollTo( + hasDescendant(withText(getStringResource(R.string.preferences_show_search_suggestions_in_private))), + ), + ) + onView(withText(getStringResource(R.string.preferences_show_search_suggestions_in_private))) + .click() + } + fun openAddSearchEngineMenu() = addSearchEngineButton().click() fun verifyAddSearchEngineList() = assertAddSearchEngineList() fun verifyEngineListContains(searchEngineName: String) = assertEngineListContains(searchEngineName) + fun verifyEngineListDoesNotContain(searchEngineName: String) = assertEngineListDoesNotContain(searchEngineName) + + fun verifyDefaultSearchEngine(searchEngineName: String) = assertDefaultSearchEngine(searchEngineName) + + fun verifyThreeDotButtonIsNotDisplayed(searchEngineName: String) = assertThreeDotButtonIsNotDisplayed(searchEngineName) + + fun verifyAddSearchEngineListContains(vararg searchEngines: String) { + for (searchEngine in searchEngines) { + assertEngineListContains(searchEngine) + } + } + fun saveNewSearchEngine() { addSearchEngineSaveButton().click() assertTrue( @@ -160,8 +260,26 @@ class SettingsSubMenuSearchRobot { threeDotMenu(searchEngineName).click() } + fun deleteMultipleSearchEngines(vararg searchEngines: String) { + for (searchEngine in searchEngines) { + openEngineOverflowMenu(searchEngine) + clickDeleteSearchEngine() + } + } + fun clickEdit() = onView(withText("Edit")).click() + fun clickDeleteSearchEngine() = + mDevice.findObject( + UiSelector().textContains(getStringResource(R.string.search_engine_delete)), + ).click() + + fun clickUndoSnackBarButton() = + mDevice.findObject( + UiSelector() + .resourceId("$packageName:id/snackbar_btn"), + ).click() + fun saveEditSearchEngine() { onView(withId(R.id.save_button)).click() assertTrue( @@ -171,6 +289,8 @@ class SettingsSubMenuSearchRobot { ) } + fun verifyShowSearchEnginesToggleState(enabled: Boolean) = assertShowSearchEnginesToggle(enabled) + class Transition { fun goBack(interact: SettingsRobot.() -> Unit): SettingsRobot.Transition { mDevice.waitForIdle() @@ -215,16 +335,6 @@ private fun assertSearchEngineList() { .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun assertShowSearchSuggestions() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Show search suggestions")), - ), - ) - onView(withText("Show search suggestions")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} - private fun assertShowSearchShortcuts() { onView(withId(androidx.preference.R.id.recycler_view)).perform( RecyclerViewActions.scrollTo( @@ -235,38 +345,8 @@ private fun assertShowSearchShortcuts() { .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) } -private fun assertShowClipboardSuggestions() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Show clipboard suggestions")), - ), - ) - onView(withText("Show clipboard suggestions")) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} - -private fun assertSearchBrowsingHistory() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Search browsing history")), - ), - ) - searchHistoryToggle - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} - private val searchHistoryToggle = onView(withText("Search browsing history")) -private fun assertSearchBookmarks() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Search bookmarks")), - ), - ) - searchBookmarksToggle - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) -} - private val searchBookmarksToggle = onView(withText("Search bookmarks")) private fun selectSearchEngine(searchEngine: String) { @@ -275,28 +355,6 @@ private fun selectSearchEngine(searchEngine: String) { .perform(click()) } -private fun toggleShowSearchSuggestions() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Show search suggestions")), - ), - ) - - onView(withText("Show search suggestions")) - .perform(click()) -} - -private fun toggleShowSearchShortcuts() { - onView(withId(androidx.preference.R.id.recycler_view)).perform( - RecyclerViewActions.scrollTo( - hasDescendant(withText("Show search engines")), - ), - ) - - onView(withText("Show search engines")) - .perform(click()) -} - private fun goBackButton() = onView(CoreMatchers.allOf(withContentDescription("Navigate up"))) @@ -314,6 +372,48 @@ private fun assertEngineListContains(searchEngineName: String) { onView(withId(R.id.search_engine_group)).check(matches(hasDescendant(withText(searchEngineName)))) } +private fun assertDefaultSearchEngine(searchEngineName: String) = + onView( + allOf( + withId(R.id.radio_button), + withParent(withChild(withText(searchEngineName))), + ), + ).check(matches(isChecked(true))) + +private fun assertEngineListDoesNotContain(searchEngineName: String) { + onView(withId(R.id.search_engine_group)).check(matches(not(hasDescendant(withText(searchEngineName))))) +} + +private fun assertThreeDotButtonIsNotDisplayed(searchEngineName: String) = + threeDotMenu(searchEngineName).check(matches(not(isDisplayed()))) + +private fun assertShowSearchEnginesToggle(enabled: Boolean) = + if (enabled) { + onView(withText(R.string.preferences_show_search_engines)) + .check( + matches( + hasCousin( + allOf( + withClassName(endsWith("Switch")), + ViewMatchers.isChecked(), + ), + ), + ), + ) + } else { + onView(withText(R.string.preferences_show_search_engines)) + .check( + matches( + hasCousin( + allOf( + withClassName(endsWith("Switch")), + ViewMatchers.isNotChecked(), + ), + ), + ), + ) + } + private fun threeDotMenu(searchEngineName: String) = onView( allOf( diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt index b64e4ad31..22d31aec8 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SettingsSubMenuSitePermissionsCommonRobot.kt @@ -17,9 +17,9 @@ import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime -import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.TestHelper.getStringResource +import org.mozilla.fenix.helpers.TestHelper.mDevice import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.assertIsChecked import org.mozilla.fenix.helpers.click diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt index 3e35bca01..c204c23dc 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/SitePermissionsRobot.kt @@ -6,6 +6,7 @@ package org.mozilla.fenix.ui.robots import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.uiautomator.UiSelector @@ -82,6 +83,16 @@ class SitePermissionsRobot { } } + fun verifyCrossOriginCookiesPermissionPrompt(originSite: String, currentSite: String) { + mDevice.findObject(UiSelector().text("Allow $originSite to use its cookies on $currentSite?")) + .waitForExists(waitingTime) + onView(ViewMatchers.withText("Allow $originSite to use its cookies on $currentSite?")).check(matches(isDisplayed())) + onView(ViewMatchers.withText("You may want to block access if it's not clear why $originSite needs this data.")).check(matches(isDisplayed())) + onView(ViewMatchers.withText("Learn more")).check(matches(isDisplayed())) + onView(ViewMatchers.withText("Block")).check(matches(isDisplayed())) + onView(ViewMatchers.withText("Allow")).check(matches(isDisplayed())) + } + fun selectRememberPermissionDecision() { onView(withId(R.id.do_not_ask_again)) .check(matches(isDisplayed())) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt index 57528dae2..89088f6a9 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/TabDrawerRobot.kt @@ -33,17 +33,18 @@ import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until.findObject import com.google.android.material.bottomsheet.BottomSheetBehavior import junit.framework.AssertionFailedError +import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.anyOf import org.hamcrest.CoreMatchers.containsString import org.hamcrest.Matcher import org.mozilla.fenix.R -import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeLong import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort -import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.mDevice +import org.mozilla.fenix.helpers.TestHelper.packageName import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.clickAtLocationInView @@ -78,6 +79,7 @@ class TabDrawerRobot { assertSyncedTabsButtonIsSelected(isSelected) fun verifyExistingOpenTabs(vararg titles: String) = assertExistingOpenTabs(*titles) + fun verifyNoExistingOpenTabs(vararg titles: String) = assertNoExistingOpenTabs(*titles) fun verifyCloseTabsButton(title: String) = assertCloseTabsButton(title) fun verifyExistingTabList() = assertExistingTabList() @@ -338,19 +340,19 @@ class TabDrawerRobot { return BrowserRobot.Transition() } - fun openTabFromGroup( - title: String, + // Temporary method to use indexes instead of tab titles, until the compose migration is complete + fun openTabWithIndex( + tabPosition: Int, interact: BrowserRobot.() -> Unit, ): BrowserRobot.Transition { - val tab = UiScrollable(UiSelector().resourceId("$packageName:id/tab_group_list")) - .setAsHorizontalList() - .getChildByText( - UiSelector() - .resourceId("$packageName:id/mozac_browser_tabstray_title") - .textContains(title), - title, - true, - ) + val tab = mDevice.findObject( + UiSelector() + .className("androidx.compose.ui.platform.ComposeView") + .index(tabPosition), + ) + + UiScrollable(UiSelector().resourceId("$packageName:id/tray_list_item")).scrollIntoView(tab) + tab.waitForExists(waitingTime) tab.click() BrowserRobot().interact() @@ -451,7 +453,7 @@ private fun tabMediaControlButton() = mDevice.findObject(UiSelector().resourceId("$packageName:id/play_pause_button")) private fun closeTabButton() = - mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_tabstray_close")) + mDevice.findObject(UiSelector().descriptionContains("Close tab")) private fun assertCloseTabsButton(title: String) = assertTrue( @@ -490,6 +492,14 @@ private fun assertExistingOpenTabs(vararg tabTitles: String) { } } +private fun assertNoExistingOpenTabs(vararg tabTitles: String) { + for (title in tabTitles) { + assertFalse( + tabItem(title).waitForExists(waitingTimeLong), + ) + } +} + private fun assertExistingTabList() { mDevice.findObject( UiSelector().resourceId("$packageName:id/tabsTray"), @@ -497,7 +507,7 @@ private fun assertExistingTabList() { assertTrue( mDevice.findObject( - UiSelector().resourceId("$packageName:id/tab_item"), + UiSelector().resourceId("$packageName:id/tray_list_item"), ).waitForExists(waitingTime), ) } @@ -623,8 +633,7 @@ private fun tab(title: String) = private fun tabItem(title: String) = mDevice.findObject( UiSelector() - .resourceId("$packageName:id/tab_item") - .childSelector(UiSelector().text(title)), + .textContains(title), ) private fun tabsCounter() = onView(withId(R.id.tab_button)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuBookmarksRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuBookmarksRobot.kt index 2c13ba626..035aa87ff 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuBookmarksRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuBookmarksRobot.kt @@ -52,6 +52,20 @@ class ThreeDotMenuBookmarksRobot { return TabDrawerRobot.Transition() } + fun clickOpenAllInTabs(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { + openAllInTabsButton().click() + + TabDrawerRobot().interact() + return TabDrawerRobot.Transition() + } + + fun clickOpenAllInPrivateTabs(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition { + openAllInPrivateTabsButton().click() + + TabDrawerRobot().interact() + return TabDrawerRobot.Transition() + } + fun clickDelete(interact: BookmarksRobot.() -> Unit): BookmarksRobot.Transition { deleteButton().click() @@ -71,4 +85,8 @@ private fun openInNewTabButton() = onView(withText("Open in new tab")) private fun openInPrivateTabButton() = onView(withText("Open in private tab")) +private fun openAllInTabsButton() = onView(withText("Open all in new tabs")) + +private fun openAllInPrivateTabsButton() = onView(withText("Open all in private tabs")) + private fun deleteButton() = onView(withText("Delete")) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt index 865e17ada..1e5f6f114 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt @@ -50,7 +50,7 @@ class ThreeDotMenuMainRobot { fun verifyAddOnsButton() = assertAddOnsButton() fun verifyHistoryButton() = assertHistoryButton() fun verifyBookmarksButton() = assertBookmarksButton() - fun verifySyncSignInButton() = assertSignInToSyncButton() + fun verifySyncSignInButton() = assertSyncSignInButton() fun verifyHelpButton() = assertHelpButton() fun verifyThreeDotMenuExists() = threeDotMenuRecyclerViewExists() fun verifyForwardButton() = assertForwardButton() @@ -77,7 +77,6 @@ class ThreeDotMenuMainRobot { fun verifyDesktopSite() = assertDesktopSite() fun verifyDownloadsButton() = assertDownloadsButton() fun verifyShareTabsOverlay() = assertShareTabsOverlay() - fun verifySignInToSyncButton() = assertSignInToSyncButton() fun verifyNewTabButton() = assertNormalBrowsingNewTabButton() fun verifyReportSiteIssueButton() = assertReportSiteIssueButton() @@ -97,7 +96,7 @@ class ThreeDotMenuMainRobot { verifyHistoryButton() verifyDownloadsButton() verifyAddOnsButton() - verifySignInToSyncButton() + verifySyncSignInButton() threeDotMenuRecyclerView().perform(swipeUp()) verifyFindInPageButton() verifyDesktopSite() @@ -173,8 +172,8 @@ class ThreeDotMenuMainRobot { fun openSyncSignIn(interact: SyncSignInRobot.() -> Unit): SyncSignInRobot.Transition { threeDotMenuRecyclerView().perform(swipeDown()) - mDevice.waitNotNull(Until.findObject(By.text("Sign in to sync")), waitingTime) - signInToSyncButton().click() + mDevice.waitNotNull(Until.findObject(By.text("Sync and save data")), waitingTime) + syncSignInButton().click() SyncSignInRobot().interact() return SyncSignInRobot.Transition() @@ -208,6 +207,14 @@ class ThreeDotMenuMainRobot { return BrowserRobot.Transition() } + fun editBookmarkPage(interact: BookmarksRobot.() -> Unit): BookmarksRobot.Transition { + mDevice.waitNotNull(Until.findObject(By.text("Bookmarks")), waitingTime) + editBookmarkButton().click() + + BookmarksRobot().interact() + return BookmarksRobot.Transition() + } + fun openHelp(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { mDevice.waitNotNull(Until.findObject(By.text("Help")), waitingTime) helpButton().click() @@ -440,8 +447,8 @@ private fun bookmarksButton() = onView(allOf(withText(R.string.library_bookmarks private fun assertBookmarksButton() = bookmarksButton() .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun signInToSyncButton() = onView(withText("Sign in to sync")) -private fun assertSignInToSyncButton() = signInToSyncButton().check(matches(isDisplayed())) +private fun syncSignInButton() = onView(withText("Sync and save data")) +private fun assertSyncSignInButton() = syncSignInButton().check(matches(isDisplayed())) private fun helpButton() = onView(allOf(withText(R.string.browser_menu_help))) private fun assertHelpButton() = helpButton() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt index 4e92643b3..729200c54 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/util/Strings.kt @@ -8,6 +8,7 @@ const val STRING_ONBOARDING_ACCOUNT_SIGN_IN_HEADER = "Pick up where you left off const val STRING_ONBOARDING_TRACKING_PROTECTION_HEADER = "Privacy protection by default" const val STRING_ONBOARDING_TOOLBAR_PLACEMENT_HEADER = "Pick your toolbar placement" const val FRENCH_LANGUAGE_HEADER = "Langues" +const val ROMANIAN_LANGUAGE_HEADER = "Limbă" +const val ARABIC_LANGUAGE_HEADER = "اللغة" const val FR_SETTINGS = "Paramètres" const val FRENCH_SYSTEM_LOCALE_OPTION = "Utiliser la langue de l’appareil" -const val ROMANIAN_LANGUAGE_HEADER = "Limbă" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1be77d026..e433e95c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,6 +19,9 @@ + + + diff --git a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt index ba17bcf10..03c67bff5 100644 --- a/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt +++ b/app/src/main/java/org/mozilla/fenix/FeatureFlags.kt @@ -12,6 +12,14 @@ import mozilla.components.support.locale.LocaleManager.getSystemDefault * A single source for setting feature flags that are mostly based on build type. */ object FeatureFlags { + + /** + * Enables custom extension collection feature, + * This feature does not only depend on this flag. It requires the AMO collection override to + * be enabled which is behind the Secret Settings. + * */ + val customExtensionCollectionFeature = Config.channel.isNightlyOrDebug || Config.channel.isBeta + /** * Pull-to-refresh allows you to pull the web content down far enough to have the page to * reload. @@ -58,11 +66,6 @@ object FeatureFlags { */ const val inactiveTabs = true - /** - * Allows tabs to be dragged around as long as tab groups are disabled - */ - val tabReorderingFeature = Config.channel.isNightlyOrDebug - /** * Show Pocket recommended stories on home. */ @@ -84,11 +87,6 @@ object FeatureFlags { */ const val showHomeOnboarding = true - /** - * Enables history improvement features. - */ - const val historyImprovementFeatures = true - /** * Enables the Task Continuity enhancements. */ @@ -118,4 +116,16 @@ object FeatureFlags { * Enables the wallpaper v2 enhancements. */ const val wallpaperV2Enabled = true + + /** + * Enables the save to PDF feature. + */ + const val saveToPDF = true + + /** + * Enables storage maintenance feature. + * + * Feature flag tracking: https://github.com/mozilla-mobile/fenix/issues/27759 + * */ + val storageMaintenanceFeature = Config.channel.isNightlyOrDebug } diff --git a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt index 0ae4b06c0..fb7ac86bd 100644 --- a/app/src/main/java/org/mozilla/fenix/FenixApplication.kt +++ b/app/src/main/java/org/mozilla/fenix/FenixApplication.kt @@ -14,6 +14,7 @@ import android.util.Log.INFO import androidx.annotation.CallSuper import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AppCompatDelegate +import androidx.core.app.NotificationManagerCompat import androidx.core.content.getSystemService import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration.Builder @@ -28,6 +29,7 @@ import mozilla.appservices.Megazord import mozilla.components.browser.state.action.SystemAction import mozilla.components.browser.state.selector.selectedTab import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.browser.storage.sync.GlobalPlacesDependencyProvider import mozilla.components.concept.base.crash.Breadcrumb import mozilla.components.concept.engine.webextension.WebExtension import mozilla.components.concept.engine.webextension.isUnsupported @@ -75,8 +77,10 @@ import org.mozilla.fenix.components.metrics.MetricServiceType import org.mozilla.fenix.components.metrics.MozillaProductDetector import org.mozilla.fenix.components.toolbar.ToolbarPosition import org.mozilla.fenix.ext.containsQueryParameters +import org.mozilla.fenix.ext.getCustomGleanServerUrlIfAvailable import org.mozilla.fenix.ext.isCustomEngine import org.mozilla.fenix.ext.isKnownSearchDomain +import org.mozilla.fenix.ext.setCustomEndpointIfAvailable import org.mozilla.fenix.ext.settings import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.perf.MarkersActivityLifecycleCallbacks @@ -93,7 +97,7 @@ import org.mozilla.fenix.telemetry.TelemetryLifecycleObserver import org.mozilla.fenix.utils.BrowsersCache import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD -import org.mozilla.fenix.wallpapers.WallpaperManager +import org.mozilla.fenix.wallpapers.Wallpaper import java.util.UUID import java.util.concurrent.TimeUnit @@ -154,14 +158,24 @@ open class FenixApplication : LocaleAwareApplication(), Provider { logger.debug("Initializing Glean (uploadEnabled=$telemetryEnabled})") + // for performance reasons, this is only available in Nightly or Debug builds + val customEndpoint = if (Config.channel.isNightlyOrDebug) { + // for testing, if custom glean server url is set in the secret menu, use it to initialize Glean + getCustomGleanServerUrlIfAvailable(this) + } else { + null + } + + val configuration = Configuration( + channel = BuildConfig.BUILD_TYPE, + httpClient = ConceptFetchHttpUploader( + lazy(LazyThreadSafetyMode.NONE) { components.core.client }, + ), + ) + Glean.initialize( applicationContext = this, - configuration = Configuration( - channel = BuildConfig.BUILD_TYPE, - httpClient = ConceptFetchHttpUploader( - lazy(LazyThreadSafetyMode.NONE) { components.core.client }, - ), - ), + configuration = configuration.setCustomEndpointIfAvailable(customEndpoint), uploadEnabled = telemetryEnabled, buildInfo = GleanBuildInfo.buildInfo, ) @@ -198,6 +212,14 @@ open class FenixApplication : LocaleAwareApplication(), Provider { components.core.engine.warmUp() } initializeWebExtensionSupport() + if (FeatureFlags.storageMaintenanceFeature) { + // Make sure to call this function before registering a storage worker + // (e.g. components.core.historyStorage.registerStorageMaintenanceWorker()) + // as the storage maintenance worker needs a places storage globally when + // it is needed while the app is not running and WorkManager wakes up the app + // for the periodic task. + GlobalPlacesDependencyProvider.initialize(components.core.historyStorage) + } restoreBrowserState() restoreDownloads() @@ -217,12 +239,6 @@ open class FenixApplication : LocaleAwareApplication(), Provider { registerActivityLifecycleCallbacks(visibilityLifecycleCallback) registerActivityLifecycleCallbacks(MarkersActivityLifecycleCallbacks(components.core.engine)) - // Storage maintenance disabled, for now, as it was interfering with background migrations. - // See https://github.com/mozilla-mobile/fenix/issues/7227 for context. - // if ((System.currentTimeMillis() - settings().lastPlacesStorageMaintenance) > ONE_DAY_MILLIS) { - // runStorageMaintenance() - // } - components.appStartReasonProvider.registerInAppOnCreate(this) components.startupActivityLog.registerInAppOnCreate(this) initVisualCompletenessQueueAndQueueTasks() @@ -331,6 +347,18 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } } + fun queueStorageMaintenance() { + if (FeatureFlags.storageMaintenanceFeature) { + queue.runIfReadyOrQueue { + // Make sure GlobalPlacesDependencyProvider.initialize(components.core.historyStorage) + // is called before this call. When app is not running and WorkManager wakes up + // the app for the periodic task, it will require a globally provided places storage + // to run the maintenance on. + components.core.historyStorage.registerStorageMaintenanceWorker() + } + } + } + initQueue() // We init these items in the visual completeness queue to avoid them initing in the critical @@ -339,6 +367,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider { queueMetrics() queueReviewPrompt() queueRestoreLocale() + queueStorageMaintenance() } private fun startMetricsIfEnabled() { @@ -351,20 +380,6 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } } - // See https://github.com/mozilla-mobile/fenix/issues/7227 for context. - // To re-enable this, we need to do so in a way that won't interfere with any startup operations - // which acquire reserved+ sqlite lock. Currently, Fennec migrations need to write to storage - // on startup, and since they run in a background service we can't simply order these operations. - // @OptIn(DelicateCoroutinesApi::class) // GlobalScope usage - // private fun runStorageMaintenance() { - // GlobalScope.launch(Dispatchers.IO) { - // // Bookmarks and history storage sit on top of the same db file so we only need to - // // run maintenance on one - arbitrarily using bookmarks. - // // components.core.bookmarksStorage.runMaintenance() - // } - // settings().lastPlacesStorageMaintenance = System.currentTimeMillis() - // } - protected open fun setupLeakCanary() { // no-op, LeakCanary is disabled by default } @@ -711,7 +726,19 @@ open class FenixApplication : LocaleAwareApplication(), Provider { } installSource.set(installSourcePackage.orEmpty()) - defaultWallpaper.set(WallpaperManager.isDefaultTheCurrentWallpaper(settings)) + val isDefaultTheCurrentWallpaper = + Wallpaper.nameIsDefault(settings.currentWallpaperName) + + defaultWallpaper.set(isDefaultTheCurrentWallpaper) + + @Suppress("TooGenericExceptionCaught") + try { + notificationsAllowed.set( + NotificationManagerCompat.from(applicationContext).areNotificationsEnabled(), + ) + } catch (e: Exception) { + Logger.warn("Failed to check if notifications are enabled", e) + } } with(AndroidAutofill) { diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index fc70fd044..9f849d6f5 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -25,7 +25,7 @@ import android.view.WindowManager.LayoutParams.FLAG_SECURE import androidx.annotation.CallSuper import androidx.annotation.IdRes import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PROTECTED +import androidx.annotation.VisibleForTesting.Companion.PROTECTED import androidx.appcompat.app.ActionBar import androidx.appcompat.widget.Toolbar import androidx.lifecycle.lifecycleScope @@ -78,6 +78,7 @@ import org.mozilla.fenix.addons.AddonPermissionsDetailsFragmentDirections import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.DefaultBrowsingModeManager +import org.mozilla.fenix.components.appstate.AppAction import org.mozilla.fenix.components.metrics.BreadcrumbsRecorder import org.mozilla.fenix.databinding.ActivityHomeBinding import org.mozilla.fenix.exceptions.trackingprotection.TrackingProtectionExceptionsFragmentDirections @@ -370,6 +371,11 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { Events.defaultBrowserChanged.record(NoExtras()) } + // We attempt to send metrics onResume so that the start of new user sessions is not + // missed. Previously, this was done in FenixApplication::onCreate, but it was decided + // that we should not rely on the application being killed between user sessions. + components.appStore.dispatch(AppAction.ResumedMetricsAction) + DefaultBrowserNotificationWorker.setDefaultBrowserNotificationIfNeeded(applicationContext) } } diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonPopupBaseFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonPopupBaseFragment.kt index 8fbd32ab4..ccee01685 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonPopupBaseFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonPopupBaseFragment.kt @@ -10,10 +10,10 @@ import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import mozilla.components.browser.state.action.ContentAction import mozilla.components.browser.state.action.CustomTabListAction -import mozilla.components.browser.state.state.createCustomTab import mozilla.components.browser.state.state.CustomTabSessionState import mozilla.components.browser.state.state.EngineState import mozilla.components.browser.state.state.SessionState +import mozilla.components.browser.state.state.createCustomTab import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.prompt.PromptRequest import mozilla.components.concept.engine.window.WindowRequest diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt index 1a19a55bf..dd21b2978 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonsManagementFragment.kt @@ -40,9 +40,9 @@ import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.databinding.FragmentAddOnsManagementBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getRootView +import org.mozilla.fenix.ext.runIfFragmentIsAttached import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar -import org.mozilla.fenix.ext.runIfFragmentIsAttached import org.mozilla.fenix.theme.ThemeManager import java.lang.ref.WeakReference import java.util.concurrent.CancellationException diff --git a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt index 7eb06ba7a..7c009bc30 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/InstalledAddonDetailsFragment.kt @@ -8,6 +8,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.annotation.VisibleForTesting import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -17,7 +18,9 @@ import androidx.navigation.fragment.findNavController import com.google.android.material.switchmaterial.SwitchMaterial import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import mozilla.components.concept.engine.webextension.EnableSource import mozilla.components.feature.addons.Addon +import mozilla.components.feature.addons.AddonManager import mozilla.components.feature.addons.AddonManagerException import mozilla.components.feature.addons.ui.translateName import org.mozilla.fenix.HomeActivity @@ -32,7 +35,8 @@ import org.mozilla.fenix.ext.showToolbar */ @Suppress("LargeClass", "TooManyFunctions") class InstalledAddonDetailsFragment : Fragment() { - private lateinit var addon: Addon + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal lateinit var addon: Addon private var _binding: FragmentInstalledAddOnDetailsBinding? = null private val binding get() = _binding!! @@ -124,8 +128,8 @@ class InstalledAddonDetailsFragment : Fragment() { switch.isClickable = false binding.removeAddOn.isEnabled = false if (isChecked) { - addonManager.enableAddon( - addon, + enableAddon( + addonManager, onSuccess = { runIfFragmentIsAttached { this.addon = it @@ -207,6 +211,28 @@ class InstalledAddonDetailsFragment : Fragment() { } } + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun enableAddon( + addonManager: AddonManager, + onSuccess: (Addon) -> Unit, + onError: (Throwable) -> Unit, + ) { + // If the addon is migrated from Fennec and supported in Fenix, for the addon to be enabled, + // we need to also request the addon to be enabled as supported by the app + if (addon.isSupported() && addon.isDisabledAsUnsupported()) { + addonManager.enableAddon( + addon, + EnableSource.APP_SUPPORT, + { enabledAddon -> + addonManager.enableAddon(enabledAddon, EnableSource.USER, onSuccess, onError) + }, + onError, + ) + } else { + addonManager.enableAddon(addon, EnableSource.USER, onSuccess, onError) + } + } + private fun bindSettings() { binding.settings.apply { isVisible = shouldSettingsBeVisible() diff --git a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 3c4a45c8d..1be9447b3 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -39,7 +39,7 @@ import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mozilla.appservices.places.BookmarkRoot -import mozilla.appservices.places.uniffi.PlacesException +import mozilla.appservices.places.uniffi.PlacesApiException import mozilla.components.browser.state.action.ContentAction import mozilla.components.browser.state.selector.findCustomTab import mozilla.components.browser.state.selector.findCustomTabOrSelectedTab @@ -54,6 +54,7 @@ import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.content.DownloadState import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.thumbnails.BrowserThumbnails +import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.feature.accounts.FxaCapability import mozilla.components.feature.accounts.FxaWebChannelFeature @@ -68,31 +69,38 @@ import mozilla.components.feature.media.fullscreen.MediaSessionFullscreenFeature import mozilla.components.feature.privatemode.feature.SecureWindowFeature import mozilla.components.feature.prompts.PromptFeature import mozilla.components.feature.prompts.PromptFeature.Companion.PIN_REQUEST +import mozilla.components.feature.prompts.address.AddressDelegate +import mozilla.components.feature.prompts.creditcard.CreditCardDelegate +import mozilla.components.feature.prompts.login.LoginDelegate import mozilla.components.feature.prompts.share.ShareDelegate import mozilla.components.feature.readerview.ReaderViewFeature import mozilla.components.feature.search.SearchFeature import mozilla.components.feature.session.FullScreenFeature import mozilla.components.feature.session.PictureInPictureFeature +import mozilla.components.feature.session.ScreenOrientationFeature import mozilla.components.feature.session.SessionFeature import mozilla.components.feature.session.SwipeRefreshFeature -import mozilla.components.concept.engine.permission.SitePermissions -import mozilla.components.feature.prompts.address.AddressDelegate -import mozilla.components.feature.prompts.creditcard.CreditCardDelegate -import mozilla.components.feature.prompts.login.LoginDelegate -import mozilla.components.feature.session.ScreenOrientationFeature +import mozilla.components.feature.session.behavior.EngineViewBrowserToolbarBehavior import mozilla.components.feature.sitepermissions.SitePermissionsFeature +import mozilla.components.feature.webauthn.WebAuthnFeature import mozilla.components.lib.state.ext.consumeFlow import mozilla.components.lib.state.ext.flowScoped +import mozilla.components.service.glean.private.NoExtras +import mozilla.components.service.sync.autofill.DefaultCreditCardValidationDelegate import mozilla.components.service.sync.logins.DefaultLoginValidationDelegate +import mozilla.components.support.base.feature.ActivityResultHandler import mozilla.components.support.base.feature.PermissionsFeature import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper +import mozilla.components.support.ktx.android.view.enterToImmersiveMode import mozilla.components.support.ktx.android.view.exitImmersiveMode import mozilla.components.support.ktx.android.view.hideKeyboard +import mozilla.components.support.ktx.kotlin.getOrigin import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.FeatureFlags +import org.mozilla.fenix.GleanMetrics.MediaState import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.IntentReceiverActivity import org.mozilla.fenix.NavGraphDirections @@ -109,6 +117,10 @@ import org.mozilla.fenix.components.toolbar.BrowserToolbarView import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarController import org.mozilla.fenix.components.toolbar.DefaultBrowserToolbarMenuController import org.mozilla.fenix.components.toolbar.ToolbarIntegration +import org.mozilla.fenix.components.toolbar.interactor.BrowserToolbarInteractor +import org.mozilla.fenix.components.toolbar.interactor.DefaultBrowserToolbarInteractor +import org.mozilla.fenix.crashes.CrashContentIntegration +import org.mozilla.fenix.databinding.FragmentBrowserBinding import org.mozilla.fenix.downloads.DownloadService import org.mozilla.fenix.downloads.DynamicDownloadDialog import org.mozilla.fenix.ext.accessibilityManager @@ -118,32 +130,19 @@ import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.hideToolbar import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents -import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.runIfFragmentIsAttached +import org.mozilla.fenix.ext.secure +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.HomeScreenViewModel import org.mozilla.fenix.home.SharedViewModel import org.mozilla.fenix.onboarding.FenixOnboarding +import org.mozilla.fenix.perf.MarkersFragmentLifecycleCallbacks import org.mozilla.fenix.settings.SupportUtils +import org.mozilla.fenix.settings.biometric.BiometricPromptFeature import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.wifi.SitePermissionsWifiIntegration import java.lang.ref.WeakReference -import mozilla.components.feature.session.behavior.EngineViewBrowserToolbarBehavior -import mozilla.components.feature.webauthn.WebAuthnFeature -import mozilla.components.service.glean.private.NoExtras -import mozilla.components.service.sync.autofill.DefaultCreditCardValidationDelegate -import mozilla.components.support.base.feature.ActivityResultHandler -import mozilla.components.support.ktx.android.view.enterToImmersiveMode -import mozilla.components.support.ktx.kotlin.getOrigin -import org.mozilla.fenix.GleanMetrics.Downloads -import org.mozilla.fenix.GleanMetrics.MediaState -import org.mozilla.fenix.components.toolbar.interactor.BrowserToolbarInteractor -import org.mozilla.fenix.components.toolbar.interactor.DefaultBrowserToolbarInteractor -import org.mozilla.fenix.crashes.CrashContentIntegration -import org.mozilla.fenix.databinding.FragmentBrowserBinding -import org.mozilla.fenix.ext.secure -import org.mozilla.fenix.perf.MarkersFragmentLifecycleCallbacks -import org.mozilla.fenix.settings.biometric.BiometricPromptFeature import mozilla.components.feature.session.behavior.ToolbarPosition as MozacToolbarPosition /** @@ -529,10 +528,6 @@ abstract class BaseBrowserFragment : dynamicDownloadDialog.show() browserToolbarView.expand() - - if (downloadState.contentType == "application/pdf") { - Downloads.pdfDownloadCount.add() - } } } @@ -1321,7 +1316,7 @@ abstract class BaseBrowserFragment : .show() } } - } catch (e: PlacesException.UrlParseFailed) { + } catch (e: PlacesApiException.UrlParseFailed) { withContext(Main) { view?.let { FenixSnackbar.make( diff --git a/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt b/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt index bfb4c6b5c..81f7570c8 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver.kt @@ -38,7 +38,6 @@ class OpenInAppOnboardingObserver( private val settings: Settings, private val appLinksUseCases: AppLinksUseCases, private val container: ViewGroup, - @VisibleForTesting internal val shouldScrollWithTopToolbar: Boolean = false, ) : LifecycleAwareFeature { private var scope: CoroutineScope? = null diff --git a/app/src/main/java/org/mozilla/fenix/browser/SwipeGestureLayout.kt b/app/src/main/java/org/mozilla/fenix/browser/SwipeGestureLayout.kt index a1084602e..c34279ed1 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/SwipeGestureLayout.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/SwipeGestureLayout.kt @@ -106,8 +106,8 @@ class SwipeGestureLayout @JvmOverloads constructor( listeners.add(listener) } - override fun onInterceptTouchEvent(event: MotionEvent?): Boolean { - return when (event?.actionMasked) { + override fun onInterceptTouchEvent(event: MotionEvent): Boolean { + return when (event.actionMasked) { MotionEvent.ACTION_DOWN -> { handledInitialScroll = false gestureDetector.onTouchEvent(event) @@ -117,8 +117,8 @@ class SwipeGestureLayout @JvmOverloads constructor( } } - override fun onTouchEvent(event: MotionEvent?): Boolean { - return when (event?.actionMasked) { + override fun onTouchEvent(event: MotionEvent): Boolean { + return when (event.actionMasked) { MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> { gestureDetector.onTouchEvent(event) // If the active listener is not null here, then we haven't detected a fling diff --git a/app/src/main/java/org/mozilla/fenix/browser/infobanner/DynamicInfoBanner.kt b/app/src/main/java/org/mozilla/fenix/browser/infobanner/DynamicInfoBanner.kt index 72e296fc6..2a9621e26 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/infobanner/DynamicInfoBanner.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/infobanner/DynamicInfoBanner.kt @@ -6,7 +6,6 @@ package org.mozilla.fenix.browser.infobanner import android.content.Context import android.view.ViewGroup -import androidx.annotation.VisibleForTesting import androidx.coordinatorlayout.widget.CoordinatorLayout /** @@ -19,7 +18,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout class DynamicInfoBanner( private val context: Context, container: ViewGroup, - @VisibleForTesting internal val shouldScrollWithTopToolbar: Boolean = false, message: String, dismissText: String, diff --git a/app/src/main/java/org/mozilla/fenix/browser/infobanner/InfoBanner.kt b/app/src/main/java/org/mozilla/fenix/browser/infobanner/InfoBanner.kt index 6e8061ad6..b8df9f957 100644 --- a/app/src/main/java/org/mozilla/fenix/browser/infobanner/InfoBanner.kt +++ b/app/src/main/java/org/mozilla/fenix/browser/infobanner/InfoBanner.kt @@ -32,10 +32,8 @@ open class InfoBanner( private val dismissText: String, private val actionText: String? = null, private val dismissByHiding: Boolean = false, - @VisibleForTesting internal val dismissAction: (() -> Unit)? = null, - @VisibleForTesting - internal val actionToPerform: (() -> Unit)? = null, + private val actionToPerform: (() -> Unit)? = null, ) { @SuppressLint("InflateParams") @VisibleForTesting diff --git a/app/src/main/java/org/mozilla/fenix/components/Analytics.kt b/app/src/main/java/org/mozilla/fenix/components/Analytics.kt index e619965cc..1a6549702 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Analytics.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Analytics.kt @@ -10,10 +10,10 @@ import android.content.Context import android.content.Intent import android.os.Build import mozilla.components.lib.crash.CrashReporter +import mozilla.components.lib.crash.sentry.SentryService import mozilla.components.lib.crash.service.CrashReporterService import mozilla.components.lib.crash.service.GleanCrashReporterService import mozilla.components.lib.crash.service.MozillaSocorroService -import mozilla.components.lib.crash.sentry.SentryService import mozilla.components.service.nimbus.NimbusApi import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config @@ -22,15 +22,17 @@ import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.ReleaseChannel import org.mozilla.fenix.components.metrics.AdjustMetricsService +import org.mozilla.fenix.components.metrics.DefaultMetricsStorage import org.mozilla.fenix.components.metrics.GleanMetricsService import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.experiments.createNimbus import org.mozilla.fenix.ext.settings import org.mozilla.fenix.gleanplumb.CustomAttributeProvider -import org.mozilla.fenix.gleanplumb.OnDiskMessageMetadataStorage import org.mozilla.fenix.gleanplumb.NimbusMessagingStorage +import org.mozilla.fenix.gleanplumb.OnDiskMessageMetadataStorage import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.perf.lazyMonitored +import org.mozilla.fenix.utils.BrowsersCache import org.mozilla.geckoview.BuildConfig.MOZ_APP_BUILDID import org.mozilla.geckoview.BuildConfig.MOZ_APP_VENDOR import org.mozilla.geckoview.BuildConfig.MOZ_APP_VERSION @@ -119,7 +121,15 @@ class Analytics( MetricController.create( listOf( GleanMetricsService(context), - AdjustMetricsService(context as Application), + AdjustMetricsService( + application = context as Application, + storage = DefaultMetricsStorage( + context = context, + settings = context.settings(), + checkDefaultBrowser = { BrowsersCache.all(context).isDefaultBrowser }, + ), + crashReporter = crashReporter, + ), ), isDataTelemetryEnabled = { context.settings().isTelemetryEnabled }, isMarketingDataTelemetryEnabled = { context.settings().isMarketingTelemetryEnabled }, diff --git a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt index 5103bf20a..508fdd246 100644 --- a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt +++ b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.components import android.content.Context import android.os.Build import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import mozilla.components.browser.storage.sync.PlacesBookmarksStorage @@ -183,6 +183,7 @@ class BackgroundServices( // Enable push if it's configured. push.feature?.let { autoPushFeature -> FxaPushSupportFeature(context, accountManager, autoPushFeature, crashReporter) + .initialize() } SendTabFeature(accountManager) { device, tabs -> diff --git a/app/src/main/java/org/mozilla/fenix/components/Components.kt b/app/src/main/java/org/mozilla/fenix/components/Components.kt index 72218058b..711ca7718 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Components.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Components.kt @@ -4,13 +4,11 @@ package org.mozilla.fenix.components +import android.annotation.SuppressLint import android.app.Application import android.content.Context -import android.content.Intent -import android.os.StrictMode import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext -import androidx.core.net.toUri import com.google.android.play.core.review.ReviewManagerFactory import mozilla.components.feature.addons.AddonManager import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker @@ -21,19 +19,20 @@ import mozilla.components.support.base.worker.Frequency import io.github.forkmaintainers.iceraven.components.PagedAddonCollectionProvider import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.autofill.AutofillConfirmActivity import org.mozilla.fenix.autofill.AutofillSearchActivity import org.mozilla.fenix.autofill.AutofillUnlockActivity import org.mozilla.fenix.components.appstate.AppState +import org.mozilla.fenix.components.metrics.MetricsMiddleware import org.mozilla.fenix.datastore.pocketStoriesSelectedCategoriesDataStore import org.mozilla.fenix.ext.asRecentTabs import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.filterState import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.gleanplumb.state.MessagingMiddleware import org.mozilla.fenix.ext.sort +import org.mozilla.fenix.gleanplumb.state.MessagingMiddleware import org.mozilla.fenix.home.PocketUpdatesMiddleware import org.mozilla.fenix.home.blocklist.BlocklistHandler import org.mozilla.fenix.home.blocklist.BlocklistMiddleware @@ -44,7 +43,6 @@ import org.mozilla.fenix.perf.StrictModeManager import org.mozilla.fenix.perf.lazyMonitored import org.mozilla.fenix.utils.ClipboardHandler import org.mozilla.fenix.utils.Settings -import org.mozilla.fenix.wallpapers.WallpaperManager import org.mozilla.fenix.wifi.WifiConnectionMonitor import java.util.concurrent.TimeUnit @@ -104,12 +102,32 @@ class Components(private val context: Context) { } val addonCollectionProvider by lazyMonitored { - PagedAddonCollectionProvider( - context, - core.client, - serverURL = BuildConfig.AMO_SERVER_URL, - maxCacheAgeInMinutes = AMO_COLLECTION_MAX_CACHE_AGE, - ) + // Check if we have a customized (overridden) AMO collection (supported in Nightly & Beta) + if (FeatureFlags.customExtensionCollectionFeature && context.settings().amoCollectionOverrideConfigured()) { + AddonCollectionProvider( + context, + core.client, + collectionUser = context.settings().overrideAmoUser, + collectionName = context.settings().overrideAmoCollection, + ) + } + // Use build config otherwise + else if (!BuildConfig.AMO_COLLECTION_USER.isNullOrEmpty() && + !BuildConfig.AMO_COLLECTION_NAME.isNullOrEmpty() + ) { + AddonCollectionProvider( + context, + core.client, + serverURL = BuildConfig.AMO_SERVER_URL, + collectionUser = BuildConfig.AMO_COLLECTION_USER, + collectionName = BuildConfig.AMO_COLLECTION_NAME, + maxCacheAgeInMinutes = AMO_COLLECTION_MAX_CACHE_AGE, + ) + } + // Fall back to defaults + else { + AddonCollectionProvider(context, core.client, maxCacheAgeInMinutes = AMO_COLLECTION_MAX_CACHE_AGE) + } } @Suppress("MagicNumber") @@ -122,11 +140,6 @@ class Components(private val context: Context) { DefaultSupportedAddonsChecker( context, Frequency(12, TimeUnit.HOURS), - onNotificationClickIntent = Intent(context, HomeActivity::class.java).apply { - action = Intent.ACTION_VIEW - flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK - data = "${BuildConfig.DEEP_LINK_SCHEME}://settings_addon_manager".toUri() - }, ) } @@ -146,14 +159,6 @@ class Components(private val context: Context) { val wifiConnectionMonitor by lazyMonitored { WifiConnectionMonitor(context as Application) } val strictMode by lazyMonitored { StrictModeManager(Config, this) } - val wallpaperManager by lazyMonitored { - strictMode.resetAfter(StrictMode.allowThreadDiskReads()) { - WallpaperManager( - appStore, - ) - } - } - val settings by lazyMonitored { Settings(context) } val reviewPromptController by lazyMonitored { @@ -163,6 +168,7 @@ class Components(private val context: Context) { ) } + @delegate:SuppressLint("NewApi") val autofillConfiguration by lazyMonitored { AutofillConfiguration( storage = core.passwordsStorage, @@ -206,6 +212,7 @@ class Components(private val context: Context) { context.pocketStoriesSelectedCategoriesDataStore, ), MessagingMiddleware(messagingStorage = analytics.messagingStorage), + MetricsMiddleware(metrics = analytics.metrics), ), ) } diff --git a/app/src/main/java/org/mozilla/fenix/components/Core.kt b/app/src/main/java/org/mozilla/fenix/components/Core.kt index 5dfc2c576..8ef188e3f 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Core.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Core.kt @@ -92,6 +92,7 @@ import org.mozilla.fenix.perf.StrictModeManager import org.mozilla.fenix.perf.lazyMonitored import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.advanced.getSelectedLocale +import org.mozilla.fenix.share.SaveToPDFMiddleware import org.mozilla.fenix.telemetry.TelemetryMiddleware import org.mozilla.fenix.utils.getUndoDelay import org.mozilla.geckoview.GeckoRuntime @@ -229,7 +230,7 @@ class Core( RecentlyClosedMiddleware(recentlyClosedTabsStorage, RECENTLY_CLOSED_MAX), DownloadMiddleware(context, DownloadService::class.java), ReaderViewMiddleware(), - TelemetryMiddleware(context.settings()), + TelemetryMiddleware(context.settings(), metrics), ThumbnailsMiddleware(thumbnailStorage), UndoMiddleware(context.getUndoDelay()), RegionMiddleware(context, locationService), @@ -244,6 +245,7 @@ class Core( LastMediaAccessMiddleware(), HistoryMetadataMiddleware(historyMetadataService), SessionPrioritizationMiddleware(), + SaveToPDFMiddleware(context), ) BrowserStore( diff --git a/app/src/main/java/org/mozilla/fenix/components/PermissionStorage.kt b/app/src/main/java/org/mozilla/fenix/components/PermissionStorage.kt index e986f4e69..5a5efcaf4 100644 --- a/app/src/main/java/org/mozilla/fenix/components/PermissionStorage.kt +++ b/app/src/main/java/org/mozilla/fenix/components/PermissionStorage.kt @@ -5,7 +5,6 @@ package org.mozilla.fenix.components import android.content.Context -import androidx.annotation.VisibleForTesting import androidx.paging.DataSource import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -16,8 +15,8 @@ import kotlin.coroutines.CoroutineContext class PermissionStorage( private val context: Context, - @VisibleForTesting internal val dispatcher: CoroutineContext = Dispatchers.IO, - @VisibleForTesting internal val permissionsStorage: SitePermissionsStorage = + private val dispatcher: CoroutineContext = Dispatchers.IO, + internal val permissionsStorage: SitePermissionsStorage = context.components.core.geckoSitePermissionsStorage, ) { diff --git a/app/src/main/java/org/mozilla/fenix/components/Push.kt b/app/src/main/java/org/mozilla/fenix/components/Push.kt index cc7a925ee..f99ef999c 100644 --- a/app/src/main/java/org/mozilla/fenix/components/Push.kt +++ b/app/src/main/java/org/mozilla/fenix/components/Push.kt @@ -7,8 +7,8 @@ package org.mozilla.fenix.components import android.content.Context import androidx.core.net.toUri import mozilla.components.feature.push.AutoPushFeature -import mozilla.components.feature.push.PushConfig import mozilla.components.feature.push.Protocol +import mozilla.components.feature.push.PushConfig import mozilla.components.lib.crash.CrashReporter import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.R diff --git a/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt b/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt index 87c3a831b..33e8704ad 100644 --- a/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt @@ -6,10 +6,15 @@ package org.mozilla.fenix.components import android.app.Activity import androidx.annotation.VisibleForTesting +import com.google.android.play.core.review.ReviewInfo import com.google.android.play.core.review.ReviewManager import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.withContext +import org.mozilla.fenix.GleanMetrics.ReviewPrompt import org.mozilla.fenix.utils.Settings +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale /** * Interface that describes the settings needed to track the Review Prompt. @@ -50,6 +55,11 @@ class ReviewPromptController( flow.addOnCompleteListener { if (it.isSuccessful) { manager.launchReviewFlow(activity, it.result) + recordReviewPromptEvent( + it.result.toString(), + reviewSettings.numberOfAppLaunches, + Date(), + ) } } } @@ -98,3 +108,44 @@ class ReviewPromptController( private const val NUMBER_OF_MONTHS_TO_PASS = 4 } } + +/** + * Records a [ReviewPrompt] with the required data. + * + * **Note:** The docs for [ReviewManager.launchReviewFlow] state 'In some circumstances the review + * flow will not be shown to the user, e.g. they have already seen it recently, so do not assume that + * calling this method will always display the review dialog.' + * However, investigation has shown that a [ReviewInfo] instance with the flag: + * - 'isNoOp=true' indicates that the prompt has NOT been displayed. + * - 'isNoOp=false' indicates that a prompt has been displayed. + * [ReviewManager.launchReviewFlow] will modify the ReviewInfo instance which can be used to determine + * which of these flags is present. + */ +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) +fun recordReviewPromptEvent( + reviewInfoAsString: String, + numberOfAppLaunches: Int, + now: Date, +) { + val formattedLocalDatetime = + SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()).format(now) + + // The internals of ReviewInfo cannot be accessed directly or cast nicely, so lets simply use + // the object as a string. + // ReviewInfo is susceptible to changes outside of our control hence the catch-all 'else' statement. + val promptWasDisplayed = if (reviewInfoAsString.contains("isNoOp=true")) { + "false" + } else if (reviewInfoAsString.contains("isNoOp=false")) { + "true" + } else { + "error" + } + + ReviewPrompt.promptAttempt.record( + ReviewPrompt.PromptAttemptExtra( + promptWasDisplayed = promptWasDisplayed, + localDatetime = formattedLocalDatetime, + numberOfAppLaunches = numberOfAppLaunches, + ), + ) +} diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt index aa87697b6..33ab9a23c 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt @@ -11,17 +11,17 @@ import mozilla.components.lib.state.Action import mozilla.components.service.pocket.PocketStory import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory import org.mozilla.fenix.components.AppStore +import org.mozilla.fenix.gleanplumb.Message +import org.mozilla.fenix.gleanplumb.MessagingState import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.pocket.PocketRecommendedStoriesCategory import org.mozilla.fenix.home.pocket.PocketRecommendedStoriesSelectedCategory import org.mozilla.fenix.home.recentbookmarks.RecentBookmark +import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState import org.mozilla.fenix.home.recenttabs.RecentTab import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem import org.mozilla.fenix.library.history.PendingDeletionHistory -import org.mozilla.fenix.gleanplumb.Message -import org.mozilla.fenix.gleanplumb.MessagingState -import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab import org.mozilla.fenix.wallpapers.Wallpaper /** @@ -191,4 +191,9 @@ sealed class AppAction : Action { val imageState: Wallpaper.ImageFileState, ) : WallpaperAction() } + + /** + * Indicates that the app has been resumed and metrics that relate to that should be sent. + */ + object ResumedMetricsAction : AppAction() } diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/AppState.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/AppState.kt index c24e61716..424e3c654 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/AppState.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/AppState.kt @@ -12,6 +12,7 @@ import mozilla.components.lib.state.State import mozilla.components.service.pocket.PocketStory import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory +import org.mozilla.fenix.gleanplumb.MessagingState import org.mozilla.fenix.home.HomeFragment import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.pocket.PocketRecommendedStoriesCategory @@ -21,7 +22,6 @@ import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState import org.mozilla.fenix.home.recenttabs.RecentTab import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem import org.mozilla.fenix.library.history.PendingDeletionHistory -import org.mozilla.fenix.gleanplumb.MessagingState import org.mozilla.fenix.wallpapers.WallpaperState /** diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/AppStoreReducer.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/AppStoreReducer.kt index 5355af13d..5ac962aa6 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/AppStoreReducer.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/AppStoreReducer.kt @@ -220,6 +220,7 @@ internal object AppStoreReducer { val wallpaperState = state.wallpaperState.copy(availableWallpapers = wallpapers) state.copy(wallpaperState = wallpaperState) } + is AppAction.ResumedMetricsAction -> state } } diff --git a/app/src/main/java/org/mozilla/fenix/components/bookmarks/BookmarksUseCase.kt b/app/src/main/java/org/mozilla/fenix/components/bookmarks/BookmarksUseCase.kt index 9e51d44be..19a8c856b 100644 --- a/app/src/main/java/org/mozilla/fenix/components/bookmarks/BookmarksUseCase.kt +++ b/app/src/main/java/org/mozilla/fenix/components/bookmarks/BookmarksUseCase.kt @@ -6,7 +6,7 @@ package org.mozilla.fenix.components.bookmarks import androidx.annotation.WorkerThread import mozilla.appservices.places.BookmarkRoot -import mozilla.appservices.places.uniffi.PlacesException +import mozilla.appservices.places.uniffi.PlacesApiException import mozilla.components.concept.storage.BookmarksStorage import mozilla.components.concept.storage.HistoryStorage import org.mozilla.fenix.home.recentbookmarks.RecentBookmark @@ -42,7 +42,7 @@ class BookmarksUseCase( ) } canAdd - } catch (e: PlacesException.UrlParseFailed) { + } catch (e: PlacesApiException.UrlParseFailed) { false } } diff --git a/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt b/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt index d95a8c8ff..00cf6002b 100644 --- a/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt +++ b/app/src/main/java/org/mozilla/fenix/components/history/PagedHistoryProvider.kt @@ -11,7 +11,6 @@ import mozilla.components.concept.storage.HistoryMetadataKey import mozilla.components.concept.storage.VisitInfo import mozilla.components.concept.storage.VisitType import mozilla.components.support.ktx.kotlin.tryGetHostFromUrl -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.library.history.History import org.mozilla.fenix.library.history.HistoryItemTimeGroup import org.mozilla.fenix.utils.Settings.Companion.SEARCH_GROUP_MINIMUM_SITES @@ -86,7 +85,6 @@ interface PagedHistoryProvider { */ class DefaultPagedHistoryProvider( private val historyStorage: PlacesHistoryStorage, - private val historyImprovementFeatures: Boolean = FeatureFlags.historyImprovementFeatures, ) : PagedHistoryProvider { /** @@ -132,11 +130,7 @@ class DefaultPagedHistoryProvider( ) } .filter { - if (historyImprovementFeatures) { - it.items.size >= SEARCH_GROUP_MINIMUM_SITES - } else { - true - } + it.items.size >= SEARCH_GROUP_MINIMUM_SITES } .toList() } @@ -207,10 +201,7 @@ class DefaultPagedHistoryProvider( emptyList() } val historyMetadata = historyGroupsInOffset.flatMap { it.items } - - if (historyImprovementFeatures) { - history = history.distinctBy { Pair(it.historyTimeGroup, it.url) } - } + history = history.distinctBy { Pair(it.historyTimeGroup, it.url) } // Add all history items that are not in a group filtering out any matches with a history // metadata item. @@ -227,11 +218,7 @@ class DefaultPagedHistoryProvider( }, ) - return if (historyImprovementFeatures) { - result.sortedByDescending { it.visitedAt } - } else { - result.removeConsecutiveDuplicates().sortedByDescending { it.visitedAt } - } + return result.sortedByDescending { it.visitedAt } } private fun transformVisitInfoToHistoryItem(visit: VisitInfo): HistoryDB.Regular { diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/AdjustMetricsService.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/AdjustMetricsService.kt index 5f4788aff..bf32cb29c 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/AdjustMetricsService.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/AdjustMetricsService.kt @@ -10,12 +10,23 @@ import android.os.Bundle import android.util.Log import com.adjust.sdk.Adjust import com.adjust.sdk.AdjustConfig +import com.adjust.sdk.AdjustEvent import com.adjust.sdk.LogLevel +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import mozilla.components.lib.crash.CrashReporter import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config import org.mozilla.fenix.ext.settings -class AdjustMetricsService(private val application: Application) : MetricsService { +class AdjustMetricsService( + private val application: Application, + private val storage: MetricsStorage, + private val crashReporter: CrashReporter, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO, +) : MetricsService { override val type = MetricServiceType.Marketing override fun start() { @@ -70,9 +81,22 @@ class AdjustMetricsService(private val application: Application) : MetricsServic Adjust.gdprForgetMe(application.applicationContext) } - // We're not currently sending events directly to Adjust - override fun track(event: Event) { /* noop */ } - override fun shouldTrack(event: Event): Boolean = false + @Suppress("TooGenericExceptionCaught") + override fun track(event: Event) { + CoroutineScope(dispatcher).launch { + try { + if (event is Event.GrowthData && storage.shouldTrack(event)) { + Adjust.trackEvent(AdjustEvent(event.tokenName)) + storage.updateSentState(event) + } + } catch (e: Exception) { + crashReporter.submitCaughtException(e) + } + } + } + + override fun shouldTrack(event: Event): Boolean = + event is Event.GrowthData companion object { private const val LOGTAG = "AdjustMetricsService" diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt index b625cbd09..77fedea9a 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/Event.kt @@ -12,4 +12,29 @@ sealed class Event { internal open val extras: Map<*, String>? get() = null + + /** + * Events related to growth campaigns. + */ + sealed class GrowthData(val tokenName: String) : Event() { + /** + * Event recording whether Firefox has been set as the default browser. + */ + object SetAsDefault : GrowthData("xgpcgt") + + /** + * Event recording the first time Firefox has been resumed in a 24 hour period. + */ + object FirstAppOpenForDay : GrowthData("41hl22") + + /** + * Event recording the first time a URI is loaded in Firefox in a 24 hour period. + */ + object FirstUriLoadForDay : GrowthData("ja86ek") + + /** + * Event recording the first time Firefox is used 3 days in a row in the first week of install. + */ + object FirstWeekSeriesActivity : GrowthData("20ay7u") + } } diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt index 4921f7dca..d5590efe7 100644 --- a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricController.kt @@ -36,10 +36,10 @@ import mozilla.telemetry.glean.private.NoExtras import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.GleanMetrics.Addons import org.mozilla.fenix.GleanMetrics.Addresses -import org.mozilla.fenix.GleanMetrics.ContextMenu import org.mozilla.fenix.GleanMetrics.AndroidAutofill import org.mozilla.fenix.GleanMetrics.Awesomebar import org.mozilla.fenix.GleanMetrics.BrowserSearch +import org.mozilla.fenix.GleanMetrics.ContextMenu import org.mozilla.fenix.GleanMetrics.ContextualMenu import org.mozilla.fenix.GleanMetrics.CreditCards import org.mozilla.fenix.GleanMetrics.LoginDialog diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsMiddleware.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsMiddleware.kt new file mode 100644 index 000000000..e7d7cf2a1 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsMiddleware.kt @@ -0,0 +1,31 @@ +package org.mozilla.fenix.components.metrics + +import mozilla.components.lib.state.Middleware +import mozilla.components.lib.state.MiddlewareContext +import org.mozilla.fenix.components.appstate.AppAction +import org.mozilla.fenix.components.appstate.AppState + +/** + * A middleware that will map incoming actions to relevant events for [metrics]. + */ +class MetricsMiddleware( + private val metrics: MetricController, +) : Middleware { + override fun invoke( + context: MiddlewareContext, + next: (AppAction) -> Unit, + action: AppAction, + ) { + handleAction(action) + next(action) + } + + private fun handleAction(action: AppAction) = when (action) { + is AppAction.ResumedMetricsAction -> { + metrics.track(Event.GrowthData.SetAsDefault) + metrics.track(Event.GrowthData.FirstAppOpenForDay) + metrics.track(Event.GrowthData.FirstWeekSeriesActivity) + } + else -> Unit + } +} diff --git a/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsStorage.kt b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsStorage.kt new file mode 100644 index 000000000..6b06e40ca --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/components/metrics/MetricsStorage.kt @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.components.metrics + +import android.content.Context +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.nimbus.FxNimbus +import org.mozilla.fenix.utils.Settings +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Locale + +/** + * Interface defining functions around persisted local state for certain metrics. + */ +interface MetricsStorage { + /** + * Determines whether an [event] should be sent based on locally-stored state. + */ + suspend fun shouldTrack(event: Event): Boolean + + /** + * Updates locally-stored state for an [event] that has just been sent. + */ + suspend fun updateSentState(event: Event) +} + +internal class DefaultMetricsStorage( + context: Context, + private val settings: Settings, + private val checkDefaultBrowser: () -> Boolean, + private val shouldSendGenerally: () -> Boolean = { shouldSendGenerally(context) }, + private val getInstalledTime: () -> Long = { getInstalledTime(context) }, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO, +) : MetricsStorage { + + private val dateFormatter = SimpleDateFormat("yyyy-MM-dd", Locale.US) + + /** + * Checks local state to see whether the [event] should be sent. + */ + override suspend fun shouldTrack(event: Event): Boolean = + withContext(dispatcher) { + // The side-effect of storing days of use needs to happen during the first two days after + // install, which would normally be skipped by shouldSendGenerally. + updateDaysOfUse() + shouldSendGenerally() && when (event) { + Event.GrowthData.SetAsDefault -> { + !settings.setAsDefaultGrowthSent && checkDefaultBrowser() + } + Event.GrowthData.FirstAppOpenForDay -> { + settings.resumeGrowthLastSent.hasBeenMoreThanDaySince() + } + Event.GrowthData.FirstUriLoadForDay -> { + settings.uriLoadGrowthLastSent.hasBeenMoreThanDaySince() + } + Event.GrowthData.FirstWeekSeriesActivity -> { + shouldTrackFirstWeekActivity() + } + } + } + + override suspend fun updateSentState(event: Event) = withContext(dispatcher) { + when (event) { + Event.GrowthData.SetAsDefault -> { + settings.setAsDefaultGrowthSent = true + } + Event.GrowthData.FirstAppOpenForDay -> { + settings.resumeGrowthLastSent = System.currentTimeMillis() + } + Event.GrowthData.FirstUriLoadForDay -> { + settings.uriLoadGrowthLastSent = System.currentTimeMillis() + } + Event.GrowthData.FirstWeekSeriesActivity -> { + settings.firstWeekSeriesGrowthSent = true + } + } + } + + private fun updateDaysOfUse() { + val daysOfUse = settings.firstWeekDaysOfUseGrowthData + val currentDate = Calendar.getInstance(Locale.US) + val currentDateString = dateFormatter.format(currentDate.time) + if (currentDate.timeInMillis.withinFirstWeek() && daysOfUse.none { it == currentDateString }) { + settings.firstWeekDaysOfUseGrowthData = daysOfUse + currentDateString + } + } + + private fun shouldTrackFirstWeekActivity(): Boolean = Result.runCatching { + if (!System.currentTimeMillis().withinFirstWeek() || settings.firstWeekSeriesGrowthSent) { + return false + } + + val daysOfUse = settings.firstWeekDaysOfUseGrowthData.map { + dateFormatter.parse(it) + }.sorted() + + // This loop will check whether the existing list of days of use, combined with the + // current date, contains any periods of 3 days of use in a row. + for (idx in daysOfUse.indices) { + if (idx + 1 > daysOfUse.lastIndex || idx + 2 > daysOfUse.lastIndex) { + continue + } + + val referenceDate = daysOfUse[idx]!!.time.toCalendar() + val secondDateEntry = daysOfUse[idx + 1]!!.time.toCalendar() + val thirdDateEntry = daysOfUse[idx + 2]!!.time.toCalendar() + val oneDayAfterReference = referenceDate.createNextDay() + val twoDaysAfterReference = oneDayAfterReference.createNextDay() + + if (oneDayAfterReference == secondDateEntry && thirdDateEntry == twoDaysAfterReference) { + return true + } + } + return false + }.getOrDefault(false) + + private fun Long.hasBeenMoreThanDaySince(): Boolean = + System.currentTimeMillis() - this > dayMillis + + private fun Long.toCalendar(): Calendar = Calendar.getInstance(Locale.US).also { calendar -> + calendar.timeInMillis = this + } + + private fun Long.withinFirstWeek() = this < getInstalledTime() + fullWeekMillis + + private fun Calendar.createNextDay() = (this.clone() as Calendar).also { calendar -> + calendar.add(Calendar.DAY_OF_MONTH, 1) + } + + companion object { + private const val dayMillis: Long = 1000 * 60 * 60 * 24 + private const val windowStartMillis: Long = dayMillis * 2 + private const val windowEndMillis: Long = dayMillis * 28 + + // Note this is 8 so that recording of FirstWeekSeriesActivity happens throughout the length + // of the 7th day after install + private const val fullWeekMillis: Long = dayMillis * 8 + + /** + * Determines whether events should be tracked based on some general criteria: + * - user has installed as a result of a campaign + * - user is within 2-28 days of install + * - tracking is still enabled through Nimbus + */ + fun shouldSendGenerally(context: Context): Boolean { + val installedTime = getInstalledTime(context) + val timeDifference = System.currentTimeMillis() - installedTime + val withinWindow = timeDifference in windowStartMillis..windowEndMillis + + return context.settings().adjustCampaignId.isNotEmpty() && + FxNimbus.features.growthData.value().enabled && + withinWindow + } + + fun getInstalledTime(context: Context): Long = context.packageManager + .getPackageInfo(context.packageName, 0) + .firstInstallTime + } +} diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt index 0166ce89d..08545bfcf 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarController.kt @@ -49,6 +49,7 @@ interface BrowserToolbarController { fun handleHomeButtonClick() } +@Suppress("LongParameterList") class DefaultBrowserToolbarController( private val store: BrowserStore, private val tabsUseCases: TabsUseCases, diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt index 6fdb31fd7..02ab6be31 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMenuController.kt @@ -58,7 +58,7 @@ interface BrowserToolbarMenuController { fun handleToolbarItemInteraction(item: ToolbarMenu.Item) } -@Suppress("LargeClass", "ForbiddenComment") +@Suppress("LargeClass", "ForbiddenComment", "LongParameterList") class DefaultBrowserToolbarMenuController( private val store: BrowserStore, private val activity: HomeActivity, @@ -211,6 +211,7 @@ class DefaultBrowserToolbarMenuController( } is ToolbarMenu.Item.Share -> { val directions = NavGraphDirections.actionGlobalShareFragment( + sessionId = currentSession?.id, data = arrayOf( ShareData( url = getProperUrl(currentSession), diff --git a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt index 385ec50d1..edcca2f93 100644 --- a/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/components/toolbar/DefaultToolbarMenu.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.components.toolbar import android.content.Context import androidx.annotation.ColorRes import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.core.content.ContextCompat.getColor import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope @@ -352,7 +352,7 @@ open class DefaultToolbarMenu( private fun syncMenuItem(): BrowserMenuImageText? { val syncItemTitle = if (context.components.backgroundServices.accountManagerAvailableQueue.isReady()) { - accountManager.accountProfileEmail ?: context.getString(R.string.sync_menu_sign_in) + accountManager.accountProfileEmail ?: context.getString(R.string.sync_menu_sync_and_save_data) } else { null } diff --git a/app/src/main/java/org/mozilla/fenix/compose/Divider.kt b/app/src/main/java/org/mozilla/fenix/compose/Divider.kt new file mode 100644 index 000000000..67e71db87 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/compose/Divider.kt @@ -0,0 +1,108 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.compose + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.theme.FirefoxTheme + +/** + * Generic divider. + * + * @param modifier [Modifier] used to be applied to the layout of the divider. + */ +@Composable +fun Divider( + modifier: Modifier = Modifier, +) { + androidx.compose.material.Divider( + modifier = modifier, + color = FirefoxTheme.colors.borderPrimary, + ) +} + +/** + * An example of a vertical divider. + */ +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun VerticalDividerPreview() { + FirefoxTheme { + Box( + Modifier + .background(FirefoxTheme.colors.layer1) + .height(75.dp), + ) { + Row { + Text( + text = "Before the line", + modifier = Modifier.padding(end = 10.dp), + ) + + Divider( + modifier = Modifier + .fillMaxHeight() + .width(0.5.dp) + .padding(vertical = 10.dp), + ) + + Text( + text = "After the line", + modifier = Modifier.padding(start = 10.dp), + ) + } + } + } +} + +/** + * An example of divider usage in a list menu. + */ +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun HorizontalDividerPreview() { + FirefoxTheme { + Box( + Modifier + .background(FirefoxTheme.colors.layer1) + .width(100.dp) + .height(175.dp), + ) { + Column(Modifier.padding(start = 4.dp)) { + Text(text = "New") + + Text(text = "Open") + + Text(text = "Open Recent") + + Divider(modifier = Modifier.padding(vertical = 10.dp, horizontal = 24.dp)) + + Text(text = "Close") + + Text(text = "Save") + + Text(text = "Save as") + + Text(text = "Rename") + + Divider(modifier = Modifier.padding(vertical = 10.dp, horizontal = 24.dp)) + } + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt b/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt index a4aa3e14c..e7b221543 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt @@ -4,16 +4,17 @@ package org.mozilla.fenix.compose +import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card import androidx.compose.material.Icon @@ -21,32 +22,36 @@ import androidx.compose.material.IconButton import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import org.mozilla.experiments.nimbus.StringHolder import org.mozilla.fenix.R import org.mozilla.fenix.compose.button.PrimaryButton -import org.mozilla.fenix.gleanplumb.Message -import org.mozilla.fenix.nimbus.MessageData -import org.mozilla.fenix.nimbus.StyleData import org.mozilla.fenix.theme.FirefoxTheme -import org.mozilla.fenix.theme.Theme /** * Message Card. * - * @param message [Message] that holds a representation of GleanPlum message from Nimbus. + * @param messageText The message card's body text to be displayed. + * @param titleText An optional title of message card. If the provided title text is blank or null, + * the title will not be shown. + * @param buttonText An optional button text of the message card. If the provided button text is blank or null, + * the button won't be shown. + * @param messageColors The color set defined by [MessageCardColors] used to style the message card. * @param onClick Invoked when user clicks on the message card. * @param onCloseButtonClick Invoked when user clicks on close button to remove message. */ @Suppress("LongMethod") @Composable fun MessageCard( - message: Message, + messageText: String, + titleText: String? = null, + buttonText: String? = null, + messageColors: MessageCardColors = MessageCardColors.buildMessageCardColors(), onClick: () -> Unit, onCloseButtonClick: () -> Unit, ) { @@ -54,86 +59,70 @@ fun MessageCard( modifier = Modifier .padding(vertical = 16.dp) .then( - if (message.data.buttonLabel.isNullOrBlank()) { + if (buttonText.isNullOrBlank()) { Modifier.clickable(onClick = onClick) } else { Modifier }, ), shape = RoundedCornerShape(8.dp), - backgroundColor = FirefoxTheme.colors.layer2, + backgroundColor = messageColors.backgroundColor, ) { Column( Modifier .padding(all = 16.dp) .fillMaxWidth(), ) { - val title = message.data.title - if (!title.isNullOrBlank()) { + if (!titleText.isNullOrBlank()) { Row( modifier = Modifier.fillMaxWidth(), ) { Text( - text = title, + text = titleText, modifier = Modifier.weight(1f), - color = FirefoxTheme.colors.textPrimary, + color = messageColors.titleTextColor, overflow = TextOverflow.Ellipsis, maxLines = 2, style = FirefoxTheme.typography.headline7, ) - IconButton( - modifier = Modifier.size(20.dp), - onClick = onCloseButtonClick, - ) { - Icon( - painter = painterResource(R.drawable.mozac_ic_close_20), - contentDescription = stringResource( - R.string.content_description_close_button, - ), - tint = FirefoxTheme.colors.iconPrimary, - ) - } + MessageCardIconButton( + iconTint = messageColors.iconColor, + onCloseButtonClick = onCloseButtonClick, + ) } Text( - text = message.data.text, + text = messageText, modifier = Modifier.fillMaxWidth(), fontSize = 14.sp, - color = FirefoxTheme.colors.textSecondary, + color = messageColors.messageTextColor, ) } else { Row( modifier = Modifier.fillMaxWidth(), ) { Text( - text = message.data.text, + text = messageText, modifier = Modifier.weight(1f), fontSize = 14.sp, - color = FirefoxTheme.colors.textPrimary, + color = messageColors.titleTextColor, ) - IconButton( - modifier = Modifier.size(20.dp), - onClick = onCloseButtonClick, - ) { - Icon( - painter = painterResource(R.drawable.mozac_ic_close_20), - contentDescription = stringResource( - R.string.content_description_close_button, - ), - tint = FirefoxTheme.colors.iconPrimary, - ) - } + MessageCardIconButton( + iconTint = messageColors.iconColor, + onCloseButtonClick = onCloseButtonClick, + ) } } - val buttonLabel = message.data.buttonLabel - if (!buttonLabel.isNullOrBlank()) { + if (!buttonText.isNullOrBlank()) { Spacer(modifier = Modifier.height(16.dp)) PrimaryButton( - text = buttonLabel, + text = buttonText, + textColor = messageColors.buttonTextColor, + backgroundColor = messageColors.buttonColor, onClick = onClick, ) } @@ -141,29 +130,87 @@ fun MessageCard( } } +/** + * IconButton within a MessageCard. + * + * @param iconTint The [Color] used to tint the button's icon. + * @param onCloseButtonClick Invoked when user clicks on close button to remove message. + */ @Composable -@Preview +private fun MessageCardIconButton( + iconTint: Color, + onCloseButtonClick: () -> Unit, +) { + IconButton( + modifier = Modifier.size(20.dp), + onClick = onCloseButtonClick, + ) { + Icon( + painter = painterResource(R.drawable.mozac_ic_close_20), + contentDescription = stringResource( + R.string.content_description_close_button, + ), + tint = iconTint, + ) + } +} + +/** + * Wrapper for the color parameters of [MessageCard]. + * + * @param backgroundColor The background [Color] of the message. + * @param titleTextColor [Color] to apply to the message's title, or the body text when there is no title. + * @param messageTextColor [Color] to apply to the message's body text. + * @param iconColor [Color] to apply to the message's icon. + * @param buttonColor The background [Color] of the message's button. + * @param buttonTextColor [Color] to apply to the button text. + */ +data class MessageCardColors( + val backgroundColor: Color, + val titleTextColor: Color, + val messageTextColor: Color, + val iconColor: Color, + val buttonColor: Color, + val buttonTextColor: Color, +) { + companion object { + + /** + * Builder function used to construct an instance of [MessageCardColors]. + */ + @Composable + fun buildMessageCardColors( + backgroundColor: Color = FirefoxTheme.colors.layer2, + titleTextColor: Color = FirefoxTheme.colors.textPrimary, + messageTextColor: Color = FirefoxTheme.colors.textSecondary, + iconColor: Color = FirefoxTheme.colors.iconPrimary, + buttonColor: Color = FirefoxTheme.colors.actionPrimary, + buttonTextColor: Color = FirefoxTheme.colors.textActionPrimary, + ): MessageCardColors = + MessageCardColors( + backgroundColor = backgroundColor, + titleTextColor = titleTextColor, + messageTextColor = messageTextColor, + iconColor = iconColor, + buttonColor = buttonColor, + buttonTextColor = buttonTextColor, + ) + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) private fun MessageCardPreview() { - FirefoxTheme(theme = Theme.getTheme()) { - Box(Modifier.background(FirefoxTheme.colors.layer1)) { + FirefoxTheme { + Box( + Modifier + .background(FirefoxTheme.colors.layer1) + .padding(all = 16.dp), + ) { MessageCard( - message = Message( - id = "end-", - data = MessageData( - title = StringHolder( - R.string.bookmark_empty_title_error, - "Title", - ), - text = StringHolder( - R.string.default_browser_experiment_card_text, - "description", - ), - ), - action = "action", - style = StyleData(), - triggers = listOf("trigger"), - metadata = Message.Metadata("end-"), - ), + messageText = stringResource(id = R.string.default_browser_experiment_card_text), + titleText = stringResource(id = R.string.bookmark_empty_title_error), onClick = {}, onCloseButtonClick = {}, ) @@ -172,24 +219,17 @@ private fun MessageCardPreview() { } @Composable -@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) private fun MessageCardWithoutTitlePreview() { - FirefoxTheme(theme = Theme.getTheme()) { - Box(Modifier.background(FirefoxTheme.colors.layer1)) { + FirefoxTheme { + Box( + modifier = Modifier + .background(FirefoxTheme.colors.layer1) + .padding(all = 16.dp), + ) { MessageCard( - message = Message( - id = "end-", - data = MessageData( - text = StringHolder( - R.string.default_browser_experiment_card_text, - "description", - ), - ), - action = "action", - style = StyleData(), - triggers = listOf("trigger"), - metadata = Message.Metadata("end-"), - ), + messageText = stringResource(id = R.string.default_browser_experiment_card_text), onClick = {}, onCloseButtonClick = {}, ) @@ -198,29 +238,19 @@ private fun MessageCardWithoutTitlePreview() { } @Composable -@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) private fun MessageCardWithButtonLabelPreview() { - FirefoxTheme(theme = Theme.getTheme()) { - Box(Modifier.background(FirefoxTheme.colors.layer1)) { + FirefoxTheme { + Box( + modifier = Modifier + .background(FirefoxTheme.colors.layer1) + .padding(all = 16.dp), + ) { MessageCard( - message = Message( - id = "end-", - data = MessageData( - buttonLabel = StringHolder(R.string.preferences_set_as_default_browser, ""), - title = StringHolder( - R.string.bookmark_empty_title_error, - "Title", - ), - text = StringHolder( - R.string.default_browser_experiment_card_text, - "description", - ), - ), - action = "action", - style = StyleData(), - triggers = listOf("trigger"), - metadata = Message.Metadata("end-"), - ), + messageText = stringResource(id = R.string.default_browser_experiment_card_text), + titleText = stringResource(id = R.string.bookmark_empty_title_error), + buttonText = stringResource(id = R.string.preferences_set_as_default_browser), onClick = {}, onCloseButtonClick = {}, ) diff --git a/app/src/main/java/org/mozilla/fenix/compose/SelectableChip.kt b/app/src/main/java/org/mozilla/fenix/compose/SelectableChip.kt index 95060db7b..ae2e04aba 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/SelectableChip.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/SelectableChip.kt @@ -18,6 +18,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.intl.Locale @@ -32,12 +33,20 @@ import org.mozilla.fenix.theme.Theme * * @param text [String] displayed in this chip. Ideally should only be one word. * @param isSelected Whether this should be shown as selected. + * @param selectedTextColor Optional text [Color] when the chip is selected. + * @param unselectedTextColor Optional text [Color] when the chip is not selected. + * @param selectedBackgroundColor Optional background [Color] when the chip is selected. + * @param unselectedBackgroundColor Optional background [Color] when the chip is not selected. * @param onClick Callback for when the user taps this. */ @Composable fun SelectableChip( text: String, isSelected: Boolean, + selectedTextColor: Color? = null, + unselectedTextColor: Color? = null, + selectedBackgroundColor: Color? = null, + unselectedBackgroundColor: Color? = null, onClick: () -> Unit, ) { Box( @@ -46,9 +55,9 @@ fun SelectableChip( .clip(MaterialTheme.shapes.small) .background( color = if (isSelected) { - FirefoxTheme.colors.actionPrimary + selectedBackgroundColor ?: FirefoxTheme.colors.actionPrimary } else { - FirefoxTheme.colors.actionTertiary + unselectedBackgroundColor ?: FirefoxTheme.colors.actionTertiary }, ) .padding(horizontal = 16.dp, vertical = 10.dp), @@ -57,9 +66,9 @@ fun SelectableChip( text = text.capitalize(Locale.current), style = TextStyle(fontSize = 14.sp), color = if (isSelected) { - FirefoxTheme.colors.textActionPrimary + selectedTextColor ?: FirefoxTheme.colors.textActionPrimary } else { - FirefoxTheme.colors.textActionTertiary + unselectedTextColor ?: FirefoxTheme.colors.textActionTertiary }, ) } @@ -67,7 +76,8 @@ fun SelectableChip( @Composable @Preview(uiMode = UI_MODE_NIGHT_YES) -private fun SelectableChipDarkThemePreview() { +@Preview(uiMode = UI_MODE_NIGHT_NO) +private fun SelectableChipPreview() { FirefoxTheme(theme = Theme.getTheme()) { Row( modifier = Modifier @@ -82,8 +92,9 @@ private fun SelectableChipDarkThemePreview() { } @Composable +@Preview(uiMode = UI_MODE_NIGHT_YES) @Preview(uiMode = UI_MODE_NIGHT_NO) -private fun SelectableChipLightThemePreview() { +private fun SelectableChipWithCustomColorsPreview() { FirefoxTheme(theme = Theme.getTheme()) { Row( modifier = Modifier @@ -91,8 +102,18 @@ private fun SelectableChipLightThemePreview() { .background(FirefoxTheme.colors.layer1), horizontalArrangement = Arrangement.SpaceEvenly, ) { - SelectableChip(text = "Chirp", isSelected = false) { } - SelectableChip(text = "Chirp", isSelected = true) { } + SelectableChip( + text = "Chirp", + isSelected = false, + unselectedTextColor = FirefoxTheme.colors.textSecondary, + unselectedBackgroundColor = Color.Cyan, + ) { } + SelectableChip( + text = "Chirp", + isSelected = true, + selectedTextColor = Color.Black, + selectedBackgroundColor = Color.Yellow, + ) { } } } } diff --git a/app/src/main/java/org/mozilla/fenix/compose/button/Button.kt b/app/src/main/java/org/mozilla/fenix/compose/button/Button.kt index d9a5e691b..d344fb681 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/button/Button.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/button/Button.kt @@ -38,7 +38,7 @@ import org.mozilla.fenix.theme.Theme * @param onClick Invoked when the user clicks on the button. */ @Composable -fun Button( +private fun Button( text: String, textColor: Color, backgroundColor: Color, @@ -79,19 +79,23 @@ fun Button( * Primary button. * * @param text The button text to be displayed. + * @param textColor [Color] to apply to the button text. + * @param backgroundColor The background [Color] of the button. * @param icon Optional [Painter] used to display an [Icon] before the button text. * @param onClick Invoked when the user clicks on the button. */ @Composable fun PrimaryButton( text: String, + textColor: Color = FirefoxTheme.colors.textActionPrimary, + backgroundColor: Color = FirefoxTheme.colors.actionPrimary, icon: Painter? = null, onClick: () -> Unit, ) { Button( text = text, - textColor = FirefoxTheme.colors.textActionPrimary, - backgroundColor = FirefoxTheme.colors.actionPrimary, + textColor = textColor, + backgroundColor = backgroundColor, icon = icon, tint = FirefoxTheme.colors.iconActionPrimary, onClick = onClick, @@ -102,19 +106,23 @@ fun PrimaryButton( * Secondary button. * * @param text The button text to be displayed. + * @param textColor [Color] to apply to the button text. + * @param backgroundColor The background [Color] of the button. * @param icon Optional [Painter] used to display an [Icon] before the button text. * @param onClick Invoked when the user clicks on the button. */ @Composable fun SecondaryButton( text: String, + textColor: Color = FirefoxTheme.colors.textActionSecondary, + backgroundColor: Color = FirefoxTheme.colors.actionSecondary, icon: Painter? = null, onClick: () -> Unit, ) { Button( text = text, - textColor = FirefoxTheme.colors.textActionSecondary, - backgroundColor = FirefoxTheme.colors.actionSecondary, + textColor = textColor, + backgroundColor = backgroundColor, icon = icon, tint = FirefoxTheme.colors.iconActionSecondary, onClick = onClick, @@ -125,19 +133,23 @@ fun SecondaryButton( * Tertiary button. * * @param text The button text to be displayed. + * @param textColor [Color] to apply to the button text. + * @param backgroundColor The background [Color] of the button. * @param icon Optional [Painter] used to display an [Icon] before the button text. * @param onClick Invoked when the user clicks on the button. */ @Composable fun TertiaryButton( text: String, + textColor: Color = FirefoxTheme.colors.textActionTertiary, + backgroundColor: Color = FirefoxTheme.colors.actionTertiary, icon: Painter? = null, onClick: () -> Unit, ) { Button( text = text, - textColor = FirefoxTheme.colors.textActionTertiary, - backgroundColor = FirefoxTheme.colors.actionTertiary, + textColor = textColor, + backgroundColor = backgroundColor, icon = icon, tint = FirefoxTheme.colors.iconActionTertiary, onClick = onClick, @@ -148,19 +160,23 @@ fun TertiaryButton( * Destructive button. * * @param text The button text to be displayed. + * @param textColor [Color] to apply to the button text. + * @param backgroundColor The background [Color] of the button. * @param icon Optional [Painter] used to display an [Icon] before the button text. * @param onClick Invoked when the user clicks on the button. */ @Composable fun DestructiveButton( text: String, + textColor: Color = FirefoxTheme.colors.textWarningButton, + backgroundColor: Color = FirefoxTheme.colors.actionSecondary, icon: Painter? = null, onClick: () -> Unit, ) { Button( text = text, - textColor = FirefoxTheme.colors.textWarningButton, - backgroundColor = FirefoxTheme.colors.actionSecondary, + textColor = textColor, + backgroundColor = backgroundColor, icon = icon, tint = FirefoxTheme.colors.iconWarningButton, onClick = onClick, diff --git a/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopup.kt b/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopup.kt index a2ed1e048..1c1951f02 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopup.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopup.kt @@ -72,6 +72,19 @@ class CFRPopup( */ fun show() { anchor.post { + // When we're in this Runnable, the 'show' method might have been called right before + // the activity is no longer attached to the WindowManager. When we get to calling + // the CFRPopupFullscreenLayout#show method below, we are now trying to attach the View + // with the WindowManager that has an unusable Activity. + // + // To protect against this, within this same Runnable, we check if the anchor view is + // safe to use before continuing. + // + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1799996 + if (anchor.context == null || !anchor.isAttachedToWindow) { + return@post + } + CFRPopupFullscreenLayout(text, anchor, properties, onDismiss, action).apply { this.show() popup = WeakReference(this) diff --git a/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopupFullscreenLayout.kt b/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopupFullscreenLayout.kt index 836359f4a..096511b60 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopupFullscreenLayout.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/cfr/CFRPopupFullscreenLayout.kt @@ -380,11 +380,11 @@ internal class CFRPopupFullscreenLayout( * [View.OnAttachStateChangeListener.onViewDetachedFromWindow]. */ private class OnViewDetachedListener(val onDismiss: () -> Unit) : View.OnAttachStateChangeListener { - override fun onViewAttachedToWindow(v: View?) { + override fun onViewAttachedToWindow(v: View) { // no-op } - override fun onViewDetachedFromWindow(v: View?) { + override fun onViewDetachedFromWindow(v: View) { onDismiss() } } diff --git a/app/src/main/java/org/mozilla/fenix/compose/tabstray/TabGridItem.kt b/app/src/main/java/org/mozilla/fenix/compose/tabstray/TabGridItem.kt index 0137dbba4..c5981a985 100644 --- a/app/src/main/java/org/mozilla/fenix/compose/tabstray/TabGridItem.kt +++ b/app/src/main/java/org/mozilla/fenix/compose/tabstray/TabGridItem.kt @@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.Divider import androidx.compose.material.Icon import androidx.compose.material.Text import androidx.compose.runtime.Composable @@ -46,6 +45,7 @@ import androidx.core.text.BidiFormatter import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.state.createTab import org.mozilla.fenix.R +import org.mozilla.fenix.compose.Divider import org.mozilla.fenix.compose.Favicon import org.mozilla.fenix.compose.HorizontalFadingEdgeBox import org.mozilla.fenix.compose.ThumbnailCard @@ -159,10 +159,7 @@ fun TabGridItem( ) } - Divider( - color = FirefoxTheme.colors.borderPrimary, - thickness = 1.dp, - ) + Divider() Thumbnail( tab = tab, diff --git a/app/src/main/java/org/mozilla/fenix/crashes/CrashContentIntegration.kt b/app/src/main/java/org/mozilla/fenix/crashes/CrashContentIntegration.kt index 1cd803469..05f6a69c8 100644 --- a/app/src/main/java/org/mozilla/fenix/crashes/CrashContentIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/crashes/CrashContentIntegration.kt @@ -38,6 +38,8 @@ import org.mozilla.fenix.utils.Settings * @param sessionId [String] Id of the tab or custom tab which should be observed for [EngineState.crashed] * depending on which [crashReporterView] will be shown or hidden. */ + +@Suppress("LongParameterList") class CrashContentIntegration( private val browserStore: BrowserStore, private val appStore: AppStore, diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt index 0663ba028..3df602f67 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/CustomTabsIntegration.kt @@ -16,6 +16,7 @@ import mozilla.components.support.base.feature.UserInteractionHandler import org.mozilla.fenix.R import org.mozilla.fenix.components.toolbar.ToolbarMenu +@Suppress("LongParameterList") class CustomTabsIntegration( store: BrowserStore, useCases: CustomTabsUseCases, diff --git a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt index 3820a7aae..07a9b46d8 100644 --- a/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt @@ -14,13 +14,13 @@ import mozilla.components.browser.state.state.SessionState import mozilla.components.browser.toolbar.BrowserToolbar import mozilla.components.concept.engine.manifest.WebAppManifestParser import mozilla.components.concept.engine.manifest.getOrNull +import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.feature.contextmenu.ContextMenuCandidate import mozilla.components.feature.customtabs.CustomTabWindowFeature import mozilla.components.feature.pwa.feature.ManifestUpdateFeature import mozilla.components.feature.pwa.feature.WebAppActivityFeature import mozilla.components.feature.pwa.feature.WebAppHideToolbarFeature import mozilla.components.feature.pwa.feature.WebAppSiteControlsFeature -import mozilla.components.concept.engine.permission.SitePermissions import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.components.support.base.feature.ViewBoundFeatureWrapper import mozilla.components.support.ktx.android.arch.lifecycle.addObservers diff --git a/app/src/main/java/org/mozilla/fenix/downloads/DynamicDownloadDialog.kt b/app/src/main/java/org/mozilla/fenix/downloads/DynamicDownloadDialog.kt index d0f0ed66c..84ff159dd 100644 --- a/app/src/main/java/org/mozilla/fenix/downloads/DynamicDownloadDialog.kt +++ b/app/src/main/java/org/mozilla/fenix/downloads/DynamicDownloadDialog.kt @@ -12,7 +12,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout import mozilla.components.browser.state.state.content.DownloadState import mozilla.components.feature.downloads.AbstractFetchDownloadService import mozilla.components.feature.downloads.toMegabyteOrKilobyteString -import org.mozilla.fenix.GleanMetrics.Downloads import org.mozilla.fenix.R import org.mozilla.fenix.databinding.DownloadDialogLayoutBinding import org.mozilla.fenix.ext.settings @@ -99,10 +98,6 @@ class DynamicDownloadDialog( download = downloadState, ) - if (downloadState.contentType == "application/pdf") { - Downloads.downloadedPdfOpenCount.add() - } - if (!fileWasOpened) { onCannotOpenFile(downloadState) } diff --git a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt index 17af5619f..00e2004f3 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Activity.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Activity.kt @@ -5,16 +5,16 @@ package org.mozilla.fenix.ext import android.app.Activity -import android.view.View -import android.view.WindowManager -import mozilla.components.concept.base.crash.Breadcrumb import android.app.role.RoleManager import android.content.Intent import android.os.Build import android.provider.Settings +import android.view.View +import android.view.WindowManager import androidx.annotation.DrawableRes import androidx.appcompat.app.AppCompatActivity import androidx.core.os.bundleOf +import mozilla.components.concept.base.crash.Breadcrumb import mozilla.components.concept.engine.EngineSession import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.HomeActivity diff --git a/app/src/main/java/org/mozilla/fenix/ext/Configuration.kt b/app/src/main/java/org/mozilla/fenix/ext/Configuration.kt new file mode 100644 index 000000000..0c304ae7d --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/ext/Configuration.kt @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ext + +import android.content.Context +import androidx.preference.PreferenceManager +import mozilla.components.service.glean.config.Configuration +import org.mozilla.fenix.BuildConfig +import org.mozilla.fenix.R + +/** + * Get custom Glean server URL if available. + */ +fun getCustomGleanServerUrlIfAvailable(context: Context): String? { + return if (BuildConfig.GLEAN_CUSTOM_URL.isNullOrEmpty()) { + PreferenceManager.getDefaultSharedPreferences(context).getString( + context.getPreferenceKey(R.string.pref_key_custom_glean_server_url), + null, + ) + } else { + BuildConfig.GLEAN_CUSTOM_URL + } +} + +/** + * Applies the custom Glean server URL to the Configuration if available. + */ +fun Configuration.setCustomEndpointIfAvailable(serverEndpoint: String?): Configuration { + if (!serverEndpoint.isNullOrEmpty()) { + return copy(serverEndpoint = serverEndpoint) + } + + return this +} diff --git a/app/src/main/java/org/mozilla/fenix/ext/Context.kt b/app/src/main/java/org/mozilla/fenix/ext/Context.kt index cb355b70f..8afb8b727 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Context.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Context.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.ext import android.app.Activity import android.content.Context import android.content.Intent +import android.content.res.Configuration import android.os.Build import android.provider.Settings import android.view.ContextThemeWrapper @@ -103,3 +104,11 @@ fun Context.navigateToNotificationsSettings() { } startActivity(intent) } + +/** + * Helper function used to determine if the user's device is set to dark mode. + * + * @return true if the system is considered to be in dark theme. + */ +fun Context.isSystemInDarkTheme(): Boolean = + resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES diff --git a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt index bbfcb84e3..c25c42429 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt @@ -11,7 +11,6 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.navigation.NavDirections import androidx.navigation.NavOptions -import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.findNavController import mozilla.components.concept.base.crash.Breadcrumb import org.mozilla.fenix.NavHostActivity @@ -25,7 +24,7 @@ val Fragment.requireComponents: Components get() = requireContext().components fun Fragment.nav(@IdRes id: Int?, directions: NavDirections, options: NavOptions? = null) { - findNavController(this).nav(id, directions, options) + findNavController().nav(id, directions, options) } fun Fragment.getPreferenceKey(@StringRes resourceId: Int): String = getString(resourceId) diff --git a/app/src/main/java/org/mozilla/fenix/ext/SpannableString.kt b/app/src/main/java/org/mozilla/fenix/ext/SpannableString.kt index a5cc5cb5f..0dce7cf83 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/SpannableString.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/SpannableString.kt @@ -11,7 +11,7 @@ import android.text.style.AbsoluteSizeSpan import android.text.style.ForegroundColorSpan import androidx.annotation.AttrRes import androidx.annotation.Dimension -import androidx.annotation.Dimension.DP +import androidx.annotation.Dimension.Companion.DP import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.util.dpToPx diff --git a/app/src/main/java/org/mozilla/fenix/ext/String.kt b/app/src/main/java/org/mozilla/fenix/ext/String.kt index b9c710617..618172d8e 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/String.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/String.kt @@ -11,9 +11,9 @@ import android.util.Patterns import android.webkit.URLUtil import androidx.compose.runtime.Composable import androidx.core.net.toUri -import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.lib.publicsuffixlist.PublicSuffixList import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes +import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.inComposePreview import java.net.IDN diff --git a/app/src/main/java/org/mozilla/fenix/ext/View.kt b/app/src/main/java/org/mozilla/fenix/ext/View.kt index feb645248..f8891e35f 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/View.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/View.kt @@ -12,7 +12,7 @@ import android.view.TouchDelegate import android.view.View import android.view.accessibility.AccessibilityNodeInfo import androidx.annotation.Dimension -import androidx.annotation.Dimension.DP +import androidx.annotation.Dimension.Companion.DP import androidx.annotation.VisibleForTesting import androidx.core.view.WindowInsetsCompat import mozilla.components.support.ktx.android.util.dpToPx diff --git a/app/src/main/java/org/mozilla/fenix/gleanplumb/CustomAttributeProvider.kt b/app/src/main/java/org/mozilla/fenix/gleanplumb/CustomAttributeProvider.kt index c0a3d697d..d86824032 100644 --- a/app/src/main/java/org/mozilla/fenix/gleanplumb/CustomAttributeProvider.kt +++ b/app/src/main/java/org/mozilla/fenix/gleanplumb/CustomAttributeProvider.kt @@ -9,8 +9,8 @@ import org.json.JSONObject import org.mozilla.fenix.ext.settings import org.mozilla.fenix.utils.BrowsersCache import java.text.SimpleDateFormat -import java.util.Locale import java.util.Calendar +import java.util.Locale /** * Custom attributes that the messaging framework will use to evaluate if message is eligible diff --git a/app/src/main/java/org/mozilla/fenix/gleanplumb/MessagingFeature.kt b/app/src/main/java/org/mozilla/fenix/gleanplumb/MessagingFeature.kt index f7df88b76..9a27bb159 100644 --- a/app/src/main/java/org/mozilla/fenix/gleanplumb/MessagingFeature.kt +++ b/app/src/main/java/org/mozilla/fenix/gleanplumb/MessagingFeature.kt @@ -12,11 +12,11 @@ import org.mozilla.fenix.components.appstate.AppAction.MessagingAction /** * A message observer that updates the provided. */ -class MessagingFeature(val store: AppStore) : LifecycleAwareFeature { +class MessagingFeature(val appStore: AppStore) : LifecycleAwareFeature { override fun start() { if (FeatureFlags.messagingFeature) { - store.dispatch(MessagingAction.Evaluate) + appStore.dispatch(MessagingAction.Evaluate) } } diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index 7bdf82337..72df445e6 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -255,7 +255,7 @@ class HomeFragment : Fragment() { if (requireContext().settings().isExperimentationEnabled) { messagingFeature.set( feature = MessagingFeature( - store = requireComponents.appStore, + appStore = requireComponents.appStore, ), owner = viewLifecycleOwner, view = binding.root, @@ -266,7 +266,7 @@ class HomeFragment : Fragment() { topSitesFeature.set( feature = TopSitesFeature( view = DefaultTopSitesView( - store = components.appStore, + appStore = components.appStore, settings = components.settings, ), storage = components.core.topSitesStorage, @@ -994,22 +994,7 @@ class HomeFragment : Fragment() { } binding.wordmarkText.imageTintList = tintColor - - // Need to preemptively apply the new theme to the private browsing button drawable - // See https://github.com/mozilla-mobile/fenix/issues/26644#issuecomment-1254961616 - (activity as? HomeActivity)?.themeManager?.let { themeManager -> - with(binding.privateBrowsingButton) { - val drawable = VectorDrawableCompat.create( - resources, - R.drawable.private_browsing_button, - resources.newTheme().apply { - applyStyle(themeManager.currentThemeResource, true) - }, - ) - setImageDrawable(drawable) - imageTintList = tintColor - } - } + binding.privateBrowsingButton.imageTintList = tintColor } private fun observeWallpaperUpdates() { diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt index 60a28586f..a5425ad61 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeMenu.kt @@ -100,7 +100,7 @@ class HomeMenu( private fun syncSignInMenuItem(): BrowserMenuImageText? { val syncItemTitle = if (context.components.backgroundServices.accountManagerAvailableQueue.isReady()) { - accountManager.accountProfileEmail ?: context.getString(R.string.sync_menu_sign_in) + accountManager.accountProfileEmail ?: context.getString(R.string.sync_menu_sync_and_save_data) } else { null } diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeMenuBuilder.kt b/app/src/main/java/org/mozilla/fenix/home/HomeMenuBuilder.kt index efd819370..d964670b2 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeMenuBuilder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeMenuBuilder.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.home import android.content.Context import android.view.View import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.core.content.ContextCompat import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt index 384badb86..7f3a2942d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt +++ b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt @@ -35,6 +35,7 @@ import mozilla.components.browser.state.state.recover.RecoverableTab import mozilla.components.concept.engine.Engine import mozilla.components.feature.tab.collections.Tab import mozilla.components.feature.tab.collections.TabCollection +import org.mozilla.fenix.R import org.mozilla.fenix.R.drawable import org.mozilla.fenix.R.string import org.mozilla.fenix.compose.list.ExpandableListHeader @@ -64,7 +65,7 @@ private val expandedCollectionShape = RoundedCornerShape(topStart = 8.dp, topEnd * @param onCollectionMenuOpened Invoked when the user clicks to open a menu for the collection. */ @Composable -@Suppress("LongParameterList") +@Suppress("LongParameterList", "LongMethod") fun Collection( collection: TabCollection, expanded: Boolean, @@ -79,7 +80,14 @@ fun Collection( Card( modifier = Modifier .semantics(mergeDescendants = true) {} - .clickable { onToggleCollectionExpanded(collection, !isExpanded) } + .clickable( + onClickLabel = if (isExpanded) { + stringResource(R.string.a11y_action_label_collapse) + } else { + stringResource(R.string.a11y_action_label_expand) + }, + onClick = { onToggleCollectionExpanded(collection, !isExpanded) }, + ) .height(48.dp), shape = if (isExpanded) expandedCollectionShape else collapsedCollectionShape, backgroundColor = FirefoxTheme.colors.layer2, diff --git a/app/src/main/java/org/mozilla/fenix/home/intent/CrashReporterIntentProcessor.kt b/app/src/main/java/org/mozilla/fenix/home/intent/CrashReporterIntentProcessor.kt index b3002a07c..06dc2348a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/intent/CrashReporterIntentProcessor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/intent/CrashReporterIntentProcessor.kt @@ -9,22 +9,22 @@ import android.util.Log import androidx.navigation.NavController import mozilla.components.lib.crash.Crash import mozilla.components.lib.crash.Crash.NativeCodeCrash +import mozilla.components.lib.crash.CrashReporter import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.appstate.AppAction -import mozilla.components.lib.crash.CrashReporter /** * Process the [Intent] from [CrashReporter] through which the app is informed about * recoverable native crashes. */ -class CrashReporterIntentProcessor(private val store: AppStore) : HomeIntentProcessor { +class CrashReporterIntentProcessor(private val appStore: AppStore) : HomeIntentProcessor { override fun process(intent: Intent, navController: NavController, out: Intent): Boolean { return if (Crash.isCrashIntent(intent)) { val crash = Crash.fromIntent(intent) // If only a child process crashed we can handle this gracefully. if ((crash as? NativeCodeCrash)?.isFatal == false) { - store.dispatch(AppAction.AddNonFatalCrash(crash)) + appStore.dispatch(AppAction.AddNonFatalCrash(crash)) } else { // A fatal crash means the app's main process is affected. // An UncaughtExceptionCrash refers to a [Throwable] that would otherwise crash the app diff --git a/app/src/main/java/org/mozilla/fenix/home/intent/StartSearchIntentProcessor.kt b/app/src/main/java/org/mozilla/fenix/home/intent/StartSearchIntentProcessor.kt index feadb1900..adde11b87 100644 --- a/app/src/main/java/org/mozilla/fenix/home/intent/StartSearchIntentProcessor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/intent/StartSearchIntentProcessor.kt @@ -48,7 +48,7 @@ class StartSearchIntentProcessor : HomeIntentProcessor { } directions?.let { val options = navOptions { - popUpTo = R.id.homeFragment + popUpTo(R.id.homeFragment) } navController.nav(null, it, options) } diff --git a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketCategoriesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketCategoriesViewHolder.kt index 5283300e5..1e3d1a044 100644 --- a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketCategoriesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketCategoriesViewHolder.kt @@ -5,12 +5,14 @@ package org.mozilla.fenix.home.pocket import android.view.View +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -24,6 +26,7 @@ import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.compose.home.HomeSectionHeader import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.Theme +import org.mozilla.fenix.wallpapers.WallpaperState internal const val POCKET_CATEGORIES_SELECTED_AT_A_TIME_COUNT = 8 @@ -55,12 +58,37 @@ class PocketCategoriesViewHolder( val categoriesSelections = components.appStore .observeAsComposableState { state -> state.pocketStoriesCategoriesSelections }.value + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default + + var selectedBackgroundColor: Color? = null + var unselectedBackgroundColor: Color? = null + var selectedTextColor: Color? = null + var unselectedTextColor: Color? = null + wallpaperState.composeRunIfWallpaperCardColorsAreAvailable { cardColorLight, cardColorDark -> + if (isSystemInDarkTheme()) { + selectedBackgroundColor = cardColorDark + unselectedBackgroundColor = cardColorLight + selectedTextColor = FirefoxTheme.colors.textActionPrimary + unselectedTextColor = FirefoxTheme.colors.textActionSecondary + } else { + selectedBackgroundColor = cardColorLight + unselectedBackgroundColor = cardColorDark + selectedTextColor = FirefoxTheme.colors.textActionSecondary + unselectedTextColor = FirefoxTheme.colors.textActionPrimary + } + } + // See the detailed comment in PocketStoriesViewHolder for reasoning behind this change. if (!homeScreenReady) return Column { Spacer(Modifier.height(24.dp)) PocketTopics( + selectedBackgroundColor = selectedBackgroundColor, + unselectedBackgroundColor = unselectedBackgroundColor, + selectedTextColor = selectedTextColor, + unselectedTextColor = unselectedTextColor, categories = categories ?: emptyList(), categoriesSelections = categoriesSelections ?: emptyList(), onCategoryClick = interactor::onCategoryClicked, @@ -75,6 +103,10 @@ class PocketCategoriesViewHolder( @Composable private fun PocketTopics( + selectedTextColor: Color? = null, + unselectedTextColor: Color? = null, + selectedBackgroundColor: Color? = null, + unselectedBackgroundColor: Color? = null, categories: List = emptyList(), categoriesSelections: List = emptyList(), onCategoryClick: (PocketRecommendedStoriesCategory) -> Unit, @@ -89,6 +121,10 @@ private fun PocketTopics( PocketStoriesCategories( categories = categories, selections = categoriesSelections, + selectedTextColor = selectedTextColor, + unselectedTextColor = unselectedTextColor, + selectedBackgroundColor = selectedBackgroundColor, + unselectedBackgroundColor = unselectedBackgroundColor, onCategoryClick = onCategoryClick, modifier = Modifier .fillMaxWidth(), diff --git a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesComposables.kt b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesComposables.kt index 014fbf8ed..4e58288c6 100644 --- a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesComposables.kt +++ b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesComposables.kt @@ -31,6 +31,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.graphics.Color @@ -44,6 +45,8 @@ import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -98,11 +101,14 @@ private val placeholderStory = PocketRecommendedStory("", "", "", "", "", 0, 0) * Displays a single [PocketRecommendedStory]. * * @param story The [PocketRecommendedStory] to be displayed. + * @param backgroundColor The background [Color] of the story. * @param onStoryClick Callback for when the user taps on this story. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun PocketStory( @PreviewParameter(PocketStoryProvider::class) story: PocketRecommendedStory, + backgroundColor: Color, onStoryClick: (PocketRecommendedStory) -> Unit, ) { val imageUrl = story.imageUrl.replace( @@ -113,10 +119,15 @@ fun PocketStory( val isValidTimeToRead = story.timeToRead >= 0 ListItemTabLarge( imageUrl = imageUrl, + backgroundColor = backgroundColor, onClick = { onStoryClick(story) }, title = { Text( text = story.title, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.story.title" + }, color = FirefoxTheme.colors.textPrimary, overflow = TextOverflow.Ellipsis, maxLines = 2, @@ -129,6 +140,10 @@ fun PocketStory( } else if (isValidPublisher) { Text( text = story.publisher, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.story.publisher" + }, color = FirefoxTheme.colors.textSecondary, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -137,6 +152,10 @@ fun PocketStory( } else if (isValidTimeToRead) { Text( text = "${story.timeToRead} min", + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.story.timeToRead" + }, color = FirefoxTheme.colors.textSecondary, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -151,11 +170,14 @@ fun PocketStory( * Displays a single [PocketSponsoredStory]. * * @param story The [PocketSponsoredStory] to be displayed. + * @param backgroundColor The background [Color] of the story. * @param onStoryClick Callback for when the user taps on this story. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun PocketSponsoredStory( story: PocketSponsoredStory, + backgroundColor: Color, onStoryClick: (PocketSponsoredStory) -> Unit, ) { val (imageWidth, imageHeight) = with(LocalDensity.current) { @@ -168,10 +190,15 @@ fun PocketSponsoredStory( ListItemTabSurface( imageUrl = imageUrl, + backgroundColor = backgroundColor, onClick = { onStoryClick(story) }, ) { Text( text = story.title, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.sponsoredStory.title" + }, color = FirefoxTheme.colors.textPrimary, overflow = TextOverflow.Ellipsis, maxLines = 2, @@ -182,6 +209,10 @@ fun PocketSponsoredStory( Text( text = stringResource(R.string.pocket_stories_sponsor_indication), + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.sponsoredStory.identifier" + }, color = FirefoxTheme.colors.textSecondary, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -192,6 +223,10 @@ fun PocketSponsoredStory( Text( text = story.sponsor, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.sponsoredStory.sponsor" + }, color = FirefoxTheme.colors.textSecondary, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -208,14 +243,18 @@ fun PocketSponsoredStory( * @param stories The list of [PocketStory]ies to be displayed. Expect a list with 8 items. * @param contentPadding Dimension for padding the content after it has been clipped. * This space will be used for shadows and also content rendering when the list is scrolled. + * @param backgroundColor The background [Color] of each story. * @param onStoryShown Callback for when a certain story is visible to the user. * @param onStoryClicked Callback for when the user taps on a recommended story. * @param onDiscoverMoreClicked Callback for when the user taps an element which contains an */ +@OptIn(ExperimentalComposeUiApi::class) +@Suppress("LongParameterList") @Composable fun PocketStories( @PreviewParameter(PocketStoryProvider::class) stories: List, contentPadding: Dp, + backgroundColor: Color = FirefoxTheme.colors.layer2, onStoryShown: (PocketStory, Pair) -> Unit, onStoryClicked: (PocketStory, Pair) -> Unit, onDiscoverMoreClicked: (String) -> Unit, @@ -228,6 +267,10 @@ fun PocketStories( val flingBehavior = EagerFlingBehavior(lazyRowState = listState) LazyRow( + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.stories" + }, contentPadding = PaddingValues(horizontal = contentPadding), state = listState, flingBehavior = flingBehavior, @@ -241,7 +284,10 @@ fun PocketStories( onDiscoverMoreClicked("https://getpocket.com/explore?$POCKET_FEATURE_UTM_KEY_VALUE") } } else if (story is PocketRecommendedStory) { - PocketStory(story) { + PocketStory( + story = story, + backgroundColor = backgroundColor, + ) { val uri = Uri.parse(story.url) .buildUpon() .appendQueryParameter(URI_PARAM_UTM_KEY, POCKET_STORIES_UTM_VALUE) @@ -254,7 +300,10 @@ fun PocketStories( onStoryShown(story, rowIndex to columnIndex) }, ) { - PocketSponsoredStory(story) { + PocketSponsoredStory( + story = story, + backgroundColor = backgroundColor, + ) { onStoryClicked(story, rowIndex to columnIndex) } } @@ -359,23 +408,45 @@ private fun Rect.getIntersectPercentage(realSize: IntSize, other: Rect): Float { * * @param categories The categories needed to be displayed. * @param selections List of categories currently selected. + * @param selectedTextColor Text [Color] when the category is selected. + * @param unselectedTextColor Text [Color] when the category is not selected. + * @param selectedBackgroundColor Background [Color] when the category is selected. + * @param unselectedBackgroundColor Background [Color] when the category is not selected. * @param onCategoryClick Callback for when the user taps a category. * @param modifier [Modifier] to be applied to the layout. */ +@OptIn(ExperimentalComposeUiApi::class) +@Suppress("LongParameterList") @Composable fun PocketStoriesCategories( categories: List, selections: List, + selectedTextColor: Color? = null, + unselectedTextColor: Color? = null, + selectedBackgroundColor: Color? = null, + unselectedBackgroundColor: Color? = null, onCategoryClick: (PocketRecommendedStoriesCategory) -> Unit, modifier: Modifier = Modifier, ) { - Box(modifier = modifier) { + Box( + modifier = modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.categories" + }, + ) { StaggeredHorizontalGrid( horizontalItemsSpacing = 16.dp, verticalItemsSpacing = 16.dp, ) { categories.filter { it.name != POCKET_STORIES_DEFAULT_CATEGORY_NAME }.forEach { category -> - SelectableChip(category.name, selections.map { it.name }.contains(category.name)) { + SelectableChip( + text = category.name, + isSelected = selections.map { it.name }.contains(category.name), + selectedTextColor = selectedTextColor, + unselectedTextColor = unselectedTextColor, + selectedBackgroundColor = selectedBackgroundColor, + unselectedBackgroundColor = unselectedBackgroundColor, + ) { onCategoryClick(category) } } @@ -393,6 +464,7 @@ fun PocketStoriesCategories( * @param textColor [Color] to be applied to the text. * @param linkTextColor [Color] of the link text. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun PoweredByPocketHeader( onLearnMoreClicked: (String) -> Unit, @@ -406,7 +478,10 @@ fun PoweredByPocketHeader( val linkEndIndex = linkStartIndex + link.length Column( - modifier = modifier, + modifier = modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.header" + }, horizontalAlignment = Alignment.CenterHorizontally, ) { Row( @@ -426,20 +501,36 @@ fun PoweredByPocketHeader( Column { Text( - text = stringResource(R.string.pocket_stories_feature_title), + text = stringResource( + R.string.pocket_stories_feature_title_2, + LocalContext.current.getString(R.string.pocket_product_name), + ), + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.header.title" + }, color = textColor, style = FirefoxTheme.typography.caption, ) - ClickableSubstringLink( - text = text, - textColor = textColor, - linkTextColor = linkTextColor, - linkTextDecoration = TextDecoration.Underline, - clickableStartIndex = linkStartIndex, - clickableEndIndex = linkEndIndex, + Box( + modifier = modifier.semantics { + testTagsAsResourceId = true + testTag = "pocket.header.subtitle" + }, ) { - onLearnMoreClicked("https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE") + ClickableSubstringLink( + text = text, + textColor = textColor, + linkTextColor = linkTextColor, + linkTextDecoration = TextDecoration.Underline, + clickableStartIndex = linkStartIndex, + clickableEndIndex = linkEndIndex, + ) { + onLearnMoreClicked( + "https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE", + ) + } } } } diff --git a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesController.kt b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesController.kt index 0bb1618fd..0a660e56e 100644 --- a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesController.kt @@ -12,6 +12,7 @@ import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory import mozilla.components.service.pocket.PocketStory.PocketSponsoredStory import mozilla.components.service.pocket.ext.getCurrentFlightImpressions import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.GleanMetrics.Pings import org.mozilla.fenix.GleanMetrics.Pocket import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R @@ -93,6 +94,8 @@ internal class DefaultPocketStoriesController( timesShown = storyShown.getCurrentFlightImpressions().size.inc().toString(), ), ) + Pocket.spocShim.set(storyShown.shim.impression) + Pings.spoc.submit(Pings.spocReasonCodes.impression) } else -> { // no-op @@ -169,6 +172,8 @@ internal class DefaultPocketStoriesController( timesShown = storyClicked.getCurrentFlightImpressions().size.inc().toString(), ), ) + Pocket.spocShim.set(storyClicked.shim.click) + Pings.spoc.submit(Pings.spocReasonCodes.click) } } } diff --git a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesViewHolder.kt index d7ffc9eac..f8d799a38 100644 --- a/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesViewHolder.kt @@ -23,12 +23,12 @@ import androidx.recyclerview.widget.RecyclerView import mozilla.components.lib.state.ext.observeAsComposableState import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory import org.mozilla.fenix.R -import org.mozilla.fenix.R.dimen import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.compose.home.HomeSectionHeader import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.theme.Theme +import org.mozilla.fenix.wallpapers.WallpaperState /** * [RecyclerView.ViewHolder] for displaying the list of [PocketRecommendedStory]s from [AppStore]. @@ -49,7 +49,7 @@ class PocketStoriesViewHolder( @Composable override fun Content() { - val horizontalPadding = dimensionResource(dimen.home_item_horizontal_margin) + val horizontalPadding = dimensionResource(R.dimen.home_item_horizontal_margin) val homeScreenReady = components.appStore .observeAsComposableState { state -> state.firstFrameDrawn }.value ?: false @@ -57,6 +57,9 @@ class PocketStoriesViewHolder( val stories = components.appStore .observeAsComposableState { state -> state.pocketStories }.value + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default + /* This was originally done to address this perf issue: * https://github.com/mozilla-mobile/fenix/issues/25545 for details. * It was determined that Pocket content was becoming available before the first frame was @@ -88,11 +91,12 @@ class PocketStoriesViewHolder( Spacer(Modifier.height(16.dp)) PocketStories( - stories ?: emptyList(), - horizontalPadding, - interactor::onStoryShown, - interactor::onStoryClicked, - interactor::onDiscoverMoreClicked, + stories = stories ?: emptyList(), + contentPadding = horizontalPadding, + backgroundColor = wallpaperState.wallpaperCardColor, + onStoryShown = interactor::onStoryShown, + onStoryClicked = interactor::onStoryClicked, + onDiscoverMoreClicked = interactor::onDiscoverMoreClicked, ) } } @@ -113,6 +117,7 @@ fun PocketStoriesViewHolderPreview() { PocketStories( stories = getFakePocketStories(8), contentPadding = 0.dp, + backgroundColor = FirefoxTheme.colors.layer2, onStoryShown = { _, _ -> }, onStoryClicked = { _, _ -> }, onDiscoverMoreClicked = {}, diff --git a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/controller/RecentBookmarksController.kt b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/controller/RecentBookmarksController.kt index 8e809191e..b2eb61dbf 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/controller/RecentBookmarksController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/controller/RecentBookmarksController.kt @@ -5,7 +5,7 @@ package org.mozilla.fenix.home.recentbookmarks.controller import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.navigation.NavController import mozilla.appservices.places.BookmarkRoot import mozilla.components.concept.engine.EngineSession diff --git a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt index a891b9e1b..701e2ff1a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarks.kt @@ -34,9 +34,14 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -64,17 +69,24 @@ private val imageModifier = Modifier * * @param bookmarks List of [RecentBookmark]s to display. * @param menuItems List of [RecentBookmarksMenuItem] shown when long clicking a [RecentBookmarkItem] + * @param backgroundColor The background [Color] of each bookmark. * @param onRecentBookmarkClick Invoked when the user clicks on a recent bookmark. * @param onRecentBookmarkLongClick Invoked when the user long clicks on a recent bookmark. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun RecentBookmarks( bookmarks: List, menuItems: List, + backgroundColor: Color, onRecentBookmarkClick: (RecentBookmark) -> Unit = {}, onRecentBookmarkLongClick: () -> Unit = {}, ) { LazyRow( + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.bookmarks" + }, contentPadding = PaddingValues(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { @@ -82,6 +94,7 @@ fun RecentBookmarks( RecentBookmarkItem( bookmark = bookmark, menuItems = menuItems, + backgroundColor = backgroundColor, onRecentBookmarkClick = onRecentBookmarkClick, onRecentBookmarkLongClick = onRecentBookmarkLongClick, ) @@ -93,14 +106,20 @@ fun RecentBookmarks( * A recent bookmark item. * * @param bookmark The [RecentBookmark] to display. + * @param menuItems The list of [RecentBookmarksMenuItem] shown when long clicking on the recent bookmark item. + * @param backgroundColor The background [Color] of the recent bookmark item. * @param onRecentBookmarkClick Invoked when the user clicks on the recent bookmark item. * @param onRecentBookmarkLongClick Invoked when the user long clicks on the recent bookmark item. */ -@OptIn(ExperimentalFoundationApi::class) +@OptIn( + ExperimentalFoundationApi::class, + ExperimentalComposeUiApi::class, +) @Composable private fun RecentBookmarkItem( bookmark: RecentBookmark, menuItems: List, + backgroundColor: Color, onRecentBookmarkClick: (RecentBookmark) -> Unit = {}, onRecentBookmarkLongClick: () -> Unit = {}, ) { @@ -118,7 +137,7 @@ private fun RecentBookmarkItem( }, ), shape = cardShape, - backgroundColor = FirefoxTheme.colors.layer2, + backgroundColor = backgroundColor, elevation = 6.dp, ) { Column( @@ -132,6 +151,10 @@ private fun RecentBookmarkItem( Text( text = bookmark.title ?: bookmark.url ?: "", + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.bookmark.title" + }, color = FirefoxTheme.colors.textPrimary, overflow = TextOverflow.Ellipsis, maxLines = 1, @@ -215,6 +238,7 @@ private fun PlaceholderBookmarkImage() { * @param recentBookmark The [RecentBookmark] for which this menu is shown. * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable private fun RecentBookmarksMenu( showMenu: Boolean, @@ -226,7 +250,11 @@ private fun RecentBookmarksMenu( expanded = showMenu, onDismissRequest = { onDismissRequest() }, modifier = Modifier - .background(color = FirefoxTheme.colors.layer2), + .background(color = FirefoxTheme.colors.layer2) + .semantics { + testTagsAsResourceId = true + testTag = "recent.bookmark.menu" + }, ) { for (item in menuItems) { DropdownMenuItem( @@ -277,6 +305,7 @@ private fun RecentBookmarksPreview() { ), ), menuItems = listOf(), + backgroundColor = FirefoxTheme.colors.layer2, ) } } diff --git a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarksViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarksViewHolder.kt index 5f0b69046..8ea83ce60 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarksViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentbookmarks/view/RecentBookmarksViewHolder.kt @@ -15,6 +15,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor +import org.mozilla.fenix.wallpapers.WallpaperState import org.mozilla.fenix.GleanMetrics.RecentBookmarks as RecentBookmarksMetrics class RecentBookmarksViewHolder( @@ -33,11 +34,13 @@ class RecentBookmarksViewHolder( @Composable override fun Content() { - val recentBookmarks = components.appStore - .observeAsComposableState { state -> state.recentBookmarks } + val recentBookmarks = components.appStore.observeAsComposableState { state -> state.recentBookmarks } + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default RecentBookmarks( bookmarks = recentBookmarks.value ?: emptyList(), + backgroundColor = wallpaperState.wallpaperCardColor, onRecentBookmarkClick = interactor::onRecentBookmarkClicked, menuItems = listOf( RecentBookmarksMenuItem( diff --git a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt index b1a3d6c71..c0f8a7c14 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTab.kt @@ -34,6 +34,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource @@ -43,10 +44,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import mozilla.components.concept.sync.DeviceType +import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.R import org.mozilla.fenix.compose.Image import org.mozilla.fenix.compose.ThumbnailCard -import org.mozilla.fenix.compose.button.Button +import org.mozilla.fenix.compose.button.SecondaryButton import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab import org.mozilla.fenix.home.recenttabs.RecentTab import org.mozilla.fenix.theme.FirefoxTheme @@ -56,16 +58,22 @@ import org.mozilla.fenix.theme.Theme * A recent synced tab card. * * @param tab The [RecentSyncedTab] to display. + * @param backgroundColor The background [Color] of the item. + * @param buttonBackgroundColor The background [Color] of the item's button. + * @param buttonTextColor The [Color] of the button's text. * @param onRecentSyncedTabClick Invoked when the user clicks on the recent synced tab. * @param onSeeAllSyncedTabsButtonClick Invoked when user clicks on the "See all" button in the synced tab card. * @param onRemoveSyncedTab Invoked when user clicks on the "Remove" dropdown menu option. * @param onRecentSyncedTabLongClick Invoked when user long presses the recent synced tab. */ @OptIn(ExperimentalFoundationApi::class) -@Suppress("LongMethod") +@Suppress("LongMethod", "LongParameterList") @Composable fun RecentSyncedTab( tab: RecentSyncedTab?, + backgroundColor: Color = FirefoxTheme.colors.layer2, + buttonBackgroundColor: Color = FirefoxTheme.colors.actionSecondary, + buttonTextColor: Color = FirefoxTheme.colors.textActionSecondary, onRecentSyncedTabClick: (RecentSyncedTab) -> Unit, onSeeAllSyncedTabsButtonClick: () -> Unit, onRemoveSyncedTab: (RecentSyncedTab) -> Unit, @@ -90,7 +98,7 @@ fun RecentSyncedTab( }, ), shape = RoundedCornerShape(8.dp), - backgroundColor = FirefoxTheme.colors.layer2, + backgroundColor = backgroundColor, elevation = 6.dp, ) { Column(modifier = Modifier.padding(16.dp)) { @@ -127,7 +135,7 @@ fun RecentSyncedTab( RecentTabTitlePlaceholder() } else { Text( - text = tab.title, + text = tab.title.trimmed(), color = FirefoxTheme.colors.textPrimary, fontSize = 14.sp, overflow = TextOverflow.Ellipsis, @@ -171,19 +179,14 @@ fun RecentSyncedTab( Spacer(modifier = Modifier.height(32.dp)) - Button( + SecondaryButton( text = if (tab != null) { stringResource(R.string.recent_tabs_see_all_synced_tabs_button_text) } else { "" }, - textColor = FirefoxTheme.colors.textActionSecondary, - backgroundColor = if (tab == null) { - FirefoxTheme.colors.layer3 - } else { - FirefoxTheme.colors.actionSecondary - }, - tint = FirefoxTheme.colors.iconActionSecondary, + textColor = buttonTextColor, + backgroundColor = buttonBackgroundColor, onClick = onSeeAllSyncedTabsButtonClick, ) } @@ -301,6 +304,7 @@ private fun LoadingRecentSyncedTab() { FirefoxTheme(theme = Theme.getTheme()) { RecentSyncedTab( tab = null, + buttonBackgroundColor = FirefoxTheme.colors.layer3, onRecentSyncedTabClick = {}, onSeeAllSyncedTabsButtonClick = {}, onRemoveSyncedTab = {}, diff --git a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTabViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTabViewHolder.kt index e4f17d769..75b681285 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTabViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentsyncedtabs/view/RecentSyncedTabViewHolder.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.home.recentsyncedtabs.view import android.view.View +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.LifecycleOwner @@ -14,6 +15,9 @@ import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState import org.mozilla.fenix.home.recentsyncedtabs.interactor.RecentSyncedTabInteractor +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.wallpapers.Wallpaper +import org.mozilla.fenix.wallpapers.WallpaperState /** * View holder for a recent synced tab item. @@ -42,8 +46,11 @@ class RecentSyncedTabViewHolder( @Composable override fun Content() { - val recentSyncedTabState = - components.appStore.observeAsComposableState { state -> state.recentSyncedTabState } + val recentSyncedTabState = components.appStore.observeAsComposableState { state -> state.recentSyncedTabState } + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default + val isWallpaperNotDefault = !Wallpaper.nameIsDefault(wallpaperState.currentWallpaper.name) + recentSyncedTabState.value?.let { val syncedTab = when (it) { RecentSyncedTabState.None, @@ -51,8 +58,22 @@ class RecentSyncedTabViewHolder( -> null is RecentSyncedTabState.Success -> it.tabs.firstOrNull() } + val buttonBackgroundColor = when { + syncedTab != null && isWallpaperNotDefault -> FirefoxTheme.colors.layer1 + syncedTab != null -> FirefoxTheme.colors.actionSecondary + else -> FirefoxTheme.colors.layer3 + } + val buttonTextColor = when { + wallpaperState.currentWallpaper.cardColorDark != null && + isSystemInDarkTheme() -> FirefoxTheme.colors.textPrimary + else -> FirefoxTheme.colors.textActionSecondary + } + RecentSyncedTab( tab = syncedTab, + backgroundColor = wallpaperState.wallpaperCardColor, + buttonBackgroundColor = buttonBackgroundColor, + buttonTextColor = buttonTextColor, onRecentSyncedTabClick = recentSyncedTabInteractor::onRecentSyncedTabClicked, onSeeAllSyncedTabsButtonClick = recentSyncedTabInteractor::onSyncedTabShowAllClicked, onRemoveSyncedTab = recentSyncedTabInteractor::onRemovedRecentSyncedTab, diff --git a/app/src/main/java/org/mozilla/fenix/home/recenttabs/controller/RecentTabController.kt b/app/src/main/java/org/mozilla/fenix/home/recenttabs/controller/RecentTabController.kt index 3168dabd9..f344a81f0 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recenttabs/controller/RecentTabController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recenttabs/controller/RecentTabController.kt @@ -5,7 +5,7 @@ package org.mozilla.fenix.home.recenttabs.controller import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.navigation.NavController import mozilla.components.browser.state.store.BrowserStore import mozilla.components.feature.tabs.TabsUseCases.SelectTabUseCase diff --git a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabViewHolder.kt index eb598a8ea..f53bd1f61 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabViewHolder.kt @@ -14,6 +14,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.home.recenttabs.interactor.RecentTabInteractor +import org.mozilla.fenix.wallpapers.WallpaperState /** * View holder for a recent tab item. @@ -42,9 +43,12 @@ class RecentTabViewHolder( @Composable override fun Content() { val recentTabs = components.appStore.observeAsComposableState { state -> state.recentTabs } + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default RecentTabs( recentTabs = recentTabs.value ?: emptyList(), + backgroundColor = wallpaperState.wallpaperCardColor, onRecentTabClick = { recentTabInteractor.onRecentTabClicked(it) }, onRecentTabLongClick = { recentTabInteractor.onRecentTabLongClicked() }, menuItems = listOf( diff --git a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt index 8a0fb538e..b731b8f39 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recenttabs/view/RecentTabs.kt @@ -37,12 +37,17 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -52,6 +57,7 @@ import mozilla.components.browser.icons.compose.Placeholder import mozilla.components.browser.icons.compose.WithIcon import mozilla.components.browser.state.state.ContentState import mozilla.components.browser.state.state.TabSessionState +import mozilla.components.support.ktx.kotlin.trimmed import mozilla.components.ui.colors.PhotonColors import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.Image @@ -65,17 +71,25 @@ import org.mozilla.fenix.theme.FirefoxTheme * * @param recentTabs List of [RecentTab] to display. * @param menuItems List of [RecentTabMenuItem] shown long clicking a [RecentTab]. + * @param backgroundColor The background [Color] of each item. * @param onRecentTabClick Invoked when the user clicks on a recent tab. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun RecentTabs( recentTabs: List, menuItems: List, + backgroundColor: Color = FirefoxTheme.colors.layer2, onRecentTabClick: (String) -> Unit = {}, onRecentTabLongClick: () -> Unit = {}, ) { Column( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .semantics { + testTagsAsResourceId = true + testTag = "recent.tabs" + }, verticalArrangement = Arrangement.spacedBy(8.dp), ) { recentTabs.forEach { tab -> @@ -84,6 +98,7 @@ fun RecentTabs( RecentTabItem( tab = tab, menuItems = menuItems, + backgroundColor = backgroundColor, onRecentTabClick = onRecentTabClick, onRecentTabLongClick = onRecentTabLongClick, ) @@ -97,13 +112,19 @@ fun RecentTabs( * A recent tab item. * * @param tab [RecentTab.Tab] that was recently viewed. + * @param backgroundColor The background [Color] of the item. * @param onRecentTabClick Invoked when the user clicks on a recent tab. */ -@OptIn(ExperimentalFoundationApi::class) +@OptIn( + ExperimentalFoundationApi::class, + ExperimentalComposeUiApi::class, +) @Composable +@Suppress("LongMethod") private fun RecentTabItem( tab: RecentTab.Tab, menuItems: List, + backgroundColor: Color, onRecentTabClick: (String) -> Unit = {}, onRecentTabLongClick: () -> Unit = {}, ) { @@ -122,7 +143,7 @@ private fun RecentTabItem( }, ), shape = RoundedCornerShape(8.dp), - backgroundColor = FirefoxTheme.colors.layer2, + backgroundColor = backgroundColor, elevation = 6.dp, ) { Row( @@ -143,7 +164,11 @@ private fun RecentTabItem( verticalArrangement = Arrangement.SpaceBetween, ) { Text( - text = tab.state.content.title.ifEmpty { tab.state.content.url }, + text = tab.state.content.title.ifEmpty { tab.state.content.url.trimmed() }, + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.tab.title" + }, color = FirefoxTheme.colors.textPrimary, fontSize = 14.sp, maxLines = 2, @@ -163,7 +188,11 @@ private fun RecentTabItem( Spacer(modifier = Modifier.width(8.dp)) Text( - text = tab.state.content.url, + text = tab.state.content.url.trimmed(), + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.tab.url" + }, color = FirefoxTheme.colors.textSecondary, fontSize = 12.sp, overflow = TextOverflow.Ellipsis, @@ -188,17 +217,14 @@ private fun RecentTabItem( * @param tab [RecentTab] that was recently viewed. * @param modifier [Modifier] used to draw the image content. * @param contentScale [ContentScale] used to draw image content. - * @param alignment [Alignment] used to draw the image content. */ @Composable fun RecentTabImage( tab: RecentTab.Tab, modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.FillWidth, - alignment: Alignment = Alignment.TopCenter, ) { val previewImageUrl = tab.state.content.previewImageUrl - val thumbnail = tab.state.content.thumbnail when { !previewImageUrl.isNullOrEmpty() -> { @@ -209,15 +235,6 @@ fun RecentTabImage( contentScale = ContentScale.Crop, ) } - thumbnail != null -> { - Image( - painter = BitmapPainter(thumbnail.asImageBitmap()), - contentDescription = null, - modifier = modifier, - contentScale = contentScale, - alignment = alignment, - ) - } else -> ThumbnailCard( url = tab.state.content.url, key = tab.state.id, @@ -237,6 +254,7 @@ fun RecentTabImage( * @param tab The [RecentTab.Tab] for which this menu is shown. * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable private fun RecentTabMenu( showMenu: Boolean, @@ -252,7 +270,11 @@ private fun RecentTabMenu( expanded = showMenu, onDismissRequest = { onDismissRequest() }, modifier = Modifier - .background(color = FirefoxTheme.colors.layer2), + .background(color = FirefoxTheme.colors.layer2) + .semantics { + testTagsAsResourceId = true + testTag = "recent.tab.menu" + }, ) { for (item in menuItems) { DropdownMenuItem( diff --git a/app/src/main/java/org/mozilla/fenix/home/recentvisits/RecentVisitsFeature.kt b/app/src/main/java/org/mozilla/fenix/home/recentvisits/RecentVisitsFeature.kt index af35ce52c..f1bdcd008 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentvisits/RecentVisitsFeature.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentvisits/RecentVisitsFeature.kt @@ -17,7 +17,6 @@ import mozilla.components.concept.storage.HistoryHighlightWeights import mozilla.components.concept.storage.HistoryMetadata import mozilla.components.concept.storage.HistoryMetadataStorage import mozilla.components.support.base.feature.LifecycleAwareFeature -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.appstate.AppAction import org.mozilla.fenix.home.HomeFragment @@ -52,7 +51,6 @@ class RecentVisitsFeature( private val historyHighlightsStorage: Lazy, private val scope: CoroutineScope, private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO, - private val historyImprovementFeatures: Boolean = FeatureFlags.historyImprovementFeatures, ) : LifecycleAwareFeature { private var job: Job? = null @@ -214,11 +212,7 @@ class RecentVisitsFeature( ) } .filter { - if (historyImprovementFeatures) { - it.groupItems.size >= SEARCH_GROUP_MINIMUM_SITES - } else { - true - } + it.groupItems.size >= SEARCH_GROUP_MINIMUM_SITES } } diff --git a/app/src/main/java/org/mozilla/fenix/home/recentvisits/controller/RecentVisitsController.kt b/app/src/main/java/org/mozilla/fenix/home/recentvisits/controller/RecentVisitsController.kt index 338f2ac4c..b769db94f 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentvisits/controller/RecentVisitsController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentvisits/controller/RecentVisitsController.kt @@ -5,7 +5,7 @@ package org.mozilla.fenix.home.recentvisits.controller import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.navigation.NavController import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt index c1cdc9bbb..41baedbbf 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisited.kt @@ -27,7 +27,6 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card -import androidx.compose.material.Divider import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text @@ -38,15 +37,22 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.R +import org.mozilla.fenix.compose.Divider import org.mozilla.fenix.compose.EagerFlingBehavior import org.mozilla.fenix.compose.Favicon import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem @@ -63,26 +69,33 @@ private const val VISITS_PER_COLUMN = 3 * * @param recentVisits List of [RecentlyVisitedItem] to display. * @param menuItems List of [RecentVisitMenuItem] shown long clicking a [RecentlyVisitedItem]. + * @param backgroundColor The background [Color] of each item. * @param onRecentVisitClick Invoked when the user clicks on a recent visit. * @param onRecentVisitLongClick Invoked when the user long clicks on a recent visit. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable fun RecentlyVisited( recentVisits: List, menuItems: List, + backgroundColor: Color = FirefoxTheme.colors.layer2, onRecentVisitClick: (RecentlyVisitedItem, Int) -> Unit = { _, _ -> }, onRecentVisitLongClick: () -> Unit = {}, ) { Card( modifier = Modifier.fillMaxWidth(), shape = RoundedCornerShape(8.dp), - backgroundColor = FirefoxTheme.colors.layer2, + backgroundColor = backgroundColor, elevation = 6.dp, ) { val listState = rememberLazyListState() val flingBehavior = EagerFlingBehavior(lazyRowState = listState) LazyRow( + modifier = Modifier.semantics { + testTagsAsResourceId = true + testTag = "recent.visits" + }, state = listState, contentPadding = PaddingValues(16.dp), horizontalArrangement = Arrangement.spacedBy(32.dp), @@ -134,7 +147,10 @@ fun RecentlyVisited( * @param onRecentVisitClick Invoked when the user clicks on a recent visit. * @param onRecentVisitClick Invoked when the user long clicks on a recently visited group. */ -@OptIn(ExperimentalFoundationApi::class) +@OptIn( + ExperimentalFoundationApi::class, + ExperimentalComposeUiApi::class, +) @Suppress("LongParameterList") @Composable private fun RecentlyVisitedHistoryGroup( @@ -157,7 +173,11 @@ private fun RecentlyVisitedHistoryGroup( isMenuExpanded = true }, ) - .size(268.dp, 56.dp), + .size(268.dp, 56.dp) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visits.group" + }, verticalAlignment = Alignment.CenterVertically, ) { Image( @@ -175,16 +195,25 @@ private fun RecentlyVisitedHistoryGroup( text = recentVisit.title, modifier = Modifier .padding(top = 7.dp, bottom = 2.dp) - .weight(1f), + .weight(1f) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visits.group.title" + }, ) RecentlyVisitedCaption( count = recentVisit.historyMetadata.size, - modifier = Modifier.weight(1f), + modifier = Modifier + .weight(1f) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visits.group.caption" + }, ) if (showDividerLine) { - RecentlyVisitedDivider() + Divider() } } @@ -207,7 +236,10 @@ private fun RecentlyVisitedHistoryGroup( * @param onRecentVisitClick Invoked when the user clicks on a recent visit. * @param onRecentVisitLongClick Invoked when the user long clicks on a recent visit highlight. */ -@OptIn(ExperimentalFoundationApi::class) +@OptIn( + ExperimentalFoundationApi::class, + ExperimentalComposeUiApi::class, +) @Suppress("LongParameterList") @Composable private fun RecentlyVisitedHistoryHighlight( @@ -230,7 +262,11 @@ private fun RecentlyVisitedHistoryHighlight( isMenuExpanded = true }, ) - .size(268.dp, 56.dp), + .size(268.dp, 56.dp) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visits.highlight" + }, verticalAlignment = Alignment.CenterVertically, ) { Favicon(url = recentVisit.url, size = 24.dp) @@ -239,12 +275,17 @@ private fun RecentlyVisitedHistoryHighlight( Box(modifier = Modifier.fillMaxSize()) { RecentlyVisitedTitle( - text = recentVisit.title, - modifier = Modifier.align(Alignment.CenterStart), + text = recentVisit.title.trimmed(), + modifier = Modifier + .align(Alignment.CenterStart) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visits.highlight.title" + }, ) if (showDividerLine) { - RecentlyVisitedDivider(modifier = Modifier.align(Alignment.BottomCenter)) + Divider(modifier = Modifier.align(Alignment.BottomCenter)) } } @@ -318,6 +359,7 @@ private fun RecentlyVisitedCaption( * @param recentVisit The [RecentlyVisitedItem] for which this menu is shown. * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. */ +@OptIn(ExperimentalComposeUiApi::class) @Composable private fun RecentlyVisitedMenu( showMenu: Boolean, @@ -333,7 +375,11 @@ private fun RecentlyVisitedMenu( expanded = showMenu, onDismissRequest = { onDismissRequest() }, modifier = Modifier - .background(color = FirefoxTheme.colors.layer2), + .background(color = FirefoxTheme.colors.layer2) + .semantics { + testTagsAsResourceId = true + testTag = "recent.visit.menu" + }, ) { for (item in menuItems) { DropdownMenuItem( @@ -355,22 +401,6 @@ private fun RecentlyVisitedMenu( } } -/** - * A recent item divider. - * - * @param modifier [Modifier] allowing to perfectly place this. - */ -@Composable -private fun RecentlyVisitedDivider( - modifier: Modifier = Modifier, -) { - Divider( - modifier = modifier, - color = FirefoxTheme.colors.borderPrimary, - thickness = 0.5.dp, - ) -} - /** * Get the indexes in list of all items which have more than half showing. */ diff --git a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisitedViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisitedViewHolder.kt index 6a7a66932..7f7a6a4df 100644 --- a/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisitedViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/recentvisits/view/RecentlyVisitedViewHolder.kt @@ -20,6 +20,7 @@ import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryGroup import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryHighlight import org.mozilla.fenix.home.recentvisits.interactor.RecentVisitsInteractor +import org.mozilla.fenix.wallpapers.WallpaperState /** * View holder for [RecentlyVisitedItem]s. @@ -43,6 +44,8 @@ class RecentlyVisitedViewHolder( override fun Content() { val recentVisits = components.appStore .observeAsComposableState { state -> state.recentHistory } + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default RecentlyVisited( recentVisits = recentVisits.value ?: emptyList(), @@ -59,6 +62,7 @@ class RecentlyVisitedViewHolder( }, ), ), + backgroundColor = wallpaperState.wallpaperCardColor, onRecentVisitClick = { recentlyVisitedItem, pageNumber -> when (recentlyVisitedItem) { is RecentHistoryHighlight -> { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt index dd14e3a59..6fd052569 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt @@ -309,6 +309,7 @@ class SessionControlAdapter( TopPlaceholderViewHolder.LAYOUT_ID -> TopPlaceholderViewHolder(view) TopSitePagerViewHolder.LAYOUT_ID -> TopSitePagerViewHolder( view = view, + appStore = components.appStore, viewLifecycleOwner = viewLifecycleOwner, interactor = interactor, ) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index 6ff7d30fe..1b768d44d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -583,6 +583,7 @@ class DefaultSessionControlController( private fun showShareFragment(shareSubject: String, data: List) { val directions = HomeFragmentDirections.actionGlobalShareFragment( + sessionId = store.state.selectedTabId, shareSubject = shareSubject, data = data.toTypedArray(), ) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/CustomizeHomeButtonViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/CustomizeHomeButtonViewHolder.kt index 52d438031..d72f4a2df 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/CustomizeHomeButtonViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/CustomizeHomeButtonViewHolder.kt @@ -5,19 +5,25 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders import android.view.View +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.LifecycleOwner +import mozilla.components.lib.state.ext.observeAsComposableState import org.mozilla.fenix.R +import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.compose.button.TertiaryButton import org.mozilla.fenix.home.sessioncontrol.CustomizeHomeIteractor +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.wallpapers.WallpaperState class CustomizeHomeButtonViewHolder( composeView: ComposeView, @@ -37,11 +43,24 @@ class CustomizeHomeButtonViewHolder( @Composable override fun Content() { + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default + var buttonColor: Color = FirefoxTheme.colors.actionTertiary + + wallpaperState.composeRunIfWallpaperCardColorsAreAvailable { cardColorLight, cardColorDark -> + buttonColor = if (isSystemInDarkTheme()) { + cardColorDark + } else { + cardColorLight + } + } + Column { Spacer(modifier = Modifier.height(68.dp)) TertiaryButton( text = stringResource(R.string.browser_menu_customize_home_1), + backgroundColor = buttonColor, onClick = interactor::openCustomizeHomePage, ) } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt index 907aaa8f0..0d90c2230 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoCollectionsMessageViewHolder.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders import android.view.View import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.lifecycle.LifecycleOwner import kotlinx.coroutines.flow.map @@ -19,6 +20,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.databinding.NoCollectionsMessageBinding import org.mozilla.fenix.ext.increaseTapArea +import org.mozilla.fenix.ext.isSystemInDarkTheme import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor import org.mozilla.fenix.utils.view.ViewHolder @@ -58,9 +60,10 @@ class NoCollectionsMessageViewHolder( } appStore.flowScoped(viewLifecycleOwner) { flow -> - flow.map { state -> state.wallpaperState.currentWallpaper.textColor } + flow.map { state -> state.wallpaperState } .ifChanged() - .collect { textColor -> + .collect { wallpaperState -> + val textColor = wallpaperState.currentWallpaper.textColor if (textColor == null) { val context = view.context binding.noCollectionsHeader.setTextColor( @@ -78,6 +81,25 @@ class NoCollectionsMessageViewHolder( binding.noCollectionsDescription.setTextColor(color) binding.removeCollectionPlaceholder.setColorFilter(color) } + + var buttonColor = ContextCompat.getColor(view.context, R.color.fx_mobile_action_color_primary) + var buttonTextColor = ContextCompat.getColor( + view.context, + R.color.fx_mobile_text_color_action_primary, + ) + wallpaperState.runIfWallpaperCardColorsAreAvailable { _, _ -> + buttonColor = ContextCompat.getColor(view.context, R.color.fx_mobile_layer_color_1) + + if (!view.context.isSystemInDarkTheme()) { + buttonTextColor = ContextCompat.getColor( + view.context, + R.color.fx_mobile_text_color_action_secondary, + ) + } + } + + binding.addTabsToCollectionsButton.setBackgroundColor(buttonColor) + binding.addTabsToCollectionsButton.setTextColor(buttonTextColor) } } } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/PrivateBrowsingDescriptionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/PrivateBrowsingDescriptionViewHolder.kt index 028a85c7b..a85f18584 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/PrivateBrowsingDescriptionViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/PrivateBrowsingDescriptionViewHolder.kt @@ -95,7 +95,7 @@ fun PrivateBrowsingDescription( .clickable( interactionSource = interactionSource, indication = null, - onClickLabel = stringResource(R.string.link_text_view_type_announcement), + onClickLabel = stringResource(R.string.a11y_action_label_read_article), onClick = onLearnMoreClick, ), ) { diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/MessageCardViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/MessageCardViewHolder.kt index 5af751f5f..835ca1232 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/MessageCardViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/MessageCardViewHolder.kt @@ -5,17 +5,24 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding import android.view.View +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.LifecycleOwner +import mozilla.components.lib.state.ext.observeAsComposableState import org.mozilla.fenix.R +import org.mozilla.fenix.components.components import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.compose.MessageCard +import org.mozilla.fenix.compose.MessageCardColors import org.mozilla.fenix.gleanplumb.Message import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.wallpapers.Wallpaper +import org.mozilla.fenix.wallpapers.WallpaperState /** * View holder for the Nimbus Message Card. @@ -47,9 +54,31 @@ class MessageCardViewHolder( @Composable override fun Content() { val message by remember { mutableStateOf(messageGlobal) } + val wallpaperState = components.appStore + .observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default + val isWallpaperNotDefault = !Wallpaper.nameIsDefault(wallpaperState.currentWallpaper.name) + + var (_, _, _, _, buttonColor, buttonTextColor) = MessageCardColors.buildMessageCardColors() + + if (isWallpaperNotDefault) { + buttonColor = FirefoxTheme.colors.layer1 + + if (!isSystemInDarkTheme()) { + buttonTextColor = FirefoxTheme.colors.textActionSecondary + } + } + + val messageCardColors = MessageCardColors.buildMessageCardColors( + backgroundColor = wallpaperState.wallpaperCardColor, + buttonColor = buttonColor, + buttonTextColor = buttonTextColor, + ) MessageCard( - message = message, + messageText = message.data.text, + titleText = message.data.title, + buttonText = message.data.buttonLabel, + messageColors = messageCardColors, onClick = { interactor.onMessageClicked(message) }, onCloseButtonClick = { interactor.onMessageClosedClicked(message) }, ) diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt index c1c68d330..f13c4107d 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/DefaultTopSitesView.kt @@ -12,12 +12,12 @@ import org.mozilla.fenix.ext.sort import org.mozilla.fenix.utils.Settings class DefaultTopSitesView( - val store: AppStore, + val appStore: AppStore, val settings: Settings, ) : TopSitesView { override fun displayTopSites(topSites: List) { - store.dispatch( + appStore.dispatch( AppAction.TopSitesChange( if (!settings.showContileFeature) { topSites diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt index ab13c2abb..2176cd000 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteItemViewHolder.kt @@ -5,33 +5,46 @@ package org.mozilla.fenix.home.topsites import android.annotation.SuppressLint +import android.content.res.ColorStateList import android.view.MotionEvent import android.view.View import android.widget.PopupWindow import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources.getDrawable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.core.widget.TextViewCompat import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import mozilla.components.feature.top.sites.TopSite +import mozilla.components.lib.state.ext.flowScoped +import mozilla.components.support.ktx.android.content.getColorFromAttr +import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.GleanMetrics.Pings import org.mozilla.fenix.GleanMetrics.TopSites import org.mozilla.fenix.R +import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.databinding.TopSiteItemBinding import org.mozilla.fenix.ext.bitmapForUrl import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.isSystemInDarkTheme import org.mozilla.fenix.ext.loadIntoView import org.mozilla.fenix.ext.name import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.utils.view.ViewHolder +@SuppressLint("ClickableViewAccessibility") class TopSiteItemViewHolder( view: View, + appStore: AppStore, private val viewLifecycleOwner: LifecycleOwner, private val interactor: TopSiteInteractor, ) : ViewHolder(view) { @@ -39,7 +52,7 @@ class TopSiteItemViewHolder( private val binding = TopSiteItemBinding.bind(view) init { - binding.topSiteItem.setOnLongClickListener { + itemView.setOnLongClickListener { interactor.onTopSiteMenuOpened() TopSites.longPress.record(TopSites.LongPressExtra(topSite.name())) @@ -63,16 +76,51 @@ class TopSiteItemViewHolder( } val menu = topSiteMenu.menuBuilder.build(view.context).show(anchor = it) - it.setOnTouchListener @SuppressLint("ClickableViewAccessibility") { v, event -> + it.setOnTouchListener { v, event -> onTouchEvent(v, event, menu) } true } + + appStore.flowScoped(viewLifecycleOwner) { flow -> + flow.map { state -> state.wallpaperState } + .ifChanged() + .collect { currentState -> + var backgroundColor = ContextCompat.getColor(view.context, R.color.fx_mobile_layer_color_2) + + currentState.runIfWallpaperCardColorsAreAvailable { cardColorLight, cardColorDark -> + backgroundColor = if (view.context.isSystemInDarkTheme()) { + cardColorDark + } else { + cardColorLight + } + } + + binding.faviconCard.setCardBackgroundColor(backgroundColor) + + val textColor = currentState.currentWallpaper.textColor + if (textColor != null) { + val color = Color(textColor).toArgb() + val colorList = ColorStateList.valueOf(color) + binding.topSiteTitle.setTextColor(color) + binding.topSiteSubtitle.setTextColor(color) + TextViewCompat.setCompoundDrawableTintList(binding.topSiteTitle, colorList) + } else { + binding.topSiteTitle.setTextColor( + view.context.getColorFromAttr(R.attr.textPrimary), + ) + binding.topSiteSubtitle.setTextColor( + view.context.getColorFromAttr(R.attr.textSecondary), + ) + TextViewCompat.setCompoundDrawableTintList(binding.topSiteTitle, null) + } + } + } } fun bind(topSite: TopSite, position: Int) { - binding.topSiteItem.setOnClickListener { + itemView.setOnClickListener { interactor.onSelectTopSite(topSite, position) } @@ -140,6 +188,7 @@ class TopSiteItemViewHolder( Pings.topsitesImpression.submit() } + @SuppressLint("ClickableViewAccessibility") private fun onTouchEvent( v: View, event: MotionEvent, diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt index 3f69cc3cd..0729b1811 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitePagerViewHolder.kt @@ -12,18 +12,20 @@ import androidx.viewpager2.widget.ViewPager2 import mozilla.components.feature.top.sites.TopSite import org.mozilla.fenix.GleanMetrics.TopSites import org.mozilla.fenix.R +import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.databinding.ComponentTopSitesPagerBinding import org.mozilla.fenix.home.sessioncontrol.AdapterItem import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor class TopSitePagerViewHolder( view: View, + appStore: AppStore, viewLifecycleOwner: LifecycleOwner, interactor: TopSiteInteractor, ) : RecyclerView.ViewHolder(view) { private val binding = ComponentTopSitesPagerBinding.bind(view) - private val topSitesPagerAdapter = TopSitesPagerAdapter(viewLifecycleOwner, interactor) + private val topSitesPagerAdapter = TopSitesPagerAdapter(appStore, viewLifecycleOwner, interactor) private val pageIndicator = binding.pageIndicator private var currentPage = 0 diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt index aa1073d95..e3a29d22a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSiteViewHolder.kt @@ -9,17 +9,19 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.RecyclerView import mozilla.components.feature.top.sites.TopSite import org.mozilla.fenix.R +import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.databinding.ComponentTopSitesBinding import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor import org.mozilla.fenix.utils.AccessibilityGridLayoutManager class TopSiteViewHolder( view: View, + appStore: AppStore, viewLifecycleOwner: LifecycleOwner, interactor: TopSiteInteractor, ) : RecyclerView.ViewHolder(view) { - private val topSitesAdapter = TopSitesAdapter(viewLifecycleOwner, interactor) + private val topSitesAdapter = TopSitesAdapter(appStore, viewLifecycleOwner, interactor) val binding = ComponentTopSitesBinding.bind(view) init { diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt index 0dfab5b9c..9bd5a5711 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesAdapter.kt @@ -10,17 +10,19 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import mozilla.components.feature.top.sites.TopSite +import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor import org.mozilla.fenix.perf.StartupTimeline class TopSitesAdapter( + private val appStore: AppStore, private val viewLifecycleOwner: LifecycleOwner, private val interactor: TopSiteInteractor, ) : ListAdapter(TopSitesDiffCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteItemViewHolder { val view = LayoutInflater.from(parent.context) .inflate(TopSiteItemViewHolder.LAYOUT_ID, parent, false) - return TopSiteItemViewHolder(view, viewLifecycleOwner, interactor) + return TopSiteItemViewHolder(view, appStore, viewLifecycleOwner, interactor) } override fun onBindViewHolder(holder: TopSiteItemViewHolder, position: Int) { diff --git a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt index 235211062..0a56a0c9c 100644 --- a/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/home/topsites/TopSitesPagerAdapter.kt @@ -11,11 +11,13 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import mozilla.components.feature.top.sites.TopSite +import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.home.sessioncontrol.AdapterItem.TopSitePagerPayload import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder.Companion.TOP_SITES_PER_PAGE class TopSitesPagerAdapter( + private val appStore: AppStore, private val viewLifecycleOwner: LifecycleOwner, private val interactor: TopSiteInteractor, ) : ListAdapter, TopSiteViewHolder>(TopSiteListDiffCallback) { @@ -23,7 +25,7 @@ class TopSitesPagerAdapter( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteViewHolder { val view = LayoutInflater.from(parent.context) .inflate(TopSiteViewHolder.LAYOUT_ID, parent, false) - return TopSiteViewHolder(view, viewLifecycleOwner, interactor) + return TopSiteViewHolder(view, appStore, viewLifecycleOwner, interactor) } override fun onBindViewHolder( diff --git a/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt b/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt index 1756bdd0e..34d976c60 100644 --- a/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/LibraryPageFragment.kt @@ -6,8 +6,8 @@ package org.mozilla.fenix.library import androidx.appcompat.widget.Toolbar import androidx.fragment.app.Fragment -import mozilla.components.support.ktx.android.content.getColorFromAttr import androidx.navigation.fragment.findNavController +import mozilla.components.support.ktx.android.content.getColorFromAttr import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt index 4f96e26ac..c3da16fb7 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkController.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.library.bookmarks import android.content.ClipData import android.content.ClipboardManager import android.content.res.Resources +import androidx.annotation.VisibleForTesting import androidx.navigation.NavController import androidx.navigation.NavDirections import kotlinx.coroutines.CoroutineScope @@ -15,6 +16,7 @@ import mozilla.appservices.places.BookmarkRoot import mozilla.components.concept.engine.EngineSession import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.storage.BookmarkNode +import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.feature.tabs.TabsUseCases import mozilla.components.service.fxa.sync.SyncReason import org.mozilla.fenix.BrowserDirection @@ -27,6 +29,9 @@ import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.navigateSafe import org.mozilla.fenix.utils.Settings +@VisibleForTesting +internal const val WARN_OPEN_ALL_SIZE = 15 + /** * [BookmarkFragment] controller. * Delegated by View Interactors, handles container business logic and operates changes on it. @@ -44,6 +49,7 @@ interface BookmarkController { fun handleCopyUrl(item: BookmarkNode) fun handleBookmarkSharing(item: BookmarkNode) fun handleOpeningBookmark(item: BookmarkNode, mode: BrowsingMode) + fun handleOpeningFolderBookmarks(folder: BookmarkNode, mode: BrowsingMode) /** * Handle bookmark nodes deletion @@ -73,11 +79,12 @@ class DefaultBookmarkController( private val store: BookmarkFragmentStore, private val sharedViewModel: BookmarksSharedViewModel, private val tabsUseCases: TabsUseCases?, - private val loadBookmarkNode: suspend (String) -> BookmarkNode?, + private val loadBookmarkNode: suspend (String, Boolean) -> BookmarkNode?, private val showSnackbar: (String) -> Unit, private val deleteBookmarkNodes: (Set, BookmarkRemoveType) -> Unit, private val deleteBookmarkFolder: (Set) -> Unit, private val showTabTray: () -> Unit, + private val warnLargeOpenAll: (Int, () -> Unit) -> Unit, private val settings: Settings, ) : BookmarkController { @@ -105,7 +112,7 @@ class DefaultBookmarkController( override fun handleBookmarkExpand(folder: BookmarkNode) { handleAllBookmarksDeselected() scope.launch { - val node = loadBookmarkNode.invoke(folder.guid) ?: return@launch + val node = loadBookmarkNode.invoke(folder.guid, false) ?: return@launch sharedViewModel.selectedFolder = node store.dispatch(BookmarkFragmentAction.Change(node)) } @@ -158,6 +165,53 @@ class DefaultBookmarkController( showTabTray() } + private fun extractURLsFromTree(node: BookmarkNode): MutableList { + val urls = mutableListOf() + + when (node.type) { + BookmarkNodeType.FOLDER -> { + node.children?.forEach { + urls.addAll(extractURLsFromTree(it)) + } + } + BookmarkNodeType.ITEM -> { + node.url?.let { urls.add(it) } + } + BookmarkNodeType.SEPARATOR -> {} + } + + return urls + } + + override fun handleOpeningFolderBookmarks(folder: BookmarkNode, mode: BrowsingMode) { + scope.launch { + val tree = loadBookmarkNode.invoke(folder.guid, true) ?: return@launch + val urls = extractURLsFromTree(tree) + + val openAll = { load: Boolean -> + for (url in urls) { + tabsUseCases?.addTab?.invoke( + url, + private = (mode == BrowsingMode.Private), + startLoading = load, + ) + } + activity.browsingModeManager.mode = + BrowsingMode.fromBoolean(mode == BrowsingMode.Private) + showTabTray() + } + + // Warn user if more than maximum number of bookmarks are being opened + if (urls.size >= WARN_OPEN_ALL_SIZE) { + warnLargeOpenAll(urls.size) { + openAll(false) + } + } else { + openAll(true) + } + } + } + override fun handleBookmarkDeletion(nodes: Set, removeType: BookmarkRemoveType) { deleteBookmarkNodes(nodes, removeType) } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index 34e15347c..316228583 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -16,8 +16,10 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import androidx.core.content.getSystemService +import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.NavDirections import androidx.navigation.fragment.findNavController @@ -38,7 +40,6 @@ import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.telemetry.glean.private.NoExtras -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.GleanMetrics.BookmarksManagement import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.NavHostActivity @@ -61,7 +62,7 @@ import org.mozilla.fenix.utils.allowUndo * The screen that displays the user's bookmark list in their Library. */ @Suppress("TooManyFunctions", "LargeClass") -class BookmarkFragment : LibraryPageFragment(), UserInteractionHandler { +class BookmarkFragment : LibraryPageFragment(), UserInteractionHandler, MenuProvider { private lateinit var bookmarkStore: BookmarkFragmentStore private lateinit var bookmarkView: BookmarkView @@ -104,6 +105,7 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan deleteBookmarkNodes = ::deleteMulti, deleteBookmarkFolder = ::showRemoveFolderDialog, showTabTray = ::showTabTray, + warnLargeOpenAll = ::warnLargeOpenAll, settings = requireComponents.settings, ), ) @@ -134,6 +136,9 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + val accountManager = requireComponents.backgroundServices.accountManager consumeFrom(bookmarkStore) { bookmarkView.update(it) @@ -147,11 +152,6 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan } } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - override fun onResume() { super.onResume() @@ -176,16 +176,12 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan } } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { when (val mode = bookmarkStore.state.mode) { is BookmarkFragmentState.Mode.Normal -> { if (mode.showMenu) { inflater.inflate(R.menu.bookmarks_menu, menu) } - - if (!FeatureFlags.historyImprovementFeatures) { - menu.findItem(R.id.bookmark_search)?.isVisible = false - } } is BookmarkFragmentState.Mode.Selecting -> { if (mode.selectedItems.any { it.type != BookmarkNodeType.ITEM }) { @@ -205,7 +201,7 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.bookmark_search -> { bookmarkInteractor.onSearch() @@ -251,7 +247,8 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan deleteMulti(bookmarkStore.state.mode.selectedItems) true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } @@ -271,11 +268,11 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan return bookmarkView.onBackPressed() } - private suspend fun loadBookmarkNode(guid: String): BookmarkNode? = withContext(IO) { + private suspend fun loadBookmarkNode(guid: String, recursive: Boolean = false): BookmarkNode? = withContext(IO) { // Only runs if the fragment is attached same as [runIfFragmentIsAttached] context?.let { requireContext().bookmarkStorage - .getTree(guid, false) + .getTree(guid, recursive) ?.let { desktopFolders.withOptionalDesktopFolders(it) } } } @@ -292,6 +289,27 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan } } + private fun warnLargeOpenAll(numberOfTabs: Int, function: () -> (Unit)) { + AlertDialog.Builder(requireContext()).apply { + setTitle(String.format(context.getString(R.string.open_all_warning_title), numberOfTabs)) + setMessage(context.getString(R.string.open_all_warning_message, context.getString(R.string.app_name))) + setPositiveButton( + R.string.open_all_warning_confirm, + ) { dialog, _ -> + function() + dialog.dismiss() + } + setNegativeButton( + R.string.open_all_warning_cancel, + ) { dialog: DialogInterface, _ -> + dialog.dismiss() + } + setCancelable(false) + create() + show() + } + } + private fun deleteMulti( selected: Set, eventType: BookmarkRemoveType = BookmarkRemoveType.MULTIPLE, diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentInteractor.kt index 9515764a1..a0da5d34d 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragmentInteractor.kt @@ -41,6 +41,7 @@ class BookmarkFragmentInteractor( } override fun onSearch() { + BookmarksManagement.searchIconTapped.record(NoExtras()) bookmarksController.handleSearch() } @@ -79,6 +80,16 @@ class BookmarkFragmentInteractor( } } + override fun onOpenAllInNewTabs(folder: BookmarkNode) { + require(folder.type == BookmarkNodeType.FOLDER) + bookmarksController.handleOpeningFolderBookmarks(folder, BrowsingMode.Normal) + } + + override fun onOpenAllInPrivateTabs(folder: BookmarkNode) { + require(folder.type == BookmarkNodeType.FOLDER) + bookmarksController.handleOpeningFolderBookmarks(folder, BrowsingMode.Private) + } + override fun onDelete(nodes: Set) { if (nodes.find { it.type == BookmarkNodeType.SEPARATOR } != null) { throw IllegalStateException("Cannot delete separators") diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkItemMenu.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkItemMenu.kt index e437490ca..533f1878c 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkItemMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkItemMenu.kt @@ -13,6 +13,7 @@ import mozilla.components.concept.menu.candidate.TextStyle import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.support.ktx.android.content.getColorFromAttr import org.mozilla.fenix.R +import org.mozilla.fenix.ext.bookmarkStorage class BookmarkItemMenu( private val context: Context, @@ -25,6 +26,8 @@ class BookmarkItemMenu( Share, OpenInNewTab, OpenInPrivateTab, + OpenAllInNewTabs, + OpenAllInPrivateTabs, Delete, ; } @@ -32,7 +35,10 @@ class BookmarkItemMenu( val menuController: MenuController by lazy { BrowserMenuController() } @VisibleForTesting - internal fun menuItems(itemType: BookmarkNodeType): List { + @SuppressWarnings("LongMethod") + internal suspend fun menuItems(itemType: BookmarkNodeType, itemId: String): List { + val hasAtLeastOneChild = !context.bookmarkStorage.getTree(itemId)?.children.isNullOrEmpty() + return listOfNotNull( if (itemType != BookmarkNodeType.SEPARATOR) { TextMenuCandidate( @@ -79,6 +85,24 @@ class BookmarkItemMenu( } else { null }, + if (hasAtLeastOneChild && itemType == BookmarkNodeType.FOLDER) { + TextMenuCandidate( + text = context.getString(R.string.bookmark_menu_open_all_in_tabs_button), + ) { + onItemTapped.invoke(Item.OpenAllInNewTabs) + } + } else { + null + }, + if (hasAtLeastOneChild && itemType == BookmarkNodeType.FOLDER) { + TextMenuCandidate( + text = context.getString(R.string.bookmark_menu_open_all_in_private_tabs_button), + ) { + onItemTapped.invoke(Item.OpenAllInPrivateTabs) + } + } else { + null + }, TextMenuCandidate( text = context.getString(R.string.bookmark_menu_delete_button), textStyle = TextStyle(color = context.getColorFromAttr(R.attr.textWarning)), @@ -88,7 +112,10 @@ class BookmarkItemMenu( ) } - fun updateMenu(itemType: BookmarkNodeType) { - menuController.submitList(menuItems(itemType)) + /** + * Update the menu items for the type of bookmark. + */ + suspend fun updateMenu(itemType: BookmarkNodeType, itemId: String) { + menuController.submitList(menuItems(itemType, itemId)) } } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt index ebefc9404..e88f0678f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkSearchController.kt @@ -5,7 +5,9 @@ package org.mozilla.fenix.library.bookmarks import mozilla.components.concept.engine.EngineSession.LoadUrlFlags +import mozilla.components.service.glean.private.NoExtras import org.mozilla.fenix.BrowserDirection +import org.mozilla.fenix.GleanMetrics.BookmarksManagement import org.mozilla.fenix.HomeActivity /** @@ -32,6 +34,7 @@ class BookmarkSearchDialogController( } override fun handleUrlTapped(url: String, flags: LoadUrlFlags) { + BookmarksManagement.searchResultTapped.record(NoExtras()) clearToolbarFocus() activity.openToBrowserAndLoad( diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt index b6cbcf292..5c5c018ae 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkView.kt @@ -79,6 +79,20 @@ interface BookmarkViewInteractor : SelectionInteractor { */ fun onOpenInPrivateTab(item: BookmarkNode) + /** + * Opens all bookmark items in new tabs. + * + * @param folder the bookmark folder containing all items to open in new tabs + */ + fun onOpenAllInNewTabs(folder: BookmarkNode) + + /** + * Opens all bookmark items in new private tabs. + * + * @param folder the bookmark folder containing all items to open in new private tabs + */ + fun onOpenAllInPrivateTabs(folder: BookmarkNode) + /** * Deletes a set of bookmark nodes. * diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/addfolder/AddBookmarkFolderFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/addfolder/AddBookmarkFolderFragment.kt index f8d671d64..d2e38e771 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/addfolder/AddBookmarkFolderFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/addfolder/AddBookmarkFolderFragment.kt @@ -10,8 +10,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.View.GONE +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.Navigation import kotlinx.coroutines.Dispatchers.IO @@ -34,21 +36,18 @@ import org.mozilla.fenix.library.bookmarks.friendlyRootTitle /** * Menu to create a new bookmark folder. */ -class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark) { +class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark), MenuProvider { private var _binding: FragmentEditBookmarkBinding? = null private val binding get() = _binding!! private val sharedViewModel: BookmarksSharedViewModel by activityViewModels() - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - /** * Hides fields for bookmark items present in the shared layout file. */ override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + _binding = FragmentEditBookmarkBinding.bind(view) binding.bookmarkUrlLabel.visibility = GONE @@ -87,11 +86,11 @@ class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark) { binding.bookmarkNameEdit.hideKeyboard() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.bookmarks_add_folder, menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.confirm_add_folder_button -> { if (binding.bookmarkNameEdit.text.isNullOrBlank()) { @@ -116,7 +115,8 @@ class AddBookmarkFolderFragment : Fragment(R.layout.fragment_edit_bookmark) { } true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt index 443b10f4c..8299cc757 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt @@ -17,8 +17,10 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.Navigation import androidx.navigation.fragment.findNavController @@ -27,7 +29,7 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import mozilla.appservices.places.uniffi.PlacesException +import mozilla.appservices.places.uniffi.PlacesApiException import mozilla.components.concept.storage.BookmarkInfo import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType @@ -53,7 +55,7 @@ import org.mozilla.fenix.library.bookmarks.friendlyRootTitle /** * Menu to edit the name, URL, and location of a bookmark item. */ -class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { +class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark), MenuProvider { private var _binding: FragmentEditBookmarkBinding? = null private val binding get() = _binding!! @@ -63,13 +65,9 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { private var bookmarkParent: BookmarkNode? = null private var initialParentGuid: String? = null - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) _binding = FragmentEditBookmarkBinding.bind(view) @@ -191,11 +189,11 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { binding.progressBarBookmark.visibility = View.GONE } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.bookmarks_edit, menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.delete_bookmark_button -> { displayDeleteBookmarkDialog() @@ -206,7 +204,8 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } @@ -288,7 +287,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { findNavController().popBackStack() } - } catch (e: PlacesException.UrlParseFailed) { + } catch (e: PlacesApiException.UrlParseFailed) { withContext(Main) { binding.inputLayoutBookmarkUrl.error = getString(R.string.bookmark_invalid_url_error) diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/selectfolder/SelectBookmarkFolderFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/selectfolder/SelectBookmarkFolderFragment.kt index 20a67c191..92acd0c8f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/selectfolder/SelectBookmarkFolderFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/selectfolder/SelectBookmarkFolderFragment.kt @@ -11,8 +11,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import kotlinx.coroutines.Dispatchers.IO @@ -29,24 +31,24 @@ import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel import org.mozilla.fenix.library.bookmarks.DesktopFolders -class SelectBookmarkFolderFragment : Fragment() { +class SelectBookmarkFolderFragment : Fragment(), MenuProvider { private var _binding: FragmentSelectBookmarkFolderBinding? = null private val binding get() = _binding!! private val sharedViewModel: BookmarksSharedViewModel by activityViewModels() private var bookmarkNode: BookmarkNode? = null - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { _binding = FragmentSelectBookmarkFolderBinding.inflate(inflater, container, false) return binding.root } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + } + override fun onDestroyView() { super.onDestroyView() @@ -72,14 +74,14 @@ class SelectBookmarkFolderFragment : Fragment() { } } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { val args: SelectBookmarkFolderFragmentArgs by navArgs() if (!args.allowCreatingNewFolder) { inflater.inflate(R.menu.bookmarks_select_folder, menu) } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.add_folder_button -> { viewLifecycleOwner.lifecycleScope.launch(Main) { @@ -91,7 +93,8 @@ class SelectBookmarkFolderFragment : Fragment() { } true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } } diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkNodeViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkNodeViewHolder.kt index dc1d8c8b9..265aaa981 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkNodeViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkNodeViewHolder.kt @@ -6,14 +6,17 @@ package org.mozilla.fenix.library.bookmarks.viewholders import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import org.mozilla.fenix.R -import org.mozilla.fenix.ext.removeAndDisable -import org.mozilla.fenix.ext.hideAndDisable -import org.mozilla.fenix.ext.showAndEnable import org.mozilla.fenix.ext.components +import org.mozilla.fenix.ext.hideAndDisable import org.mozilla.fenix.ext.loadIntoView +import org.mozilla.fenix.ext.removeAndDisable +import org.mozilla.fenix.ext.showAndEnable import org.mozilla.fenix.library.LibrarySiteItemView import org.mozilla.fenix.library.bookmarks.BookmarkFragmentState import org.mozilla.fenix.library.bookmarks.BookmarkItemMenu @@ -42,6 +45,8 @@ class BookmarkNodeViewHolder( BookmarkItemMenu.Item.Share -> interactor.onSharePressed(item) BookmarkItemMenu.Item.OpenInNewTab -> interactor.onOpenInNormalTab(item) BookmarkItemMenu.Item.OpenInPrivateTab -> interactor.onOpenInPrivateTab(item) + BookmarkItemMenu.Item.OpenAllInNewTabs -> interactor.onOpenAllInNewTabs(item) + BookmarkItemMenu.Item.OpenAllInPrivateTabs -> interactor.onOpenAllInPrivateTabs(item) BookmarkItemMenu.Item.Delete -> interactor.onDelete(setOf(item)) } } @@ -58,7 +63,10 @@ class BookmarkNodeViewHolder( containerView.urlView.isVisible = item.type == BookmarkNodeType.ITEM containerView.setSelectionInteractor(item, mode, interactor) - menu.updateMenu(item.type) + + CoroutineScope(Dispatchers.Default).launch { + menu.updateMenu(item.type, item.guid) + } // Hide menu button if this item is a root folder or is selected if (item.type == BookmarkNodeType.FOLDER && item.inRoots()) { diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt index 40db18a01..c924b1325 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/DownloadFragment.kt @@ -14,11 +14,13 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.annotation.VisibleForTesting +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.MainScope -import mozilla.components.browser.state.state.BrowserState import kotlinx.coroutines.launch +import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.content.DownloadState import mozilla.components.feature.downloads.AbstractFetchDownloadService import mozilla.components.lib.state.ext.consumeFrom @@ -30,15 +32,15 @@ import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.databinding.FragmentDownloadsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.filterNotExistsOnDisk +import org.mozilla.fenix.ext.getRootView import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.setTextColor import org.mozilla.fenix.ext.showToolbar -import org.mozilla.fenix.ext.getRootView import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.utils.allowUndo @SuppressWarnings("TooManyFunctions", "LargeClass") -class DownloadFragment : LibraryPageFragment(), UserInteractionHandler { +class DownloadFragment : LibraryPageFragment(), UserInteractionHandler, MenuProvider { private lateinit var downloadStore: DownloadFragmentStore private lateinit var downloadView: DownloadView private lateinit var downloadInteractor: DownloadInteractor @@ -116,7 +118,6 @@ class DownloadFragment : LibraryPageFragment(), UserInteractionHan override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) } /** @@ -140,6 +141,8 @@ class DownloadFragment : LibraryPageFragment(), UserInteractionHan override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + consumeFrom(downloadStore) { downloadView.update(it) } @@ -150,7 +153,7 @@ class DownloadFragment : LibraryPageFragment(), UserInteractionHan showToolbar(getString(R.string.library_downloads)) } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { val menuRes = when (downloadStore.state.mode) { is DownloadFragmentState.Mode.Normal -> R.menu.library_menu is DownloadFragmentState.Mode.Editing -> R.menu.download_select_multi @@ -163,7 +166,7 @@ class DownloadFragment : LibraryPageFragment(), UserInteractionHan } } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.close_history -> { close() true @@ -181,7 +184,8 @@ class DownloadFragment : LibraryPageFragment(), UserInteractionHan } true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } /** diff --git a/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt index 90e50f58a..789af3948 100644 --- a/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/downloads/viewholders/DownloadsListItemViewHolder.kt @@ -10,14 +10,14 @@ import mozilla.components.feature.downloads.toMegabyteOrKilobyteString import org.mozilla.fenix.R import org.mozilla.fenix.databinding.DownloadListItemBinding import org.mozilla.fenix.databinding.LibrarySiteItemBinding -import org.mozilla.fenix.selection.SelectionHolder -import org.mozilla.fenix.library.downloads.DownloadInteractor -import org.mozilla.fenix.library.downloads.DownloadItem import org.mozilla.fenix.ext.getIcon import org.mozilla.fenix.ext.hideAndDisable import org.mozilla.fenix.ext.showAndEnable import org.mozilla.fenix.library.downloads.DownloadFragmentState +import org.mozilla.fenix.library.downloads.DownloadInteractor +import org.mozilla.fenix.library.downloads.DownloadItem import org.mozilla.fenix.library.downloads.DownloadItemMenu +import org.mozilla.fenix.selection.SelectionHolder class DownloadsListItemViewHolder( view: View, diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt index bce5da93c..39f3f6a17 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt @@ -8,8 +8,8 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil -import org.mozilla.fenix.selection.SelectionHolder import org.mozilla.fenix.library.history.viewholders.HistoryListItemViewHolder +import org.mozilla.fenix.selection.SelectionHolder /** * Adapter for the list of visited pages, that uses Paging 3 versions of the Paging library. diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt index d23d5b54e..5df4e92cd 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt @@ -17,7 +17,9 @@ import android.view.View import android.view.ViewGroup import android.widget.RadioGroup import androidx.appcompat.app.AlertDialog +import androidx.core.view.MenuProvider import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.NavDirections import androidx.navigation.fragment.findNavController @@ -36,7 +38,6 @@ import mozilla.components.service.fxa.sync.SyncReason import mozilla.components.support.base.feature.UserInteractionHandler import mozilla.telemetry.glean.private.NoExtras import org.mozilla.fenix.BrowserDirection -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R @@ -57,7 +58,7 @@ import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.GleanMetrics.History as GleanHistory @SuppressWarnings("TooManyFunctions", "LargeClass") -class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { +class HistoryFragment : LibraryPageFragment(), UserInteractionHandler, MenuProvider { private lateinit var historyStore: HistoryFragmentStore private lateinit var historyInteractor: HistoryInteractor private lateinit var historyProvider: DefaultPagedHistoryProvider @@ -154,8 +155,6 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { historyProvider = DefaultPagedHistoryProvider(requireComponents.core.historyStorage) GleanHistory.opened.record(NoExtras()) - - setHasOptionsMenu(true) } private fun deleteSnackbar( @@ -186,6 +185,7 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) consumeFrom(historyStore) { historyView.update(it) @@ -212,7 +212,7 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { if (historyStore.state.mode is HistoryFragmentState.Mode.Editing) { inflater.inflate(R.menu.history_select_multi, menu) menu.findItem(R.id.share_history_multi_select)?.isVisible = true @@ -223,13 +223,9 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { } else { inflater.inflate(R.menu.history_menu, menu) } - - if (!FeatureFlags.historyImprovementFeatures) { - menu.findItem(R.id.history_search)?.isVisible = false - } } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.share_history_multi_select -> { val selectedHistory = historyStore.state.mode.selectedItems val shareTabs = mutableListOf() @@ -287,7 +283,6 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { true } R.id.history_search -> { - GleanHistory.searchIconTapped.record(NoExtras()) historyInteractor.onSearch() true } @@ -295,7 +290,8 @@ class HistoryFragment : LibraryPageFragment(), UserInteractionHandler { historyInteractor.onDeleteTimeRange() true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } private fun showTabTray() { diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt index 6aef87012..d9395a010 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryInteractor.kt @@ -4,7 +4,9 @@ package org.mozilla.fenix.library.history +import mozilla.components.service.glean.private.NoExtras import org.mozilla.fenix.selection.SelectionInteractor +import org.mozilla.fenix.GleanMetrics.History as GleanHistory /** * Interface for the HistoryInteractor. This interface is implemented by objects that want @@ -86,6 +88,7 @@ class DefaultHistoryInteractor( } override fun onSearch() { + GleanHistory.searchIconTapped.record(NoExtras()) historyController.handleSearch() } diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt index 624057e37..2d61d1cae 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/HistoryMetadataGroupFragment.kt @@ -16,7 +16,9 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AlertDialog +import androidx.core.view.MenuProvider import androidx.fragment.app.DialogFragment +import androidx.lifecycle.Lifecycle import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import kotlinx.coroutines.CoroutineScope @@ -31,12 +33,12 @@ import org.mozilla.fenix.addons.showSnackBar import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.components.StoreProvider import org.mozilla.fenix.databinding.FragmentHistoryMetadataGroupBinding +import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.runIfFragmentIsAttached import org.mozilla.fenix.ext.setTextColor import org.mozilla.fenix.ext.showToolbar -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.runIfFragmentIsAttached import org.mozilla.fenix.ext.toShortUrl import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.library.history.History @@ -51,7 +53,7 @@ import org.mozilla.fenix.utils.allowUndo */ @SuppressWarnings("TooManyFunctions") class HistoryMetadataGroupFragment : - LibraryPageFragment(), UserInteractionHandler { + LibraryPageFragment(), UserInteractionHandler, MenuProvider { private lateinit var historyMetadataGroupStore: HistoryMetadataGroupFragmentStore private lateinit var interactor: HistoryMetadataGroupInteractor @@ -67,11 +69,6 @@ class HistoryMetadataGroupFragment : override val selectedItems: Set get() = historyMetadataGroupStore.state.items.filter { it.selected }.toSet() - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -121,6 +118,8 @@ class HistoryMetadataGroupFragment : } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + consumeFrom(historyMetadataGroupStore) { state -> historyMetadataGroupView.update(state) activity?.invalidateOptionsMenu() @@ -150,7 +149,7 @@ class HistoryMetadataGroupFragment : override fun onBackPressed(): Boolean = interactor.onBackPressed(selectedItems) - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { if (selectedItems.isNotEmpty()) { inflater.inflate(R.menu.history_select_multi, menu) @@ -164,7 +163,7 @@ class HistoryMetadataGroupFragment : } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.share_history_multi_select -> { interactor.onShareMenuItem(selectedItems) @@ -199,7 +198,8 @@ class HistoryMetadataGroupFragment : interactor.onDeleteAll() true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } diff --git a/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt b/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt index 17a757e4c..0351c199a 100644 --- a/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt +++ b/app/src/main/java/org/mozilla/fenix/library/historymetadata/controller/HistoryMetadataGroupController.kt @@ -14,11 +14,11 @@ import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.storage.sync.PlacesHistoryStorage import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.feature.tabs.TabsUseCases +import mozilla.components.service.glean.private.NoExtras import org.mozilla.fenix.R import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.appstate.AppAction import org.mozilla.fenix.ext.components -import mozilla.components.service.glean.private.NoExtras import org.mozilla.fenix.library.history.History import org.mozilla.fenix.library.history.toPendingDeletionHistory import org.mozilla.fenix.library.historymetadata.HistoryMetadataGroupFragment.DeleteAllConfirmationDialogFragment diff --git a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt index 44c6661b8..14abd9837 100644 --- a/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/recentlyclosed/RecentlyClosedFragment.kt @@ -12,6 +12,8 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import kotlinx.coroutines.flow.collect @@ -35,7 +37,10 @@ import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.library.LibraryPageFragment @Suppress("TooManyFunctions") -class RecentlyClosedFragment : LibraryPageFragment(), UserInteractionHandler { +class RecentlyClosedFragment : + LibraryPageFragment(), + UserInteractionHandler, + MenuProvider { private lateinit var recentlyClosedFragmentStore: RecentlyClosedFragmentStore private var _recentlyClosedFragmentView: RecentlyClosedFragmentView? = null private val recentlyClosedFragmentView: RecentlyClosedFragmentView @@ -49,7 +54,7 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera showToolbar(getString(R.string.library_recently_closed_tabs)) } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { if (recentlyClosedFragmentStore.state.selectedTabs.isNotEmpty()) { inflater.inflate(R.menu.history_select_multi, menu) menu.findItem(R.id.delete_history_multi_select)?.let { deleteItem -> @@ -61,7 +66,7 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera } } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { val selectedTabs = recentlyClosedFragmentStore.state.selectedTabs return when (item.itemId) { @@ -86,13 +91,13 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera recentlyClosedController.handleOpen(selectedTabs, BrowsingMode.Private) true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) RecentlyClosedTabs.opened.record(NoExtras()) } @@ -144,6 +149,8 @@ class RecentlyClosedFragment : LibraryPageFragment(), UserIntera } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + consumeFrom(recentlyClosedFragmentStore) { state -> recentlyClosedFragmentView.update(state) activity?.invalidateOptionsMenu() diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt b/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt index 8b1d8cc9a..55493ffac 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/DefaultBrowserNotificationWorker.kt @@ -19,13 +19,16 @@ import androidx.work.OneTimeWorkRequest import androidx.work.WorkManager import androidx.work.Worker import androidx.work.WorkerParameters -import java.util.concurrent.TimeUnit +import mozilla.components.service.glean.private.NoExtras import mozilla.components.support.base.ids.SharedIdsHelper +import org.mozilla.fenix.GleanMetrics.Events +import org.mozilla.fenix.GleanMetrics.Events.marketingNotificationAllowed import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R import org.mozilla.fenix.ext.settings import org.mozilla.fenix.utils.IntentUtils import org.mozilla.fenix.utils.Settings +import java.util.concurrent.TimeUnit class DefaultBrowserNotificationWorker( context: Context, @@ -33,9 +36,10 @@ class DefaultBrowserNotificationWorker( ) : Worker(context, workerParameters) { override fun doWork(): Result { - ensureChannelExists() + val channelId = ensureChannelExists() NotificationManagerCompat.from(applicationContext) - .notify(NOTIFICATION_TAG, NOTIFICATION_ID, buildNotification()) + .notify(NOTIFICATION_TAG, NOTIFICATION_ID, buildNotification(channelId)) + Events.defaultBrowserNotifShown.record(NoExtras()) // default browser notification should only happen once applicationContext.settings().defaultBrowserNotificationDisplayed = true @@ -46,8 +50,7 @@ class DefaultBrowserNotificationWorker( /** * Build the default browser notification. */ - private fun buildNotification(): Notification { - val channelId = ensureChannelExists() + private fun buildNotification(channelId: String): Notification { val intent = Intent(applicationContext, HomeActivity::class.java) intent.putExtra(INTENT_DEFAULT_BROWSER_NOTIFICATION, true) @@ -84,6 +87,7 @@ class DefaultBrowserNotificationWorker( * Returns the channel id to be used for notifications. */ private fun ensureChannelExists(): String { + var channelEnabled = true if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val notificationManager: NotificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager @@ -95,8 +99,21 @@ class DefaultBrowserNotificationWorker( ) notificationManager.createNotificationChannel(channel) + + val existingChannel = notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) + channelEnabled = + existingChannel != null && existingChannel.importance != NotificationManager.IMPORTANCE_NONE + } + + @Suppress("TooGenericExceptionCaught") + val notificationsEnabled = try { + NotificationManagerCompat.from(applicationContext).areNotificationsEnabled() + } catch (e: Exception) { + false } + marketingNotificationAllowed.set(notificationsEnabled && channelEnabled) + return NOTIFICATION_CHANNEL_ID } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt index fd42b1b57..679606d13 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt @@ -80,6 +80,7 @@ class WallpaperOnboardingDialogFragment : BottomSheetDialogFragment() { container: ViewGroup?, savedInstanceState: Bundle?, ): View = ComposeView(requireContext()).apply { + this@WallpaperOnboardingDialogFragment.dialog?.setCanceledOnTouchOutside(true) setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/view/Onboarding.kt b/app/src/main/java/org/mozilla/fenix/onboarding/view/Onboarding.kt index 100005804..61dd88e84 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/view/Onboarding.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/view/Onboarding.kt @@ -96,7 +96,7 @@ fun Onboarding( ) { Icon( painter = painterResource(id = R.drawable.mozac_ic_close), - contentDescription = null, + contentDescription = stringResource(R.string.onboarding_home_content_description_close_button), tint = FirefoxTheme.colors.iconPrimary, ) } diff --git a/app/src/main/java/org/mozilla/fenix/perf/Performance.kt b/app/src/main/java/org/mozilla/fenix/perf/Performance.kt index ad02cc1a0..d286d4ad9 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/Performance.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/Performance.kt @@ -34,6 +34,7 @@ object Performance { disableOnboarding(context) disableTrackingProtectionPopups(context) disableFirstTimePWAPopup(context) + disableTCPPopup(context) } /** @@ -85,4 +86,11 @@ object Performance { private fun disableFirstTimePWAPopup(context: Context) { context.components.settings.userKnowsAboutPwas = true } + + /** + * Disables the TCP popup. + */ + private fun disableTCPPopup(context: Context) { + context.components.settings.shouldShowTotalCookieProtectionCFR = false + } } diff --git a/app/src/main/java/org/mozilla/fenix/perf/ProfilerMarkerFactProcessor.kt b/app/src/main/java/org/mozilla/fenix/perf/ProfilerMarkerFactProcessor.kt index ce1b49e0a..e93e39c7c 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/ProfilerMarkerFactProcessor.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/ProfilerMarkerFactProcessor.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.perf import android.os.Handler import android.os.Looper import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import mozilla.components.concept.base.profiler.Profiler import mozilla.components.support.base.facts.Action import mozilla.components.support.base.facts.Fact diff --git a/app/src/main/java/org/mozilla/fenix/perf/ProfilerReusableComposable.kt b/app/src/main/java/org/mozilla/fenix/perf/ProfilerReusableComposable.kt index 3a2ec0b1b..c62d5b21e 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/ProfilerReusableComposable.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/ProfilerReusableComposable.kt @@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding - import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Card import androidx.compose.material.CircularProgressIndicator diff --git a/app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt index b54558bd4..686a78362 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/ProfilerStartDialogFragment.kt @@ -37,7 +37,6 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import kotlinx.coroutines.launch - import mozilla.components.concept.base.profiler.Profiler import org.mozilla.fenix.R import org.mozilla.fenix.ext.components diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupActivityLog.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupActivityLog.kt index 73f0b078f..1f53b3e64 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupActivityLog.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupActivityLog.kt @@ -8,8 +8,8 @@ import android.app.Activity import android.app.Application import android.os.Bundle import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.NONE -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.NONE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt index 85ae4363b..1cd626306 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupPathProvider.kt @@ -7,8 +7,8 @@ package org.mozilla.fenix.perf import android.app.Activity import android.content.Intent import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.NONE -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.NONE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner diff --git a/app/src/main/java/org/mozilla/fenix/perf/StartupTypeTelemetry.kt b/app/src/main/java/org/mozilla/fenix/perf/StartupTypeTelemetry.kt index ef87ecec0..4ebb7208a 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StartupTypeTelemetry.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StartupTypeTelemetry.kt @@ -5,8 +5,8 @@ package org.mozilla.fenix.perf import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.NONE -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.NONE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner diff --git a/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt b/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt index 930ec5952..79d56eefe 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StorageStatsMetrics.kt @@ -10,7 +10,7 @@ import android.content.Context import android.os.Build import androidx.annotation.RequiresApi import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.annotation.WorkerThread import androidx.core.content.getSystemService import kotlinx.coroutines.DelicateCoroutinesApi diff --git a/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt b/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt index 1264e3b8f..470f90f0b 100644 --- a/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt +++ b/app/src/main/java/org/mozilla/fenix/perf/StrictModeManager.kt @@ -14,7 +14,7 @@ import android.os.Handler import android.os.Looper import android.os.StrictMode import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import mozilla.components.support.ktx.android.os.resetAfter diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchDialogController.kt b/app/src/main/java/org/mozilla/fenix/search/SearchDialogController.kt index ba838e4ba..b7babc74f 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchDialogController.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchDialogController.kt @@ -144,7 +144,8 @@ class SearchDialogController( fragmentStore.dispatch(SearchFragmentAction.UpdateQuery(text)) fragmentStore.dispatch( SearchFragmentAction.ShowSearchShortcutEnginePicker( - (textMatchesCurrentUrl || textMatchesCurrentSearch || text.isEmpty()) && + !settings.showUnifiedSearchFeature && + (textMatchesCurrentUrl || textMatchesCurrentSearch || text.isEmpty()) && settings.shouldShowSearchShortcuts, ), ) diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt index 2eb301a33..f600d74c2 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchDialogFragment.kt @@ -5,11 +5,13 @@ package org.mozilla.fenix.search import android.Manifest +import android.annotation.SuppressLint import android.app.Activity import android.app.Dialog import android.content.Context import android.content.DialogInterface import android.content.Intent +import android.content.pm.PackageManager import android.graphics.Color import android.graphics.Typeface import android.graphics.drawable.ColorDrawable @@ -24,6 +26,7 @@ import android.view.ViewStub import android.view.WindowManager import android.view.accessibility.AccessibilityEvent import android.view.inputmethod.InputMethodManager +import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.content.res.AppCompatResources @@ -35,9 +38,10 @@ import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toUri import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavGraph import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import mozilla.components.browser.domains.autocomplete.ShippedDomainsProvider @@ -202,7 +206,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { ) val fromHomeFragment = - findNavController().previousBackStackEntry?.destination?.id == R.id.homeFragment + getPreviousDestination()?.destination?.id == R.id.homeFragment toolbarView = ToolbarView( requireContext(), @@ -252,7 +256,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { requireComponents.core.engine.speculativeCreateSession(isPrivate) - when (findNavController().previousBackStackEntry?.destination?.id) { + when (getPreviousDestination()?.destination?.id) { R.id.homeFragment -> { // When displayed above home, dispatches the touch events to scrim area to the HomeFragment binding.searchWrapper.background = ColorDrawable(Color.TRANSPARENT) @@ -292,7 +296,12 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { flow.map { state -> state.search } .ifChanged() .collect { search -> - store.dispatch(SearchFragmentAction.UpdateSearchState(search)) + store.dispatch( + SearchFragmentAction.UpdateSearchState( + search, + showUnifiedSearchFeature, + ), + ) updateSearchSelectorMenu(search.searchEngines) } @@ -301,7 +310,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { setupConstraints(view) // When displayed above browser or home screen, dismisses keyboard when touching scrim area - when (findNavController().previousBackStackEntry?.destination?.id) { + when (getPreviousDestination()?.destination?.id) { R.id.browserFragment, R.id.homeFragment -> { binding.searchWrapper.setOnTouchListener { _, _ -> binding.searchWrapper.hideKeyboard() @@ -652,7 +661,9 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { when (requestCode) { REQUEST_CODE_CAMERA_PERMISSIONS -> qrFeature.withFeature { it.onPermissionsResult(permissions, grantResults) - resetFocus() + if (grantResults.contains(PackageManager.PERMISSION_DENIED)) { + resetFocus() + } requireContext().settings().setCameraPermissionNeededState = false } else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults) @@ -724,9 +735,9 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { ) { interactor.onMenuItemTapped(SearchSelectorMenu.Item.SearchEngine(it)) } - } + searchSelectorMenu.menuItems() + } - searchSelectorMenu.menuController.submitList(searchEngineList) + searchSelectorMenu.menuController.submitList(searchSelectorMenu.menuItems(searchEngineList)) toolbarView.view.invalidateActions() } @@ -904,6 +915,37 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler { } } + /** + * Gets the previous visible [NavBackStackEntry]. + * This skips over any [NavBackStackEntry] that is associated with a [NavGraph] or refers to this + * class as a navigation destination. + */ + @VisibleForTesting + @SuppressLint("RestrictedApi") + internal fun getPreviousDestination(): NavBackStackEntry? { + // This duplicates the platform functionality for "previousBackStackEntry" but additionally skips this entry. + + val descendingEntries = findNavController().backQueue.reversed().iterator() + // Throw the topmost destination away. + if (descendingEntries.hasNext()) { + descendingEntries.next() + } + + while (descendingEntries.hasNext()) { + val entry = descendingEntries.next() + // Using the canonicalName is safer - see https://github.com/mozilla-mobile/android-components/pull/10810 + // simpleName is used as a backup to avoid the not null assertion (!!) operator. + val currentClassName = this::class.java.canonicalName?.substringAfterLast('.') + ?: this::class.java.simpleName + + // Throw this entry away if it's the current top and ignore returning the base nav graph. + if (entry.destination !is NavGraph && !entry.destination.displayName.contains(currentClassName, true)) { + return entry + } + } + return null + } + companion object { private const val TAP_INCREASE_DPS = 8 private const val QR_FRAGMENT_TAG = "MOZAC_QR_FRAGMENT" diff --git a/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt b/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt index 1fa8d5f67..6c7c81bce 100644 --- a/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt +++ b/app/src/main/java/org/mozilla/fenix/search/SearchFragmentStore.kt @@ -212,8 +212,9 @@ sealed class SearchFragmentAction : Action { /** * Updates the local `SearchFragmentState` from the global `SearchState` in `BrowserStore`. + * If the unified search is enabled, then search shortcuts should not be shown. */ - data class UpdateSearchState(val search: SearchState) : SearchFragmentAction() + data class UpdateSearchState(val search: SearchState, val isUnifiedSearchEnabled: Boolean) : SearchFragmentAction() } /** @@ -304,7 +305,8 @@ private fun searchStateReducer(state: SearchFragmentState, action: SearchFragmen state.copy( defaultEngine = action.search.selectedOrDefaultSearchEngine, areShortcutsAvailable = action.search.searchEngines.size > 1, - showSearchShortcuts = state.url.isEmpty() && + showSearchShortcuts = !action.isUnifiedSearchEnabled && + state.url.isEmpty() && state.showSearchShortcutsSetting && action.search.searchEngines.size > 1, searchEngineSource = when (state.searchEngineSource) { diff --git a/app/src/main/java/org/mozilla/fenix/search/toolbar/SearchSelectorMenu.kt b/app/src/main/java/org/mozilla/fenix/search/toolbar/SearchSelectorMenu.kt index 8f3ca1320..3152c05dc 100644 --- a/app/src/main/java/org/mozilla/fenix/search/toolbar/SearchSelectorMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/search/toolbar/SearchSelectorMenu.kt @@ -5,12 +5,13 @@ package org.mozilla.fenix.search.toolbar import android.content.Context -import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources import mozilla.components.browser.menu2.BrowserMenuController import mozilla.components.browser.state.search.SearchEngine import mozilla.components.concept.menu.MenuController +import mozilla.components.concept.menu.candidate.DecorativeTextMenuCandidate import mozilla.components.concept.menu.candidate.DrawableMenuIcon +import mozilla.components.concept.menu.candidate.MenuCandidate import mozilla.components.concept.menu.candidate.TextMenuCandidate import mozilla.components.support.ktx.android.content.getColorFromAttr import org.mozilla.fenix.R @@ -47,21 +48,22 @@ class SearchSelectorMenu( val menuController: MenuController by lazy { BrowserMenuController() } - @VisibleForTesting - internal fun menuItems(): List { - return listOf( - TextMenuCandidate( - text = context.getString(R.string.search_settings_menu_item), - start = DrawableMenuIcon( - drawable = AppCompatResources.getDrawable( - context, - R.drawable.mozac_ic_settings, - ), - tint = context.getColorFromAttr(R.attr.textPrimary), - ), - ) { - interactor.onMenuItemTapped(Item.SearchSettings) - }, + internal fun menuItems(searchEngines: List): List { + val headerCandidate = DecorativeTextMenuCandidate( + text = context.getString(R.string.search_header_menu_item), ) + val settingsCandidate = TextMenuCandidate( + text = context.getString(R.string.search_settings_menu_item), + start = DrawableMenuIcon( + drawable = AppCompatResources.getDrawable( + context, + R.drawable.mozac_ic_settings, + ), + tint = context.getColorFromAttr(R.attr.textPrimary), + ), + ) { + interactor.onMenuItemTapped(Item.SearchSettings) + } + return listOf(headerCandidate) + searchEngines + listOf(settingsCandidate) } } diff --git a/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarView.kt b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarView.kt index 97edb87f7..0fc4828dc 100644 --- a/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarView.kt +++ b/app/src/main/java/org/mozilla/fenix/search/toolbar/ToolbarView.kt @@ -16,6 +16,7 @@ import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.content.res.resolveAttribute import mozilla.components.support.ktx.android.view.hideKeyboard import org.mozilla.fenix.R +import org.mozilla.fenix.components.Core import org.mozilla.fenix.search.SearchFragmentState import org.mozilla.fenix.utils.Settings @@ -147,11 +148,16 @@ class ToolbarView( val searchEngine = searchState.searchEngineSource.searchEngine - when (searchEngine?.type) { + view.edit.hint = when (searchEngine?.type) { SearchEngine.Type.APPLICATION -> - view.edit.hint = context.getString(R.string.application_search_hint) + when (searchEngine.id) { + Core.HISTORY_SEARCH_ENGINE_ID -> context.getString(R.string.history_search_hint) + Core.BOOKMARKS_SEARCH_ENGINE_ID -> context.getString(R.string.bookmark_search_hint) + Core.TABS_SEARCH_ENGINE_ID -> context.getString(R.string.tab_search_hint) + else -> context.getString(R.string.application_search_hint) + } else -> - view.edit.hint = context.getString(R.string.search_hint) + context.getString(R.string.search_hint) } if (!settings.showUnifiedSearchFeature && searchEngine != null) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt index 8565b3c86..80ea4a8e3 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/HomeSettingsFragment.kt @@ -104,6 +104,10 @@ class HomeSettingsFragment : PreferenceFragmentCompat() { requirePreference(R.string.pref_key_pocket_homescreen_recommendations).apply { isVisible = FeatureFlags.isPocketRecommendationsFeatureEnabled(context) isChecked = context.settings().showPocketRecommendationsFeature + summary = context.getString( + R.string.customize_toggle_pocket_summary, + context.getString(R.string.pocket_product_name), + ) onPreferenceChangeListener = object : SharedPreferenceUpdater() { override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { CustomizeHome.preferenceToggled.record( diff --git a/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt index e2bbaaca5..be24d8d45 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SecretSettingsFragment.kt @@ -5,9 +5,12 @@ package org.mozilla.fenix.settings import android.os.Bundle +import androidx.preference.EditTextPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import androidx.preference.SwitchPreference +import org.mozilla.fenix.BuildConfig +import org.mozilla.fenix.Config import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.ext.components @@ -53,5 +56,10 @@ class SecretSettingsFragment : PreferenceFragmentCompat() { isChecked = context.settings().showUnifiedSearchFeature onPreferenceChangeListener = SharedPreferenceUpdater() } + + // for performance reasons, this is only available in Nightly or Debug builds + requirePreference(R.string.pref_key_custom_glean_server_url).apply { + isVisible = Config.channel.isNightlyOrDebug && BuildConfig.GLEAN_CUSTOM_URL.isNullOrEmpty() + } } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt index 3054d600b..efb867854 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SettingsFragment.kt @@ -38,6 +38,7 @@ import mozilla.components.service.glean.private.NoExtras import mozilla.components.support.ktx.android.view.showKeyboard import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.Config +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.GleanMetrics.Addons import org.mozilla.fenix.GleanMetrics.Events import org.mozilla.fenix.GleanMetrics.TrackingProtection @@ -48,9 +49,9 @@ import org.mozilla.fenix.ext.application import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.navigateToNotificationsSettings +import org.mozilla.fenix.ext.openSetDefaultBrowserOption import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings -import org.mozilla.fenix.ext.openSetDefaultBrowserOption import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.nimbus.FxNimbus import org.mozilla.fenix.perf.ProfilerViewModel @@ -66,7 +67,8 @@ class SettingsFragment : PreferenceFragmentCompat() { private lateinit var accountUiView: AccountUiView private val profilerViewModel: ProfilerViewModel by activityViewModels() - private val accountObserver = object : AccountObserver { + @VisibleForTesting + internal val accountObserver = object : AccountObserver { private fun updateAccountUi(profile: Profile? = null) { val context = context ?: return lifecycleScope.launch { @@ -100,13 +102,6 @@ class SettingsFragment : PreferenceFragmentCompat() { updateFxAAllowDomesticChinaServerMenu = ::updateFxAAllowDomesticChinaServerMenu, ) - // Observe account changes to keep the UI up-to-date. - requireComponents.backgroundServices.accountManager.register( - accountObserver, - owner = this, - autoPause = true, - ) - // It's important to update the account UI state in onCreate since that ensures we'll never // display an incorrect state in the UI. We take care to not also call it as part of onResume // if it was just called here (via the 'creatingFragment' flag). @@ -185,6 +180,23 @@ class SettingsFragment : PreferenceFragmentCompat() { creatingFragment = false } + override fun onStart() { + super.onStart() + // Observe account changes to keep the UI up-to-date. + requireComponents.backgroundServices.accountManager.register( + accountObserver, + owner = this, + autoPause = true, + ) + } + + override fun onStop() { + super.onStop() + // If the screen isn't visible we don't need to show updates. + // Also prevent the observer registered to the FXA singleton causing memory leaks. + requireComponents.backgroundServices.accountManager.unregister(accountObserver) + } + override fun onDestroyView() { super.onDestroyView() accountUiView.cancel() @@ -420,7 +432,8 @@ class SettingsFragment : PreferenceFragmentCompat() { val preferenceLeakCanary = findPreference(leakKey) val preferenceRemoteDebugging = findPreference(debuggingKey) val preferenceMakeDefaultBrowser = - requirePreference(R.string.pref_key_make_default_browser) + requirePreference(R.string.pref_key_make_default_browser) + val preferenceOpenLinksInExternalApp = findPreference(getPreferenceKey(R.string.pref_key_open_links_in_external_app)) if (!Config.channel.isReleased) { @@ -439,8 +452,11 @@ class SettingsFragment : PreferenceFragmentCompat() { true } - preferenceMakeDefaultBrowser.onPreferenceClickListener = - getClickListenerForMakeDefaultBrowser() + preferenceMakeDefaultBrowser.apply { + updateSwitch() + onPreferenceClickListener = + getClickListenerForMakeDefaultBrowser() + } preferenceOpenLinksInExternalApp?.onPreferenceChangeListener = SharedPreferenceUpdater() @@ -522,7 +538,7 @@ class SettingsFragment : PreferenceFragmentCompat() { findPreference(getPreferenceKey(R.string.pref_key_override_amo_collection)) val show = ( - Config.channel.isNightlyOrDebug && ( + FeatureFlags.customExtensionCollectionFeature && ( settings.amoCollectionOverrideConfigured() || settings.showSecretDebugMenuThisSession ) ) diff --git a/app/src/main/java/org/mozilla/fenix/settings/SyncDebugFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/SyncDebugFragment.kt index 1dbde6eab..615c53b9a 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SyncDebugFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SyncDebugFragment.kt @@ -9,11 +9,11 @@ import androidx.preference.EditTextPreference import androidx.preference.Preference import androidx.preference.Preference.OnPreferenceClickListener import androidx.preference.PreferenceFragmentCompat -import kotlin.system.exitProcess import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.R import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar +import kotlin.system.exitProcess /** * Lets the user customize Private browsing options. diff --git a/app/src/main/java/org/mozilla/fenix/settings/SyncPreferenceView.kt b/app/src/main/java/org/mozilla/fenix/settings/SyncPreferenceView.kt index daf90a145..f88973c02 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/SyncPreferenceView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/SyncPreferenceView.kt @@ -26,8 +26,7 @@ import mozilla.components.service.fxa.manager.SyncEnginesStorage * @param syncEngine The sync engine that will be used for the sync status lookup. * @param loggedOffTitle Text label for the setting when user is not logged in. * @param loggedInTitle Text label for the setting when user is logged in. - * @param onSignInToSyncClicked A callback executed when the [syncPreference] is clicked with a - * preference status of "Sign in to Sync". + * @param onSyncSignInClicked A callback executed when the sync sign in [syncPreference] is clicked. * @param onReconnectClicked A callback executed when the [syncPreference] is clicked with a * preference status of "Reconnect". */ @@ -39,7 +38,7 @@ class SyncPreferenceView( private val syncEngine: SyncEngine, private val loggedOffTitle: String, private val loggedInTitle: String, - private val onSignInToSyncClicked: () -> Unit = {}, + private val onSyncSignInClicked: () -> Unit = {}, private val onReconnectClicked: () -> Unit = {}, ) { @@ -102,7 +101,7 @@ class SyncPreferenceView( title = loggedOffTitle setOnPreferenceChangeListener { _, _ -> - onSignInToSyncClicked() + onSyncSignInClicked() false } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/TextPercentageSeekBarPreference.kt b/app/src/main/java/org/mozilla/fenix/settings/TextPercentageSeekBarPreference.kt index 58db2a041..5beb96143 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/TextPercentageSeekBarPreference.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/TextPercentageSeekBarPreference.kt @@ -37,7 +37,6 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCom import androidx.preference.Preference import androidx.preference.PreferenceViewHolder import org.mozilla.fenix.R - import java.text.NumberFormat import kotlin.math.PI import kotlin.math.abs diff --git a/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt index 714e437ff..35757878b 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/account/SignOutFragment.kt @@ -10,11 +10,11 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.FrameLayout -import com.google.android.material.bottomsheet.BottomSheetDialog +import androidx.appcompat.app.AppCompatDialogFragment import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import com.google.android.material.bottomsheet.BottomSheetBehavior -import androidx.appcompat.app.AppCompatDialogFragment +import com.google.android.material.bottomsheet.BottomSheetDialog import kotlinx.coroutines.launch import mozilla.components.service.fxa.manager.FxaAccountManager import org.mozilla.fenix.R diff --git a/app/src/main/java/org/mozilla/fenix/settings/address/AddressEditorFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/address/AddressEditorFragment.kt index 251477135..542028ef6 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/address/AddressEditorFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/address/AddressEditorFragment.kt @@ -9,6 +9,8 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -27,7 +29,7 @@ import org.mozilla.fenix.settings.address.view.AddressEditorView /** * Displays an address editor for adding and editing an address. */ -class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor) { +class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor), MenuProvider { private lateinit var addressEditorView: AddressEditorView private lateinit var interactor: AddressEditorInteractor @@ -44,6 +46,7 @@ class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) val storage = requireContext().components.core.autofillStorage @@ -56,7 +59,6 @@ class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor) { ) val binding = FragmentAddressEditorBinding.bind(view) - setHasOptionsMenu(true) val searchRegion = requireComponents.core.store.state.search.region addressEditorView = AddressEditorView(binding, interactor, searchRegion, args.address) @@ -82,14 +84,14 @@ class AddressEditorFragment : SecureFragment(R.layout.fragment_address_editor) { this.view?.hideKeyboard() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.address_editor, menu) this.menu = menu menu.findItem(R.id.delete_address_button).isVisible = isEditing } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.delete_address_button -> { args.address?.let { addressEditorView.showConfirmDeleteAddressDialog(requireContext(), it.guid) diff --git a/app/src/main/java/org/mozilla/fenix/settings/address/view/AddressEditorView.kt b/app/src/main/java/org/mozilla/fenix/settings/address/view/AddressEditorView.kt index aa838a446..517e73f2d 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/address/view/AddressEditorView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/address/view/AddressEditorView.kt @@ -8,11 +8,11 @@ import android.content.Context import android.content.DialogInterface import android.view.View import android.widget.AdapterView +import android.widget.ArrayAdapter import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible -import mozilla.components.concept.storage.Address -import android.widget.ArrayAdapter import mozilla.components.browser.state.search.RegionState +import mozilla.components.concept.storage.Address import mozilla.components.concept.storage.UpdatableAddressFields import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.ktx.android.view.showKeyboard diff --git a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt index d453eb834..fa1efc95f 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/advanced/LocaleSettingsFragment.kt @@ -8,11 +8,14 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.appcompat.widget.SearchView +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.ktx.android.view.hideKeyboard import mozilla.components.support.locale.LocaleUseCases @@ -22,7 +25,7 @@ import org.mozilla.fenix.databinding.FragmentLocaleSettingsBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.showToolbar -class LocaleSettingsFragment : Fragment() { +class LocaleSettingsFragment : Fragment(), MenuProvider { private lateinit var localeSettingsStore: LocaleSettingsStore private lateinit var interactor: LocaleSettingsInteractor @@ -33,7 +36,6 @@ class LocaleSettingsFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) } override fun onCreateView( @@ -63,7 +65,7 @@ class LocaleSettingsFragment : Fragment() { return view } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.languages_list, menu) val searchItem = menu.findItem(R.id.search) val searchView: SearchView = searchItem.actionView as SearchView @@ -85,6 +87,8 @@ class LocaleSettingsFragment : Fragment() { ) } + override fun onMenuItemSelected(menuItem: MenuItem): Boolean = false + override fun onResume() { super.onResume() localeView.onResume() @@ -98,6 +102,8 @@ class LocaleSettingsFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + consumeFrom(localeSettingsStore) { localeView.update(it) } diff --git a/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt index ab8e17b8c..530f6cbc9 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/autofill/AutofillSettingFragment.kt @@ -162,7 +162,7 @@ class AutofillSettingFragment : BiometricPromptPreferenceFragment() { .getString(R.string.preferences_credit_cards_sync_cards_across_devices), loggedInTitle = requireContext() .getString(R.string.preferences_credit_cards_sync_cards), - onSignInToSyncClicked = { + onSyncSignInClicked = { findNavController().navigate( NavGraphDirections.actionGlobalTurnOnSync(), ) diff --git a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt index 3fe41720c..36b5da0a6 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/creditcards/CreditCardEditorFragment.kt @@ -11,6 +11,8 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -34,7 +36,9 @@ import org.mozilla.fenix.settings.creditcards.view.CreditCardEditorView /** * Display a credit card editor for adding and editing a credit card. */ -class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_editor) { +class CreditCardEditorFragment : + SecureFragment(R.layout.fragment_credit_card_editor), + MenuProvider { private lateinit var creditCardEditorState: CreditCardEditorState private lateinit var creditCardEditorView: CreditCardEditorView @@ -55,7 +59,7 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setHasOptionsMenu(true) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) val storage = requireContext().components.core.autofillStorage interactor = DefaultCreditCardEditorInteractor( @@ -112,7 +116,7 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed super.onPause() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.credit_card_editor, menu) this.menu = menu @@ -120,7 +124,7 @@ class CreditCardEditorFragment : SecureFragment(R.layout.fragment_credit_card_ed } @Suppress("MagicNumber") - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.delete_credit_card_button -> { args.creditCard?.let { interactor.onDeleteCardButtonClicked(it.guid) } true diff --git a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataController.kt b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataController.kt index e118b6a92..cd668b699 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/deletebrowsingdata/DeleteBrowsingDataController.kt @@ -26,6 +26,7 @@ interface DeleteBrowsingDataController { suspend fun deleteDownloads() } +@Suppress("LongParameterList") class DefaultDeleteBrowsingDataController( private val removeAllTabs: TabsUseCases.RemoveAllTabsUseCase, private val removeAllDownloads: DownloadsUseCases.RemoveAllDownloadsUseCase, diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt index 21e308df3..d1cd8de3a 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/controller/SavedLoginsStorageController.kt @@ -17,14 +17,14 @@ import kotlinx.coroutines.withContext import mozilla.components.concept.storage.Login import mozilla.components.concept.storage.LoginEntry import mozilla.components.service.sync.logins.InvalidRecordException -import mozilla.components.service.sync.logins.LoginsStorageException +import mozilla.components.service.sync.logins.LoginsApiException import mozilla.components.service.sync.logins.NoSuchRecordException import mozilla.components.service.sync.logins.SyncableLoginsStorage import org.mozilla.fenix.R import org.mozilla.fenix.settings.logins.LoginsAction import org.mozilla.fenix.settings.logins.LoginsFragmentStore -import org.mozilla.fenix.settings.logins.fragment.EditLoginFragmentDirections import org.mozilla.fenix.settings.logins.fragment.AddLoginFragmentDirections +import org.mozilla.fenix.settings.logins.fragment.EditLoginFragmentDirections import org.mozilla.fenix.settings.logins.mapToSavedLogin /** @@ -90,7 +90,7 @@ open class SavedLoginsStorageController( try { val encryptedLogin = passwordsStorage.add(loginEntryToSave) syncAndUpdateList(passwordsStorage.decryptLogin(encryptedLogin)) - } catch (loginException: LoginsStorageException) { + } catch (loginException: LoginsApiException) { Log.e( "Add new login", "Failed to add new login.", @@ -140,7 +140,7 @@ open class SavedLoginsStorageController( try { val encryptedLogin = passwordsStorage.update(guid, loginEntryToSave) syncAndUpdateList(passwordsStorage.decryptLogin(encryptedLogin)) - } catch (loginException: LoginsStorageException) { + } catch (loginException: LoginsApiException) { when (loginException) { is NoSuchRecordException, is InvalidRecordException, @@ -194,7 +194,7 @@ open class SavedLoginsStorageController( val validEntry = if (entry.password.isNotEmpty()) entry else entry.copy(password = "password") var dupe = try { passwordsStorage.findLoginToUpdate(validEntry)?.mapToSavedLogin() - } catch (e: LoginsStorageException) { + } catch (e: LoginsApiException) { // If the entry was invalid, then consider it not a dupe null } diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt index 11eba29d7..c84583afc 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/AddLoginFragment.kt @@ -15,8 +15,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.core.content.ContextCompat +import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import mozilla.components.lib.state.ext.consumeFrom @@ -40,7 +42,7 @@ import org.mozilla.fenix.settings.logins.interactor.AddLoginInteractor * Displays the editable new login information for a single website */ @Suppress("TooManyFunctions", "NestedBlockDepth", "ForbiddenComment") -class AddLoginFragment : Fragment(R.layout.fragment_add_login) { +class AddLoginFragment : Fragment(R.layout.fragment_add_login), MenuProvider { private lateinit var loginsFragmentStore: LoginsFragmentStore private lateinit var interactor: AddLoginInteractor @@ -57,7 +59,7 @@ class AddLoginFragment : Fragment(R.layout.fragment_add_login) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setHasOptionsMenu(true) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) _binding = FragmentAddLoginBinding.bind(view) @@ -332,7 +334,7 @@ class AddLoginFragment : Fragment(R.layout.fragment_add_login) { activity?.invalidateOptionsMenu() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.login_save, menu) } @@ -356,7 +358,7 @@ class AddLoginFragment : Fragment(R.layout.fragment_add_login) { showToolbar(getString(R.string.add_login)) } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.save_login_button -> { view?.hideKeyboard() interactor.onAddLogin( diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt index ae058e5d8..6f6d45537 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/EditLoginFragment.kt @@ -14,8 +14,10 @@ import android.view.MenuInflater import android.view.MenuItem import android.view.View import androidx.core.content.ContextCompat +import androidx.core.view.MenuProvider import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -42,7 +44,7 @@ import org.mozilla.fenix.settings.logins.togglePasswordReveal * Displays the editable saved login information for a single website */ @Suppress("TooManyFunctions", "NestedBlockDepth", "ForbiddenComment") -class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { +class EditLoginFragment : Fragment(R.layout.fragment_edit_login), MenuProvider { private val args by navArgs() private lateinit var loginsFragmentStore: LoginsFragmentStore @@ -62,7 +64,7 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setHasOptionsMenu(true) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) _binding = FragmentEditLoginBinding.bind(view) @@ -278,7 +280,7 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { activity?.invalidateOptionsMenu() } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.login_save, menu) } @@ -299,7 +301,7 @@ class EditLoginFragment : Fragment(R.layout.fragment_edit_login) { super.onPause() } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.save_login_button -> { view?.hideKeyboard() interactor.onSaveLogin( diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt index 01e3c8b1f..5d2245c87 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/LoginDetailFragment.kt @@ -15,6 +15,8 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -47,7 +49,7 @@ import org.mozilla.fenix.settings.logins.view.LoginDetailsBindingDelegate * Displays saved login information for a single website. */ @Suppress("TooManyFunctions", "ForbiddenComment") -class LoginDetailFragment : SecureFragment(R.layout.fragment_login_detail) { +class LoginDetailFragment : SecureFragment(R.layout.fragment_login_detail), MenuProvider { private val args by navArgs() private var login: SavedLogin? = null @@ -79,6 +81,7 @@ class LoginDetailFragment : SecureFragment(R.layout.fragment_login_detail) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) interactor = LoginDetailInteractor( SavedLoginsStorageController( @@ -103,11 +106,6 @@ class LoginDetailFragment : SecureFragment(R.layout.fragment_login_detail) { togglePasswordReveal(binding.passwordText, binding.revealPasswordButton) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setHasOptionsMenu(true) - } - /** * As described in #10727, the User should re-auth if the fragment is paused and the user is not * navigating to SavedLoginsFragment or EditLoginFragment @@ -157,12 +155,12 @@ class LoginDetailFragment : SecureFragment(R.layout.fragment_login_detail) { ) } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.login_options_menu, menu) this.menu = menu } - override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { + override fun onMenuItemSelected(item: MenuItem): Boolean = when (item.itemId) { R.id.delete_login_button -> { displayDeleteLoginDialog() true diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsAuthFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsAuthFragment.kt index e81381454..b5d0d2735 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsAuthFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsAuthFragment.kt @@ -146,7 +146,7 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat() { .getString(R.string.preferences_passwords_sync_logins_across_devices), loggedInTitle = requireContext() .getString(R.string.preferences_passwords_sync_logins), - onSignInToSyncClicked = { + onSyncSignInClicked = { val directions = SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToTurnOnSyncFragment() findNavController().navigate(directions) @@ -224,10 +224,12 @@ class SavedLoginsAuthFragment : PreferenceFragmentCompat() { * Called when authentication succeeds. */ private fun navigateToSavedLoginsFragment() { - Logins.openLogins.record(NoExtras()) - val directions = - SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToLoginsListFragment() - findNavController().navigate(directions) + if (findNavController().currentDestination?.id == R.id.savedLoginsAuthFragment) { + Logins.openLogins.record(NoExtras()) + val directions = + SavedLoginsAuthFragmentDirections.actionSavedLoginsAuthFragmentToLoginsListFragment() + findNavController().navigate(directions) + } } private fun navigateToSaveLoginSettingFragment() { diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt index 9291fd976..2d02903a9 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/fragment/SavedLoginsFragment.kt @@ -8,6 +8,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.Menu import android.view.MenuInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.view.inputmethod.EditorInfo @@ -16,6 +17,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.Toolbar import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.MenuProvider +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import mozilla.components.concept.menu.MenuController @@ -42,7 +45,7 @@ import org.mozilla.fenix.settings.logins.interactor.SavedLoginsInteractor import org.mozilla.fenix.settings.logins.view.SavedLoginsListView @SuppressWarnings("TooManyFunctions") -class SavedLoginsFragment : SecureFragment() { +class SavedLoginsFragment : SecureFragment(), MenuProvider { private lateinit var savedLoginsStore: LoginsFragmentStore private lateinit var savedLoginsListView: SavedLoginsListView private lateinit var savedLoginsInteractor: SavedLoginsInteractor @@ -108,7 +111,7 @@ class SavedLoginsFragment : SecureFragment() { } } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.login_list, menu) val searchItem = menu.findItem(R.id.search) val searchView: SearchView = searchItem.actionView as SearchView @@ -134,6 +137,8 @@ class SavedLoginsFragment : SecureFragment() { ) } + override fun onMenuItemSelected(menuItem: MenuItem): Boolean = false + /** * If we pause this fragment, we want to pop users back to reauth */ @@ -160,7 +165,7 @@ class SavedLoginsFragment : SecureFragment() { ) = (activity as HomeActivity).openToBrowserAndLoad(searchTermOrURL, newTab, from) private fun initToolbar() { - setHasOptionsMenu(true) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) showToolbar(getString(R.string.preferences_passwords_saved_logins)) (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary() .setDisplayShowTitleEnabled(false) diff --git a/app/src/main/java/org/mozilla/fenix/settings/logins/view/LoginsListViewHolder.kt b/app/src/main/java/org/mozilla/fenix/settings/logins/view/LoginsListViewHolder.kt index c387a2ac9..198fb83fc 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/logins/view/LoginsListViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/logins/view/LoginsListViewHolder.kt @@ -9,6 +9,7 @@ import androidx.core.view.isVisible import org.mozilla.fenix.databinding.LoginsItemBinding import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView +import org.mozilla.fenix.ext.simplifiedUrl import org.mozilla.fenix.settings.logins.SavedLogin import org.mozilla.fenix.settings.logins.interactor.SavedLoginsInteractor import org.mozilla.fenix.utils.view.ViewHolder @@ -29,7 +30,7 @@ class LoginsListViewHolder( timeLastUsed = item.timeLastUsed, ) val binding = LoginsItemBinding.bind(view) - binding.webAddressView.text = item.origin + binding.webAddressView.text = item.origin.simplifiedUrl() binding.usernameView.isVisible = item.username.isNotEmpty() binding.usernameView.text = item.username diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsController.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsController.kt index 60de1b34e..ffb244419 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsController.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsController.kt @@ -98,16 +98,14 @@ interface QuickSettingsController { * specific Android runtime permissions. * @param displayPermissions callback for when [WebsitePermissionsView] needs to be displayed. */ -@Suppress("TooManyFunctions") +@Suppress("TooManyFunctions", "LongParameterList") class DefaultQuickSettingsController( private val context: Context, private val quickSettingsStore: QuickSettingsFragmentStore, private val browserStore: BrowserStore, private val ioScope: CoroutineScope, private val navController: NavController, - @VisibleForTesting internal val sessionId: String, - @VisibleForTesting internal var sitePermissions: SitePermissions?, private val settings: Settings, private val permissionStorage: PermissionStorage, diff --git a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt index 3e091413b..90c33b1ba 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/quicksettings/WebsitePermissionsView.kt @@ -19,12 +19,12 @@ import org.mozilla.fenix.databinding.QuicksettingsPermissionsBinding import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY import org.mozilla.fenix.settings.PhoneFeature.CAMERA -import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE +import org.mozilla.fenix.settings.PhoneFeature.CROSS_ORIGIN_STORAGE_ACCESS import org.mozilla.fenix.settings.PhoneFeature.LOCATION +import org.mozilla.fenix.settings.PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS +import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION import org.mozilla.fenix.settings.PhoneFeature.PERSISTENT_STORAGE -import org.mozilla.fenix.settings.PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS -import org.mozilla.fenix.settings.PhoneFeature.CROSS_ORIGIN_STORAGE_ACCESS import org.mozilla.fenix.settings.quicksettings.WebsitePermissionsView.PermissionViewHolder.SpinnerPermission import org.mozilla.fenix.settings.quicksettings.WebsitePermissionsView.PermissionViewHolder.ToggleablePermission import java.util.EnumMap diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt index 97528cba7..da6831ba1 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt @@ -18,7 +18,9 @@ import android.widget.CompoundButton import android.widget.LinearLayout import android.widget.RadioButton import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import kotlinx.coroutines.Dispatchers.IO @@ -45,7 +47,8 @@ import org.mozilla.fenix.settings.SupportUtils @SuppressWarnings("LargeClass", "TooManyFunctions") class AddSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), - CompoundButton.OnCheckedChangeListener { + CompoundButton.OnCheckedChangeListener, + MenuProvider { private var availableEngines: List = listOf() private var selectedIndex: Int = -1 private val engineViews = mutableListOf() @@ -56,7 +59,6 @@ class AddSearchEngineFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) availableEngines = requireContext() .components @@ -71,6 +73,8 @@ class AddSearchEngineFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) + val layoutInflater = LayoutInflater.from(context) val layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -125,11 +129,11 @@ class AddSearchEngineFragment : _binding = null } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.add_custom_searchengine_menu, menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.add_search_engine -> { when (selectedIndex) { @@ -143,7 +147,8 @@ class AddSearchEngineFragment : true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt index 9be8f75ed..054016960 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/EditCustomSearchEngineFragment.kt @@ -9,7 +9,9 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View +import androidx.core.view.MenuProvider import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs @@ -32,7 +34,7 @@ import org.mozilla.fenix.settings.SupportUtils /** * Fragment to enter a custom search engine name and URL template. */ -class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine) { +class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_engine), MenuProvider { private val args by navArgs() private lateinit var searchEngine: SearchEngine @@ -43,7 +45,6 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setHasOptionsMenu(true) searchEngine = requireNotNull( requireComponents.core.store.state.search.customSearchEngines.find { engine -> @@ -54,6 +55,7 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED) val url = searchEngine.resultUrls[0] @@ -85,17 +87,18 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng _binding = null } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.edit_custom_searchengine_menu, menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.save_button -> { saveCustomEngine() true } - else -> super.onOptionsItemSelected(item) + // other options are not handled by this menu provider + else -> false } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt index 4cd6fb15b..109325b84 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/SearchEngineFragment.kt @@ -50,6 +50,7 @@ class SearchEngineFragment : PreferenceFragmentCompat() { val showSearchShortcuts = requirePreference(R.string.pref_key_show_search_engine_shortcuts).apply { isChecked = context.settings().shouldShowSearchShortcuts + isVisible = !context.settings().showUnifiedSearchFeature } val showHistorySuggestions = diff --git a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsDetailsExceptionsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsDetailsExceptionsFragment.kt index 3659adcc1..c55705e2e 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsDetailsExceptionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsDetailsExceptionsFragment.kt @@ -25,14 +25,14 @@ import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.settings.PhoneFeature +import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY import org.mozilla.fenix.settings.PhoneFeature.CAMERA +import org.mozilla.fenix.settings.PhoneFeature.CROSS_ORIGIN_STORAGE_ACCESS import org.mozilla.fenix.settings.PhoneFeature.LOCATION +import org.mozilla.fenix.settings.PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION import org.mozilla.fenix.settings.PhoneFeature.PERSISTENT_STORAGE -import org.mozilla.fenix.settings.PhoneFeature.MEDIA_KEY_SYSTEM_ACCESS -import org.mozilla.fenix.settings.PhoneFeature.AUTOPLAY -import org.mozilla.fenix.settings.PhoneFeature.CROSS_ORIGIN_STORAGE_ACCESS import org.mozilla.fenix.settings.quicksettings.AutoplayValue import org.mozilla.fenix.settings.requirePreference import org.mozilla.fenix.utils.Settings diff --git a/app/src/main/java/org/mozilla/fenix/settings/studies/StudiesAdapter.kt b/app/src/main/java/org/mozilla/fenix/settings/studies/StudiesAdapter.kt index 1fdd0c2f5..f2e10fbed 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/studies/StudiesAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/studies/StudiesAdapter.kt @@ -43,8 +43,7 @@ private const val VIEW_HOLDER_TYPE_STUDY = 1 class StudiesAdapter( private val studiesDelegate: StudiesAdapterDelegate, studies: List, - @VisibleForTesting - internal val shouldSubmitOnInit: Boolean = true, + private val shouldSubmitOnInit: Boolean = true, ) : ListAdapter(DifferCallback) { /** * Represents all the studies that will be distributed in multiple headers like diff --git a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt index a30a77964..dcdedd429 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt @@ -40,6 +40,12 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.SemanticsPropertyReceiver +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.onClick +import androidx.compose.ui.semantics.role +import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -124,7 +130,22 @@ private fun WallpaperGroupHeading( style = FirefoxTheme.typography.subtitle2, ) } else { - Column { + val label = stringResource(id = R.string.a11y_action_label_wallpaper_collection_learn_more) + val headingSemantics: SemanticsPropertyReceiver.() -> Unit = + if (collection.learnMoreUrl.isNullOrEmpty()) { + {} + } else { + { + role = Role.Button + onClick(label = label) { + onLearnMoreClick(collection.learnMoreUrl, collection.name) + false + } + } + } + Column( + modifier = Modifier.semantics(mergeDescendants = true, properties = headingSemantics), + ) { Text( text = stringResource(R.string.wallpaper_limited_edition_title), color = FirefoxTheme.colors.textSecondary, @@ -257,6 +278,21 @@ private fun WallpaperThumbnailItem( // Completely avoid drawing the item if a bitmap cannot be loaded and is required if (bitmap == null && wallpaper != defaultWallpaper) return + val description = stringResource( + R.string.wallpapers_item_name_content_description, + wallpaper.name, + ) + + // For the default wallpaper to be accessible, we should set the content description for + // the Surface instead of the thumbnail image + val contentDescriptionModifier = if (bitmap == null) { + Modifier.semantics { + contentDescription = description + } + } else { + Modifier + } + Surface( elevation = 4.dp, shape = thumbnailShape, @@ -265,16 +301,14 @@ private fun WallpaperThumbnailItem( .fillMaxWidth() .aspectRatio(aspectRatio) .then(border) - .clickable { onSelect(wallpaper) }, + .clickable { onSelect(wallpaper) } + .then(contentDescriptionModifier), ) { bitmap?.let { Image( bitmap = it.asImageBitmap(), contentScale = ContentScale.FillBounds, - contentDescription = stringResource( - R.string.wallpapers_item_name_content_description, - wallpaper.name, - ), + contentDescription = description, modifier = Modifier.fillMaxSize(), alpha = if (isLoading) loadingOpacity else 1.0f, ) diff --git a/app/src/main/java/org/mozilla/fenix/share/SaveToPDFInteractor.kt b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFInteractor.kt new file mode 100644 index 000000000..5bfcb7516 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFInteractor.kt @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.share + +/** + * Callbacks for possible user interactions on the [SaveToPDFItem] + */ +interface SaveToPDFInteractor { + /** + * Generates a PDF from the given [tabId]. + * @param tabId The ID of the tab to save as PDF. + */ + fun onSaveToPDF(tabId: String?) +} diff --git a/app/src/main/java/org/mozilla/fenix/share/SaveToPDFItem.kt b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFItem.kt new file mode 100644 index 000000000..728a4d627 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFItem.kt @@ -0,0 +1,70 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.share + +import android.content.res.Configuration +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.R +import org.mozilla.fenix.theme.FirefoxTheme + +/** + * A save to PDF item. + * + * @param onClick event handler when the save to PDF item is clicked. + */ +@Composable +fun SaveToPDFItem( + onClick: () -> Unit, +) { + Row( + modifier = Modifier + .height(56.dp) + .fillMaxWidth() + .clickable(onClick = onClick), + verticalAlignment = Alignment.CenterVertically, + ) { + Spacer(Modifier.width(16.dp)) + + Icon( + painter = painterResource(R.drawable.ic_download), + contentDescription = stringResource( + R.string.content_description_close_button, + ), + tint = FirefoxTheme.colors.iconPrimary, + ) + + Spacer(Modifier.width(32.dp)) + + Text( + color = FirefoxTheme.colors.textPrimary, + text = stringResource(R.string.share_save_to_pdf), + style = FirefoxTheme.typography.subtitle1, + ) + } +} + +@Composable +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun SaveToPDFItemPreview() { + FirefoxTheme { + SaveToPDFItem {} + } +} diff --git a/app/src/main/java/org/mozilla/fenix/share/SaveToPDFMiddleware.kt b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFMiddleware.kt new file mode 100644 index 000000000..3b56847db --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/share/SaveToPDFMiddleware.kt @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.share + +import android.content.Context +import android.widget.Toast +import android.widget.Toast.LENGTH_LONG +import mozilla.components.browser.state.action.BrowserAction +import mozilla.components.browser.state.action.EngineAction +import mozilla.components.browser.state.state.BrowserState +import mozilla.components.lib.state.Action +import mozilla.components.lib.state.Middleware +import mozilla.components.lib.state.MiddlewareContext +import mozilla.telemetry.glean.private.NoExtras +import org.mozilla.fenix.GleanMetrics.Events +import org.mozilla.fenix.R +import org.mozilla.gecko.util.ThreadUtils + +/** + * [BrowserAction] middleware reacting in response to Save to PDF related [Action]s. + * @property context An Application context. + */ +class SaveToPDFMiddleware( + private val context: Context, +) : Middleware { + + override fun invoke( + ctx: MiddlewareContext, + next: (BrowserAction) -> Unit, + action: BrowserAction, + ) { + if (action is EngineAction.SaveToPdfExceptionAction) { + // See https://github.com/mozilla-mobile/fenix/issues/27649 for more details, + // why a Toast is used here. + ThreadUtils.runOnUiThread { + Toast.makeText(context, R.string.unable_to_save_to_pdf_error, LENGTH_LONG).show() + } + Events.saveToPdfFailure.record(NoExtras()) + } else { + next(action) + } + } +} diff --git a/app/src/main/java/org/mozilla/fenix/share/ShareController.kt b/app/src/main/java/org/mozilla/fenix/share/ShareController.kt index 054e5d0bc..f905aac24 100644 --- a/app/src/main/java/org/mozilla/fenix/share/ShareController.kt +++ b/app/src/main/java/org/mozilla/fenix/share/ShareController.kt @@ -20,18 +20,20 @@ import androidx.navigation.NavController import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Deferred import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.TabData import mozilla.components.feature.accounts.push.SendTabUseCases +import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.share.RecentAppsStorage import mozilla.components.service.glean.private.NoExtras import mozilla.components.support.ktx.kotlin.isExtensionUrl +import org.mozilla.fenix.GleanMetrics.Events import org.mozilla.fenix.GleanMetrics.SyncAccount import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar @@ -47,6 +49,11 @@ interface ShareController { fun handleReauth() fun handleShareClosed() fun handleShareToApp(app: AppShareOption) + + /** + * Handles when a save to PDF action was requested. + */ + fun handleSaveToPDF(tabId: String?) fun handleAddNewDevice() fun handleShareToDevice(device: Device) fun handleShareToAllDevices(devices: List) @@ -68,12 +75,13 @@ interface ShareController { * @param navController - [NavController] used for navigation. * @param dismiss - callback signalling sharing can be closed. */ -@Suppress("TooManyFunctions") +@Suppress("TooManyFunctions", "LongParameterList") class DefaultShareController( private val context: Context, private val shareSubject: String?, private val shareData: List, private val sendTabUseCases: SendTabUseCases, + private val saveToPdfUseCase: SessionUseCases.SaveToPdfUseCase, private val snackbar: FenixSnackbar, private val navController: NavController, private val recentAppsStorage: RecentAppsStorage, @@ -130,6 +138,12 @@ class DefaultShareController( dismiss(result) } + override fun handleSaveToPDF(tabId: String?) { + Events.saveToPdfTapped.record(NoExtras()) + handleShareClosed() + saveToPdfUseCase.invoke(tabId) + } + override fun handleAddNewDevice() { val directions = ShareFragmentDirections.actionShareFragmentToAddNewDeviceFragment() navController.navigate(directions) diff --git a/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt b/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt index 6a871d490..0574448ac 100644 --- a/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/share/ShareFragment.kt @@ -10,6 +10,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatDialogFragment +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.core.view.isVisible import androidx.fragment.app.clearFragmentResult import androidx.fragment.app.setFragmentResult import androidx.fragment.app.viewModels @@ -22,11 +24,13 @@ import mozilla.components.browser.state.selector.findTabOrCustomTab import mozilla.components.concept.engine.prompt.PromptRequest import mozilla.components.feature.accounts.push.SendTabUseCases import mozilla.components.feature.share.RecentAppsStorage +import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.databinding.FragmentShareBinding import org.mozilla.fenix.ext.getRootView import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.theme.FirefoxTheme class ShareFragment : AppCompatDialogFragment() { @@ -80,6 +84,7 @@ class ShareFragment : AppCompatDialogFragment() { ), navController = findNavController(), sendTabUseCases = SendTabUseCases(accountManager), + saveToPdfUseCase = requireComponents.useCases.sessionUseCases.saveToPdf, recentAppsStorage = RecentAppsStorage(requireContext()), viewLifecycleScope = viewLifecycleOwner.lifecycleScope, ) { result -> @@ -111,6 +116,20 @@ class ShareFragment : AppCompatDialogFragment() { } shareToAppsView = ShareToAppsView(binding.appsShareLayout, shareInteractor) + if (FeatureFlags.saveToPDF) { + binding.dividerLineAppsShareAndPdfSection.isVisible = true + binding.savePdf.apply { + isVisible = true + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + FirefoxTheme { + SaveToPDFItem { + shareInteractor.onSaveToPDF(tabId = args.sessionId) + } + } + } + } + } return binding.root } diff --git a/app/src/main/java/org/mozilla/fenix/share/ShareInteractor.kt b/app/src/main/java/org/mozilla/fenix/share/ShareInteractor.kt index fe6897d51..bd945b5ce 100644 --- a/app/src/main/java/org/mozilla/fenix/share/ShareInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/share/ShareInteractor.kt @@ -12,7 +12,7 @@ import org.mozilla.fenix.share.listadapters.AppShareOption */ class ShareInteractor( private val controller: ShareController, -) : ShareCloseInteractor, ShareToAccountDevicesInteractor, ShareToAppsInteractor { +) : ShareCloseInteractor, ShareToAccountDevicesInteractor, ShareToAppsInteractor, SaveToPDFInteractor { override fun onReauth() { controller.handleReauth() } @@ -40,4 +40,8 @@ class ShareInteractor( override fun onShareToApp(appToShareTo: AppShareOption) { controller.handleShareToApp(appToShareTo) } + + override fun onSaveToPDF(tabId: String?) { + controller.handleSaveToPDF(tabId) + } } diff --git a/app/src/main/java/org/mozilla/fenix/share/viewholders/AccountDeviceViewHolder.kt b/app/src/main/java/org/mozilla/fenix/share/viewholders/AccountDeviceViewHolder.kt index 3746dd744..bd4a343c5 100644 --- a/app/src/main/java/org/mozilla/fenix/share/viewholders/AccountDeviceViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/share/viewholders/AccountDeviceViewHolder.kt @@ -18,7 +18,7 @@ import org.mozilla.fenix.utils.Do class AccountDeviceViewHolder( itemView: View, - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + @get:VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) val interactor: ShareToAccountDevicesInteractor, ) : RecyclerView.ViewHolder(itemView) { diff --git a/app/src/main/java/org/mozilla/fenix/share/viewholders/AppViewHolder.kt b/app/src/main/java/org/mozilla/fenix/share/viewholders/AppViewHolder.kt index 3490019ad..0471b1acf 100644 --- a/app/src/main/java/org/mozilla/fenix/share/viewholders/AppViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/share/viewholders/AppViewHolder.kt @@ -14,7 +14,7 @@ import org.mozilla.fenix.share.listadapters.AppShareOption class AppViewHolder( itemView: View, - @VisibleForTesting val interactor: ShareToAppsInteractor, + @get:VisibleForTesting val interactor: ShareToAppsInteractor, ) : RecyclerView.ViewHolder(itemView) { private var application: AppShareOption? = null diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/MenuIntegration.kt b/app/src/main/java/org/mozilla/fenix/tabstray/MenuIntegration.kt index fec55684b..c3272a053 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/MenuIntegration.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/MenuIntegration.kt @@ -15,11 +15,11 @@ import org.mozilla.fenix.utils.Do * A wrapper class that building the tabs tray menu that handles item clicks. */ class MenuIntegration( - @VisibleForTesting internal val context: Context, - @VisibleForTesting internal val browserStore: BrowserStore, - @VisibleForTesting internal val tabsTrayStore: TabsTrayStore, - @VisibleForTesting internal val tabLayout: TabLayout, - @VisibleForTesting internal val navigationInteractor: NavigationInteractor, + @get:VisibleForTesting internal val context: Context, + @get:VisibleForTesting internal val browserStore: BrowserStore, + @get:VisibleForTesting internal val tabsTrayStore: TabsTrayStore, + @get:VisibleForTesting internal val tabLayout: TabLayout, + @get:VisibleForTesting internal val navigationInteractor: NavigationInteractor, ) { private val tabsTrayItemMenu by lazy { TabsTrayMenu( diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/NavigationInteractor.kt b/app/src/main/java/org/mozilla/fenix/tabstray/NavigationInteractor.kt index b75e64338..51538d9c0 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/NavigationInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/NavigationInteractor.kt @@ -12,7 +12,6 @@ import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.state.TabSessionState import mozilla.components.browser.state.store.BrowserStore -import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.glean.private.NoExtras @@ -29,6 +28,7 @@ import org.mozilla.fenix.home.HomeFragment import org.mozilla.fenix.tabstray.ext.getTabSessionState import org.mozilla.fenix.tabstray.ext.isActiveDownload import kotlin.coroutines.CoroutineContext +import mozilla.components.browser.storage.sync.Tab as SyncTab /** * An interactor that helps with navigating to different parts of the app from the tabs tray. diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabSheetBehaviorManager.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabSheetBehaviorManager.kt index df4cf5a69..bb76ec72b 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabSheetBehaviorManager.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabSheetBehaviorManager.kt @@ -85,8 +85,8 @@ internal class TabSheetBehaviorManager( @VisibleForTesting internal class TraySheetBehaviorCallback( - @VisibleForTesting internal val behavior: BottomSheetBehavior, - @VisibleForTesting internal val trayInteractor: NavigationInteractor, + @get:VisibleForTesting internal val behavior: BottomSheetBehavior, + @get:VisibleForTesting internal val trayInteractor: NavigationInteractor, ) : BottomSheetBehavior.BottomSheetCallback() { override fun onStateChanged(bottomSheet: View, newState: Int) { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt index e10464ec3..56a61f095 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayController.kt @@ -107,7 +107,7 @@ interface TabsTrayController { fun handleMediaClicked(tab: SessionState) } -@Suppress("TooManyFunctions") +@Suppress("TooManyFunctions", "LongParameterList") class DefaultTabsTrayController( private val trayStore: TabsTrayStore, private val browserStore: BrowserStore, @@ -120,7 +120,6 @@ class DefaultTabsTrayController( private val selectTabPosition: (Int, Boolean) -> Unit, private val dismissTray: () -> Unit, private val showUndoSnackbarForTab: (Boolean) -> Unit, - @VisibleForTesting internal val showCancelledDownloadWarning: (downloadCount: Int, tabId: String?, source: String?) -> Unit, ) : TabsTrayController { diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt index e7846bb29..2730893f8 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayFragment.kt @@ -63,8 +63,8 @@ import org.mozilla.fenix.tabstray.ext.bookmarkMessage import org.mozilla.fenix.tabstray.ext.collectionMessage import org.mozilla.fenix.tabstray.ext.make import org.mozilla.fenix.tabstray.ext.showWithTheme -import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsIntegration +import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.allowUndo import kotlin.math.max diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInfoBannerBinding.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInfoBannerBinding.kt index b9325ea6d..5e181c530 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInfoBannerBinding.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TabsTrayInfoBannerBinding.kt @@ -8,7 +8,6 @@ import android.content.Context import android.view.View.VISIBLE import android.view.ViewGroup import androidx.annotation.VisibleForTesting -import kotlin.math.max import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collect @@ -22,6 +21,7 @@ import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged import org.mozilla.fenix.R import org.mozilla.fenix.browser.infobanner.InfoBanner import org.mozilla.fenix.utils.Settings +import kotlin.math.max @OptIn(ExperimentalCoroutinesApi::class) class TabsTrayInfoBannerBinding( diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt index a9628364e..f61f05d6a 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/TrayPagerAdapter.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.tabstray import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup -import androidx.annotation.VisibleForTesting import androidx.compose.ui.platform.ComposeView import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.ConcatAdapter @@ -25,15 +24,15 @@ import org.mozilla.fenix.tabstray.viewholders.SyncedTabsPageViewHolder @Suppress("LongParameterList") class TrayPagerAdapter( - @VisibleForTesting internal val context: Context, - @VisibleForTesting internal val lifecycleOwner: LifecycleOwner, - @VisibleForTesting internal val tabsTrayStore: TabsTrayStore, - @VisibleForTesting internal val browserInteractor: BrowserTrayInteractor, - @VisibleForTesting internal val navInteractor: NavigationInteractor, - @VisibleForTesting internal val tabsTrayInteractor: TabsTrayInteractor, - @VisibleForTesting internal val browserStore: BrowserStore, - @VisibleForTesting internal val appStore: AppStore, - @VisibleForTesting internal val inactiveTabsInteractor: InactiveTabsInteractor, + internal val context: Context, + internal val lifecycleOwner: LifecycleOwner, + internal val tabsTrayStore: TabsTrayStore, + internal val browserInteractor: BrowserTrayInteractor, + internal val navInteractor: NavigationInteractor, + internal val tabsTrayInteractor: TabsTrayInteractor, + internal val browserStore: BrowserStore, + internal val appStore: AppStore, + internal val inactiveTabsInteractor: InactiveTabsInteractor, ) : RecyclerView.Adapter() { /** diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/AbstractBrowserTabViewHolder.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/AbstractBrowserTabViewHolder.kt index 696366c73..57af576a8 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/AbstractBrowserTabViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/AbstractBrowserTabViewHolder.kt @@ -25,12 +25,11 @@ import mozilla.components.browser.tabstray.SelectableTabViewHolder import mozilla.components.browser.tabstray.TabsTray import mozilla.components.browser.tabstray.TabsTrayStyling import mozilla.components.browser.tabstray.thumbnail.TabThumbnailView -import mozilla.components.browser.toolbar.MAX_URI_LENGTH import mozilla.components.concept.base.images.ImageLoadRequest import mozilla.components.concept.base.images.ImageLoader import mozilla.components.concept.engine.mediasession.MediaSession +import mozilla.components.support.ktx.kotlin.MAX_URI_LENGTH import mozilla.telemetry.glean.private.NoExtras -import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.GleanMetrics.Tab import org.mozilla.fenix.R import org.mozilla.fenix.ext.components @@ -110,11 +109,7 @@ abstract class AbstractBrowserTabViewHolder( } } - if (tab.content.thumbnail != null) { - thumbnailView.setImageBitmap(tab.content.thumbnail) - } else { - loadIntoThumbnailView(thumbnailView, tab.id) - } + loadIntoThumbnailView(thumbnailView, tab.id) } override fun showTabIsMultiSelectEnabled(selectedMaskView: View?, isSelected: Boolean) { @@ -244,7 +239,7 @@ abstract class AbstractBrowserTabViewHolder( val touchStart = touchStartPoint val selected = holder.selectedItems val selectsOnlyThis = (selected.size == 1 && selected.contains(item)) - if (FeatureFlags.tabReorderingFeature && selectsOnlyThis && touchStart != null) { + if (selectsOnlyThis && touchStart != null) { // If the parent is null then return early and mark the event as unhandled val parent = itemView.parent as? AbstractBrowserTrayList ?: return@setOnTouchListener false diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/PrivateBrowserTrayList.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/PrivateBrowserTrayList.kt index 656fa9fd3..637213c0d 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/PrivateBrowserTrayList.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/PrivateBrowserTrayList.kt @@ -7,7 +7,7 @@ package org.mozilla.fenix.tabstray.browser import android.content.Context import android.util.AttributeSet import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PACKAGE_PRIVATE import org.mozilla.fenix.ext.components class PrivateBrowserTrayList @JvmOverloads constructor( diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/ext/BrowserMenu.kt b/app/src/main/java/org/mozilla/fenix/tabstray/ext/BrowserMenu.kt index 08ffefbac..f22359741 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/ext/BrowserMenu.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/ext/BrowserMenu.kt @@ -18,7 +18,7 @@ fun BrowserMenu.showWithTheme(view: View) { (popupMenu.contentView as? CardView)?.setCardBackgroundColor( ContextCompat.getColor( view.context, - R.color.fx_mobile_layer_color_1, + R.color.fx_mobile_layer_color_2, ), ) } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/ext/SyncedDeviceTabs.kt b/app/src/main/java/org/mozilla/fenix/tabstray/ext/SyncedDeviceTabs.kt index e1fc53c34..f66bf6560 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/ext/SyncedDeviceTabs.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/ext/SyncedDeviceTabs.kt @@ -5,7 +5,7 @@ package org.mozilla.fenix.tabstray.ext import mozilla.components.browser.storage.sync.SyncedDeviceTabs -import mozilla.components.browser.toolbar.MAX_URI_LENGTH +import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.tabstray.syncedtabs.SyncedTabsListItem /** @@ -20,7 +20,7 @@ fun List.toComposeList( } else { tabs.map { val url = it.active().url - val titleText = it.active().title.ifEmpty { url.take(MAX_URI_LENGTH) } + val titleText = it.active().title.ifEmpty { url.trimmed() } SyncedTabsListItem.Tab(titleText, url, it) } } @@ -32,7 +32,7 @@ fun List.toComposeList( } else { tabs.asSequence().map { val url = it.active().url - val titleText = it.active().title.ifEmpty { url.take(MAX_URI_LENGTH) } + val titleText = it.active().title.ifEmpty { url.trimmed() } SyncedTabsListItem.Tab(titleText, url, it) } } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/ext/TabSessionState.kt b/app/src/main/java/org/mozilla/fenix/tabstray/ext/TabSessionState.kt index 216ce4955..5fb9f02d6 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/ext/TabSessionState.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/ext/TabSessionState.kt @@ -5,7 +5,7 @@ package org.mozilla.fenix.tabstray.ext import mozilla.components.browser.state.state.TabSessionState -import mozilla.components.browser.toolbar.MAX_URI_LENGTH +import mozilla.components.support.ktx.kotlin.trimmed fun TabSessionState.isActive(maxActiveTime: Long): Boolean { val lastActiveTime = maxOf(lastAccess, createdAt) @@ -58,4 +58,4 @@ internal fun TabSessionState.isNormalTab(): Boolean { /** * Returns a [String] for displaying a [TabSessionState]'s title or its url when a title is not available. */ -fun TabSessionState.toDisplayTitle(): String = content.title.ifEmpty { content.url.take(MAX_URI_LENGTH) } +fun TabSessionState.toDisplayTitle(): String = content.title.ifEmpty { content.url.trimmed() } diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/syncedtabs/SyncedTabs.kt b/app/src/main/java/org/mozilla/fenix/tabstray/syncedtabs/SyncedTabs.kt index 49ed93fff..8ad5ee0c4 100644 --- a/app/src/main/java/org/mozilla/fenix/tabstray/syncedtabs/SyncedTabs.kt +++ b/app/src/main/java/org/mozilla/fenix/tabstray/syncedtabs/SyncedTabs.kt @@ -21,7 +21,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material.Divider import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -35,6 +34,7 @@ import androidx.compose.ui.unit.sp import mozilla.components.browser.storage.sync.TabEntry import mozilla.components.feature.syncedtabs.view.SyncedTabsView import org.mozilla.fenix.R +import org.mozilla.fenix.compose.Divider import org.mozilla.fenix.compose.button.PrimaryButton import org.mozilla.fenix.compose.ext.dashedBorder import org.mozilla.fenix.compose.list.ExpandableListHeader @@ -170,7 +170,7 @@ fun SyncedTabsSectionHeader( onClick = onClick, ) - Divider(color = FirefoxTheme.colors.borderPrimary) + Divider() } } diff --git a/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryMiddleware.kt b/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryMiddleware.kt index 6863fb233..c53ca405f 100644 --- a/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryMiddleware.kt +++ b/app/src/main/java/org/mozilla/fenix/telemetry/TelemetryMiddleware.kt @@ -15,13 +15,14 @@ import mozilla.components.browser.state.selector.normalTabs import mozilla.components.browser.state.state.BrowserState import mozilla.components.browser.state.state.EngineState import mozilla.components.browser.state.state.SessionState -import mozilla.components.feature.search.telemetry.ads.AdsTelemetry import mozilla.components.lib.state.Middleware import mozilla.components.lib.state.MiddlewareContext import mozilla.components.support.base.android.Clock import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.GleanMetrics.Events import org.mozilla.fenix.GleanMetrics.Metrics +import org.mozilla.fenix.components.metrics.Event +import org.mozilla.fenix.components.metrics.MetricController import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.GleanMetrics.EngineTab as EngineMetrics @@ -29,10 +30,11 @@ import org.mozilla.fenix.GleanMetrics.EngineTab as EngineMetrics * [Middleware] to record telemetry in response to [BrowserAction]s. * * @property settings reference to the application [Settings]. - * @property adsTelemetry reference to [AdsTelemetry] use to record search telemetry. + * @property metrics [MetricController] to pass events that have been mapped from actions */ class TelemetryMiddleware( private val settings: Settings, + private val metrics: MetricController, ) : Middleware { private val logger = Logger("TelemetryMiddleware") @@ -58,6 +60,9 @@ class TelemetryMiddleware( val tab = context.state.findTabOrCustomTab(action.tabId) onEngineSessionKilled(context.state, tab) } + is EngineAction.LoadUrlAction -> { + metrics.track(Event.GrowthData.FirstUriLoadForDay) + } else -> { // no-op } diff --git a/app/src/main/java/org/mozilla/fenix/theme/FirefoxTheme.kt b/app/src/main/java/org/mozilla/fenix/theme/FirefoxTheme.kt index e9475726d..954af61b3 100644 --- a/app/src/main/java/org/mozilla/fenix/theme/FirefoxTheme.kt +++ b/app/src/main/java/org/mozilla/fenix/theme/FirefoxTheme.kt @@ -87,72 +87,6 @@ object FirefoxTheme { get() = defaultTypography } -private val privateColorPalette = FirefoxColors( - layer1 = PhotonColors.Ink50, - layer2 = PhotonColors.Ink50, - layer3 = PhotonColors.Ink50, - layer4Start = PhotonColors.Purple70, - layer4Center = PhotonColors.Violet80, - layer4End = PhotonColors.Ink05, - layerAccent = PhotonColors.Violet40, - layerAccentNonOpaque = PhotonColors.Violet50A32, - layerAccentOpaque = Color(0xFF423262), - scrim = PhotonColors.DarkGrey90A95, - gradientStart = PhotonColors.Violet70, - gradientEnd = PhotonColors.Violet40, - actionPrimary = PhotonColors.Violet60, - actionSecondary = PhotonColors.LightGrey30, - actionTertiary = PhotonColors.DarkGrey10, - actionQuarternary = PhotonColors.DarkGrey80, - formDefault = PhotonColors.LightGrey05, - formSelected = PhotonColors.Violet40, - formSurface = PhotonColors.DarkGrey05, - formDisabled = PhotonColors.DarkGrey05, - formOn = PhotonColors.Violet40, - formOff = PhotonColors.LightGrey05, - indicatorActive = PhotonColors.LightGrey90, - indicatorInactive = PhotonColors.DarkGrey05, - textPrimary = PhotonColors.LightGrey05, - textSecondary = PhotonColors.LightGrey40, - textDisabled = PhotonColors.LightGrey05A40, - textWarning = PhotonColors.Red20, - textWarningButton = PhotonColors.Red70, - textAccent = PhotonColors.Violet20, - textAccentDisabled = PhotonColors.Violet20A60, - textOnColorPrimary = PhotonColors.LightGrey05, - textOnColorSecondary = PhotonColors.LightGrey40, - textActionPrimary = PhotonColors.LightGrey05, - textActionSecondary = PhotonColors.DarkGrey90, - textActionTertiary = PhotonColors.LightGrey05, - textActionTertiaryActive = PhotonColors.LightGrey05, - iconPrimary = PhotonColors.LightGrey05, - iconPrimaryInactive = PhotonColors.LightGrey05A60, - iconSecondary = PhotonColors.LightGrey40, - iconActive = PhotonColors.Violet40, - iconDisabled = PhotonColors.LightGrey05A40, - iconOnColor = PhotonColors.LightGrey05, - iconNotice = PhotonColors.Blue30, - iconButton = PhotonColors.LightGrey05, - iconWarning = PhotonColors.Red20, - iconWarningButton = PhotonColors.Red70, - iconAccentViolet = PhotonColors.Violet20, - iconAccentBlue = PhotonColors.Blue20, - iconAccentPink = PhotonColors.Pink20, - iconAccentGreen = PhotonColors.Green20, - iconAccentYellow = PhotonColors.Yellow20, - iconActionPrimary = PhotonColors.LightGrey05, - iconActionSecondary = PhotonColors.DarkGrey90, - iconActionTertiary = PhotonColors.LightGrey05, - iconGradientStart = PhotonColors.Violet20, - iconGradientEnd = PhotonColors.Blue20, - borderPrimary = PhotonColors.DarkGrey05, - borderInverted = PhotonColors.LightGrey30, - borderFormDefault = PhotonColors.LightGrey05, - borderAccent = PhotonColors.Violet40, - borderDisabled = PhotonColors.LightGrey05A40, - borderWarning = PhotonColors.Red40, -) - private val darkColorPalette = FirefoxColors( layer1 = PhotonColors.DarkGrey60, layer2 = PhotonColors.DarkGrey30, @@ -285,6 +219,12 @@ private val lightColorPalette = FirefoxColors( borderWarning = PhotonColors.Red70, ) +private val privateColorPalette = darkColorPalette.copy( + layer1 = PhotonColors.Ink50, + layer2 = PhotonColors.Ink50, + layer3 = PhotonColors.Ink50, +) + /** * A custom Color Palette for Mozilla Firefox for Android (Fenix). */ @@ -669,7 +609,74 @@ class FirefoxColors( borderWarning = other.borderWarning } - fun copy(): FirefoxColors = FirefoxColors( + /** + * Return a copy of this [FirefoxColors] and optionally overriding any of the provided values. + */ + fun copy( + layer1: Color = this.layer1, + layer2: Color = this.layer2, + layer3: Color = this.layer3, + layer4Start: Color = this.layer4Start, + layer4Center: Color = this.layer4Center, + layer4End: Color = this.layer4End, + layerAccent: Color = this.layerAccent, + layerAccentNonOpaque: Color = this.layerAccentNonOpaque, + layerAccentOpaque: Color = this.layerAccentOpaque, + scrim: Color = this.scrim, + gradientStart: Color = this.gradientStart, + gradientEnd: Color = this.gradientEnd, + actionPrimary: Color = this.actionPrimary, + actionSecondary: Color = this.actionSecondary, + actionTertiary: Color = this.actionTertiary, + actionQuarternary: Color = this.actionQuarternary, + formDefault: Color = this.formDefault, + formSelected: Color = this.formSelected, + formSurface: Color = this.formSurface, + formDisabled: Color = this.formDisabled, + formOn: Color = this.formOn, + formOff: Color = this.formOff, + indicatorActive: Color = this.indicatorActive, + indicatorInactive: Color = this.indicatorInactive, + textPrimary: Color = this.textPrimary, + textSecondary: Color = this.textSecondary, + textDisabled: Color = this.textDisabled, + textWarning: Color = this.textWarning, + textWarningButton: Color = this.textWarningButton, + textAccent: Color = this.textAccent, + textAccentDisabled: Color = this.textAccentDisabled, + textOnColorPrimary: Color = this.textOnColorPrimary, + textOnColorSecondary: Color = this.textOnColorSecondary, + textActionPrimary: Color = this.textActionPrimary, + textActionSecondary: Color = this.textActionSecondary, + textActionTertiary: Color = this.textActionTertiary, + textActionTertiaryActive: Color = this.textActionTertiaryActive, + iconPrimary: Color = this.iconPrimary, + iconPrimaryInactive: Color = this.iconPrimaryInactive, + iconSecondary: Color = this.iconSecondary, + iconActive: Color = this.iconActive, + iconDisabled: Color = this.iconDisabled, + iconOnColor: Color = this.iconOnColor, + iconNotice: Color = this.iconNotice, + iconButton: Color = this.iconButton, + iconWarning: Color = this.iconWarning, + iconWarningButton: Color = this.iconWarningButton, + iconAccentViolet: Color = this.iconAccentViolet, + iconAccentBlue: Color = this.iconAccentBlue, + iconAccentPink: Color = this.iconAccentPink, + iconAccentGreen: Color = this.iconAccentGreen, + iconAccentYellow: Color = this.iconAccentYellow, + iconActionPrimary: Color = this.iconActionPrimary, + iconActionSecondary: Color = this.iconActionSecondary, + iconActionTertiary: Color = this.iconActionTertiary, + iconGradientStart: Color = this.iconGradientStart, + iconGradientEnd: Color = this.iconGradientEnd, + borderPrimary: Color = this.borderPrimary, + borderInverted: Color = this.borderInverted, + borderFormDefault: Color = this.borderFormDefault, + borderAccent: Color = this.borderAccent, + borderDisabled: Color = this.borderDisabled, + borderWarning: Color = this.borderWarning, + ): FirefoxColors = FirefoxColors( layer1 = layer1, layer2 = layer2, layer3 = layer3, diff --git a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelView.kt b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelView.kt index 74a080131..d9cb2f93f 100644 --- a/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelView.kt +++ b/app/src/main/java/org/mozilla/fenix/trackingprotection/TrackingProtectionPanelView.kt @@ -297,7 +297,7 @@ class TrackingProtectionPanelView( view2, object : AccessibilityDelegateCompat() { override fun onInitializeAccessibilityNodeInfo( - host: View?, + host: View, info: AccessibilityNodeInfoCompat, ) { info.setTraversalAfter(view1) diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index ee8e0b388..5cf37214e 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -13,7 +13,7 @@ import android.content.pm.ShortcutManager import android.os.Build import android.view.accessibility.AccessibilityManager import androidx.annotation.VisibleForTesting -import androidx.annotation.VisibleForTesting.PRIVATE +import androidx.annotation.VisibleForTesting.Companion.PRIVATE import androidx.lifecycle.LifecycleOwner import mozilla.components.concept.engine.Engine.HttpsOnlyMode import mozilla.components.feature.sitepermissions.SitePermissionsRules @@ -31,7 +31,6 @@ import mozilla.components.support.locale.LocaleManager import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.Config import org.mozilla.fenix.FeatureFlags -import org.mozilla.fenix.FeatureFlags.historyImprovementFeatures import org.mozilla.fenix.R import org.mozilla.fenix.browser.browsingmode.BrowsingMode import org.mozilla.fenix.components.metrics.MozillaProductDetector @@ -82,9 +81,9 @@ class Settings(private val appContext: Context) : PreferencesHolder { /** * The minimum number a search groups should contain. - * Filtering is applied depending on the [historyImprovementFeatures] flag value. */ - const val SEARCH_GROUP_MINIMUM_SITES: Int = 2 + @VisibleForTesting + internal var SEARCH_GROUP_MINIMUM_SITES: Int = 2 // The maximum number of top sites to display. const val TOP_SITES_MAX_COUNT = 160 @@ -201,10 +200,20 @@ class Settings(private val appContext: Context) : PreferencesHolder { ) /** - * A cache of the background color to use on cards overlaying the current wallpaper. + * A cache of the background color to use on cards overlaying the current wallpaper when the user's + * theme is set to Light. */ - var currentWallpaperCardColor by longPreference( - appContext.getPreferenceKey(R.string.pref_key_current_wallpaper_card_color), + var currentWallpaperCardColorLight by longPreference( + appContext.getPreferenceKey(R.string.pref_key_current_wallpaper_card_color_light), + default = 0, + ) + + /** + * A cache of the background color to use on cards overlaying the current wallpaper when the user's + * theme is set to Dark. + */ + var currentWallpaperCardColorDark by longPreference( + appContext.getPreferenceKey(R.string.pref_key_current_wallpaper_card_color_dark), default = 0, ) @@ -216,6 +225,14 @@ class Settings(private val appContext: Context) : PreferencesHolder { default = true, ) + /** + * Indicates if the current legacy wallpaper card colors should be migrated. + */ + var shouldMigrateLegacyWallpaperCardColors by booleanPreference( + key = appContext.getPreferenceKey(R.string.pref_key_should_migrate_wallpaper_card_colors), + default = true, + ) + /** * Indicates if the wallpaper onboarding dialog should be shown. */ @@ -601,9 +618,10 @@ class Settings(private val appContext: Context) : PreferencesHolder { /** * Indicates if the total cookie protection CRF should be shown. */ - var shouldShowTotalCookieProtectionCFR by booleanPreference( + var shouldShowTotalCookieProtectionCFR by lazyFeatureFlagPreference( appContext.getPreferenceKey(R.string.pref_key_should_show_total_cookie_protection_popup), - default = mr2022Sections[Mr2022Section.TCP_CFR] == true, + featureFlag = true, + default = { mr2022Sections[Mr2022Section.TCP_CFR] == true }, ) val blockCookiesSelectionInCustomTrackingProtection by stringPreference( @@ -1027,11 +1045,6 @@ class Settings(private val appContext: Context) : PreferencesHolder { default = true, ) - var lastPlacesStorageMaintenance by longPreference( - appContext.getPreferenceKey(R.string.pref_key_last_maintenance), - default = 0, - ) - fun addSearchWidgetInstalled(count: Int) { val key = appContext.getPreferenceKey(R.string.pref_key_search_widget_installed) val newValue = preferences.getInt(key, 0) + count @@ -1420,4 +1433,29 @@ class Settings(private val appContext: Context) : PreferencesHolder { HttpsOnlyMode.ENABLED } } + + var setAsDefaultGrowthSent by booleanPreference( + key = appContext.getPreferenceKey(R.string.pref_key_growth_set_as_default), + default = false, + ) + + var resumeGrowthLastSent by longPreference( + key = appContext.getPreferenceKey(R.string.pref_key_growth_resume_last_sent), + default = 0, + ) + + var uriLoadGrowthLastSent by longPreference( + key = appContext.getPreferenceKey(R.string.pref_key_growth_uri_load_last_sent), + default = 0, + ) + + var firstWeekSeriesGrowthSent by booleanPreference( + key = appContext.getPreferenceKey(R.string.pref_key_growth_first_week_series_sent), + default = false, + ) + + var firstWeekDaysOfUseGrowthData by stringSetPreference( + key = appContext.getPreferenceKey(R.string.pref_key_growth_first_week_days_of_use), + default = setOf(), + ) } diff --git a/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt b/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt index 83d20509f..839916483 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/ToolbarPopupWindow.kt @@ -14,17 +14,17 @@ import android.widget.PopupWindow import androidx.annotation.VisibleForTesting import androidx.core.view.isVisible import com.google.android.material.snackbar.Snackbar +import mozilla.components.browser.state.selector.findCustomTab import mozilla.components.browser.state.selector.selectedTab import mozilla.components.browser.state.store.BrowserStore -import org.mozilla.fenix.R -import org.mozilla.fenix.components.FenixSnackbar -import org.mozilla.fenix.ext.components -import java.lang.ref.WeakReference -import mozilla.components.browser.state.selector.findCustomTab import mozilla.components.service.glean.private.NoExtras import mozilla.components.support.base.log.logger.Logger import org.mozilla.fenix.GleanMetrics.Events +import org.mozilla.fenix.R +import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.databinding.BrowserToolbarPopupWindowBinding +import org.mozilla.fenix.ext.components +import java.lang.ref.WeakReference object ToolbarPopupWindow { fun show( diff --git a/app/src/main/java/org/mozilla/fenix/utils/Undo.kt b/app/src/main/java/org/mozilla/fenix/utils/Undo.kt index cb6fb9b1b..e06f61714 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Undo.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Undo.kt @@ -6,13 +6,10 @@ package org.mozilla.fenix.utils import android.content.Context import android.view.View -import androidx.appcompat.widget.ContentFrameLayout -import androidx.core.view.updatePadding import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.ext.settings import java.util.concurrent.atomic.AtomicBoolean @@ -66,7 +63,7 @@ fun CoroutineScope.allowUndo( .make( view = view, duration = FenixSnackbar.LENGTH_INDEFINITE, - isDisplayedWithBrowserToolbar = false, + isDisplayedWithBrowserToolbar = paddedForBottomToolbar, ) .setText(message) .setAnchorView(anchorView) @@ -81,27 +78,6 @@ fun CoroutineScope.allowUndo( snackbar.view.elevation = it } - val shouldUseBottomToolbar = view.context.settings().shouldUseBottomToolbar - val toolbarHeight = view.resources.getDimensionPixelSize(R.dimen.browser_toolbar_height) - val dynamicToolbarEnabled = view.context.settings().isDynamicToolbarEnabled - - snackbar.view.updatePadding( - bottom = if ( - paddedForBottomToolbar && - shouldUseBottomToolbar && - // If the view passed in is a ContentFrameLayout, it does not matter - // if the user has a dynamicBottomToolbar or not, as the Android system - // can't intelligently position the snackbar on the upper most view. - // Ideally we should not pass ContentFrameLayout in, but it's the only - // way to display snackbars through a fragment transition. - (view is ContentFrameLayout || !dynamicToolbarEnabled) - ) { - toolbarHeight - } else { - 0 - }, - ) - snackbar.show() // Wait a bit, and if user didn't request cancellation, proceed with diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperFileManager.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperFileManager.kt index 14285d21d..68dbb48b8 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperFileManager.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperFileManager.kt @@ -37,7 +37,8 @@ class LegacyWallpaperFileManager( name = name, collection = Wallpaper.DefaultCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ) diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperMigration.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperMigration.kt index 3358b27a1..bbb3fa4e0 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperMigration.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/LegacyWallpaperMigration.kt @@ -97,6 +97,7 @@ class LegacyWallpaperMigration( } } catch (e: IOException) { Logger.error("Failed to migrate legacy wallpaper", e) + settings.shouldMigrateLegacyWallpaperCardColors = false } // Delete the remaining legacy files @@ -106,9 +107,41 @@ class LegacyWallpaperMigration( return@withContext migratedWallpaperName } + /** + * Helper function used to migrate a legacy wallpaper's card colors that previously did not exist. + */ + fun migrateExpiredWallpaperCardColors() { + // The card colors should NOT be migrated if the file migration was ran prior to these + // changes and it failed. We can verify this by checking [settings.currentWallpaperTextColor], + // since this is only initialized for legacy wallpapers in + // [LegacyWallpaperMigration.migrateLegacyWallpaper]. + if (settings.currentWallpaperTextColor != 0L) { + when (settings.currentWallpaperName) { + TURNING_RED_MEI_WALLPAPER_NAME -> { + settings.currentWallpaperCardColorLight = + TURNING_RED_MEI_WALLPAPER_CARD_COLOR_LIGHT.toLong(radix = 16) + settings.currentWallpaperCardColorDark = + TURNING_RED_MEI_WALLPAPER_CARD_COLOR_DARK.toLong(radix = 16) + } + TURNING_RED_PANDA_WALLPAPER_NAME -> { + settings.currentWallpaperCardColorLight = + TURNING_RED_PANDA_WALLPAPER_CARD_COLOR_LIGHT.toLong(radix = 16) + settings.currentWallpaperCardColorDark = + TURNING_RED_PANDA_WALLPAPER_CARD_COLOR_DARK.toLong(radix = 16) + } + } + } + + settings.shouldMigrateLegacyWallpaperCardColors = false + } + companion object { const val TURNING_RED_MEI_WALLPAPER_NAME = "mei" const val TURNING_RED_PANDA_WALLPAPER_NAME = "panda" const val TURNING_RED_WALLPAPER_TEXT_COLOR = "FFFBFBFE" + const val TURNING_RED_MEI_WALLPAPER_CARD_COLOR_LIGHT = "FFFDE9C3" + const val TURNING_RED_MEI_WALLPAPER_CARD_COLOR_DARK = "FF532906" + const val TURNING_RED_PANDA_WALLPAPER_CARD_COLOR_LIGHT = "FFFFEDF1" + const val TURNING_RED_PANDA_WALLPAPER_CARD_COLOR_DARK = "FF611B28" } } diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/Wallpaper.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/Wallpaper.kt index d53c1478f..efcbed05c 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/Wallpaper.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/Wallpaper.kt @@ -14,13 +14,17 @@ import java.util.Date * @property collection The name of the collection the wallpaper belongs to. * is not restricted. * @property textColor The 8 digit hex code color that should be used for text overlaying the wallpaper. - * @property cardColor The 8 digit hex code color that should be used for cards overlaying the wallpaper. + * @property cardColorLight The 8 digit hex code color that should be used for cards overlaying the wallpaper + * when the user's theme is set to Light. + * @property cardColorDark The 8 digit hex code color that should be used for cards overlaying the wallpaper + * when the user's theme is set to Dark. */ data class Wallpaper( val name: String, val collection: Collection, val textColor: Long?, - val cardColor: Long?, + val cardColorLight: Long?, + val cardColorDark: Long?, val thumbnailFileState: ImageFileState, val assetsFileState: ImageFileState, ) { @@ -84,7 +88,8 @@ data class Wallpaper( name = defaultName, collection = DefaultCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = ImageFileState.Downloaded, assetsFileState = ImageFileState.Downloaded, ) @@ -112,15 +117,18 @@ data class Wallpaper( * * @param settings The local cache. */ + @Suppress("ComplexCondition") fun getCurrentWallpaperFromSettings(settings: Settings): Wallpaper? { val name = settings.currentWallpaperName val textColor = settings.currentWallpaperTextColor - val cardColor = settings.currentWallpaperCardColor - return if (name.isNotEmpty() && textColor != 0L && cardColor != 0L) { + val cardColorLight = settings.currentWallpaperCardColorLight + val cardColorDark = settings.currentWallpaperCardColorDark + return if (name.isNotEmpty() && textColor != 0L && cardColorLight != 0L && cardColorDark != 0L) { Wallpaper( name = name, textColor = textColor, - cardColor = cardColor, + cardColorLight = cardColorLight, + cardColorDark = cardColorDark, collection = DefaultCollection, thumbnailFileState = ImageFileState.Downloaded, assetsFileState = ImageFileState.Downloaded, diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperDownloader.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperDownloader.kt index d0ecc4252..2beff12a7 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperDownloader.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperDownloader.kt @@ -80,7 +80,7 @@ class WallpaperDownloader( if (!response.isSuccess) { throw IllegalStateException() } - File(localFile.path.substringBeforeLast("/")).mkdirs() + localFile.parentFile?.mkdirs() response.body.useStream { input -> input.copyTo(localFile.outputStream()) } diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperFileManager.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperFileManager.kt index 5bd3bb120..d7421dc06 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperFileManager.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperFileManager.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.wallpapers.Wallpaper.Companion.getLocalPath import java.io.File @@ -21,22 +22,25 @@ import java.io.File */ class WallpaperFileManager( private val storageRootDirectory: File, - coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO, ) { - private val scope = CoroutineScope(coroutineDispatcher) private val wallpapersDirectory = File(storageRootDirectory, "wallpapers") /** * Lookup all the files for a wallpaper name. This lookup will fail if there are not * files for each of a portrait and landscape orientation as well as a thumbnail. + * + * @param settings The local cache. */ - suspend fun lookupExpiredWallpaper(name: String): Wallpaper? = withContext(Dispatchers.IO) { + suspend fun lookupExpiredWallpaper(settings: Settings): Wallpaper? = withContext(coroutineDispatcher) { + val name = settings.currentWallpaperName if (allAssetsExist(name)) { Wallpaper( name = name, collection = Wallpaper.DefaultCollection, - textColor = null, - cardColor = null, + textColor = settings.currentWallpaperTextColor, + cardColorLight = settings.currentWallpaperCardColorLight, + cardColorDark = settings.currentWallpaperCardColorDark, thumbnailFileState = Wallpaper.ImageFileState.Downloaded, assetsFileState = Wallpaper.ImageFileState.Downloaded, ) @@ -53,8 +57,8 @@ class WallpaperFileManager( /** * Remove all wallpapers that are not the [currentWallpaper] or in [availableWallpapers]. */ - suspend fun clean(currentWallpaper: Wallpaper, availableWallpapers: List) = withContext(Dispatchers.IO) { - scope.launch { + fun clean(currentWallpaper: Wallpaper, availableWallpapers: List) { + CoroutineScope(coroutineDispatcher).launch { val wallpapersToKeep = (listOf(currentWallpaper) + availableWallpapers).map { it.name } wallpapersDirectory.listFiles()?.forEach { file -> if (file.isDirectory && !wallpapersToKeep.contains(file.name)) { @@ -67,7 +71,7 @@ class WallpaperFileManager( /** * Checks whether all the assets for a wallpaper exist on the file system. */ - suspend fun wallpaperImagesExist(wallpaper: Wallpaper): Boolean = withContext(Dispatchers.IO) { - return@withContext allAssetsExist(wallpaper.name) + suspend fun wallpaperImagesExist(wallpaper: Wallpaper): Boolean = withContext(coroutineDispatcher) { + allAssetsExist(wallpaper.name) } } diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperManager.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperManager.kt deleted file mode 100644 index 5d6bef29b..000000000 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperManager.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.fenix.wallpapers - -import mozilla.components.support.base.log.logger.Logger -import org.mozilla.fenix.components.AppStore -import org.mozilla.fenix.utils.Settings - -/** - * Provides access to available wallpapers and manages their states. - */ -@Suppress("TooManyFunctions") -class WallpaperManager( - private val appStore: AppStore, -) { - val logger = Logger("WallpaperManager") - - val wallpapers get() = appStore.state.wallpaperState.availableWallpapers - val currentWallpaper: Wallpaper get() = appStore.state.wallpaperState.currentWallpaper - - companion object { - /** - * Get whether the default wallpaper should be used. - */ - fun isDefaultTheCurrentWallpaper(settings: Settings): Boolean = with(settings.currentWallpaperName) { - return isEmpty() || equals(defaultWallpaper.name) - } - - val defaultWallpaper = Wallpaper.Default - } -} diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperMetadataFetcher.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperMetadataFetcher.kt index 1b04ced95..781773daa 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperMetadataFetcher.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperMetadataFetcher.kt @@ -81,7 +81,8 @@ class WallpaperMetadataFetcher( Wallpaper( name = getString("id"), textColor = getArgbValueAsLong("text-color"), - cardColor = getArgbValueAsLong("card-color"), + cardColorLight = getArgbValueAsLong("card-color-light"), + cardColorDark = getArgbValueAsLong("card-color-dark"), collection = collection, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Unavailable, diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperState.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperState.kt index 4ac633ffd..8e7a584d6 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperState.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperState.kt @@ -4,6 +4,11 @@ package org.mozilla.fenix.wallpapers +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import org.mozilla.fenix.theme.FirefoxTheme + /** * Represents all state related to the Wallpapers feature. * @@ -20,4 +25,44 @@ data class WallpaperState( availableWallpapers = listOf(), ) } + + /** + * Helper property used to obtain the [Color] to fill-in cards in front of a wallpaper. + * + * @return The appropriate light or dark wallpaper card [Color], if available, otherwise a default. + */ + val wallpaperCardColor: Color + @Composable get() = when { + currentWallpaper.cardColorLight != null && currentWallpaper.cardColorDark != null -> { + if (isSystemInDarkTheme()) { + Color(currentWallpaper.cardColorDark) + } else { + Color(currentWallpaper.cardColorLight) + } + } + else -> FirefoxTheme.colors.layer2 + } + + /** + * Run the Composable [run] block only if the current wallpaper's card colors are available. + */ + @Composable + fun composeRunIfWallpaperCardColorsAreAvailable( + run: @Composable (cardColorLight: Color, cardColorDark: Color) -> Unit, + ) { + if (currentWallpaper.cardColorLight != null && currentWallpaper.cardColorDark != null) { + run(Color(currentWallpaper.cardColorLight), Color(currentWallpaper.cardColorDark)) + } + } + + /** + * Run the [run] block only if the current wallpaper's card colors are available. + */ + fun runIfWallpaperCardColorsAreAvailable( + run: (cardColorLight: Int, cardColorDark: Int) -> Unit, + ) { + if (currentWallpaper.cardColorLight != null && currentWallpaper.cardColorDark != null) { + run(currentWallpaper.cardColorLight.toInt(), currentWallpaper.cardColorDark.toInt()) + } + } } diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpapersUseCases.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpapersUseCases.kt index d5c104c7a..4d32e9e2a 100644 --- a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpapersUseCases.kt +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpapersUseCases.kt @@ -16,6 +16,7 @@ import org.mozilla.fenix.FeatureFlags import org.mozilla.fenix.R import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.components.appstate.AppAction +import org.mozilla.fenix.ext.isSystemInDarkTheme import org.mozilla.fenix.ext.settings import org.mozilla.fenix.utils.Settings import java.io.File @@ -25,7 +26,7 @@ import java.util.Date * Contains use cases related to the wallpaper feature. * * @param context Used for various file and configuration checks. - * @param store Will receive dispatches of metadata updates like the currently selected wallpaper. + * @param appStore Will receive dispatches of metadata updates like the currently selected wallpaper. * @param client Handles downloading wallpapers and their metadata. * @param storageRootDirectory The top level app-local storage directory. * @param currentLocale The locale currently being used on the device. @@ -37,7 +38,7 @@ import java.util.Date */ class WallpapersUseCases( context: Context, - store: AppStore, + appStore: AppStore, client: Client, storageRootDirectory: File, currentLocale: String, @@ -53,7 +54,7 @@ class WallpapersUseCases( selectWallpaper::invoke, ) DefaultInitializeWallpaperUseCase( - store = store, + appStore = appStore, downloader = downloader, fileManager = fileManager, metadataFetcher = metadataFetcher, @@ -65,7 +66,7 @@ class WallpapersUseCases( val fileManager = LegacyWallpaperFileManager(storageRootDirectory) val downloader = LegacyWallpaperDownloader(context, client) LegacyInitializeWallpaperUseCase( - store = store, + appStore = appStore, downloader = downloader, fileManager = fileManager, settings = context.settings(), @@ -89,9 +90,9 @@ class WallpapersUseCases( } val selectWallpaper: SelectWallpaperUseCase by lazy { if (FeatureFlags.wallpaperV2Enabled) { - DefaultSelectWallpaperUseCase(context.settings(), store, fileManager, downloader) + DefaultSelectWallpaperUseCase(context.settings(), appStore, fileManager, downloader) } else { - LegacySelectWallpaperUseCase(context.settings(), store) + LegacySelectWallpaperUseCase(context.settings(), appStore) } } @@ -108,7 +109,7 @@ class WallpapersUseCases( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal class LegacyInitializeWallpaperUseCase( - private val store: AppStore, + private val appStore: AppStore, private val downloader: LegacyWallpaperDownloader, private val fileManager: LegacyWallpaperFileManager, private val settings: Settings, @@ -118,7 +119,7 @@ class WallpapersUseCases( /** * Downloads the currently available wallpaper metadata from a remote source. - * Updates the [store] with that metadata and with the selected wallpaper found in storage. + * Updates the [appStore] with that metadata and with the selected wallpaper found in storage. * Removes any unused promotional or time-limited assets from local storage. * Should usually be called early the app's lifetime to ensure that metadata and thumbnails * are available as soon as they are needed. @@ -130,7 +131,7 @@ class WallpapersUseCases( withContext(Dispatchers.IO) { val dispatchedCurrent = Wallpaper.getCurrentWallpaperFromSettings(settings)?.let { // Dispatch this ASAP so the home screen can render. - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(it)) + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(it)) true } ?: false val availableWallpapers = possibleWallpapers.getAvailableWallpapers() @@ -144,9 +145,9 @@ class WallpapersUseCases( possibleWallpapers, ) downloadAllRemoteWallpapers(availableWallpapers) - store.dispatch(AppAction.WallpaperAction.UpdateAvailableWallpapers(availableWallpapers)) + appStore.dispatch(AppAction.WallpaperAction.UpdateAvailableWallpapers(availableWallpapers)) if (!dispatchedCurrent) { - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(currentWallpaper)) + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(currentWallpaper)) } } } @@ -185,7 +186,8 @@ class WallpapersUseCases( name = Wallpaper.amethystName, collection = firefoxClassicCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ), @@ -193,7 +195,8 @@ class WallpapersUseCases( name = Wallpaper.ceruleanName, collection = firefoxClassicCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ), @@ -201,7 +204,8 @@ class WallpapersUseCases( name = Wallpaper.sunriseName, collection = firefoxClassicCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ), @@ -211,7 +215,8 @@ class WallpapersUseCases( name = Wallpaper.twilightHillsName, collection = firefoxClassicCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ), @@ -219,7 +224,8 @@ class WallpapersUseCases( name = Wallpaper.beachVibeName, collection = firefoxClassicCollection, textColor = null, - cardColor = null, + cardColorLight = null, + cardColorDark = null, thumbnailFileState = Wallpaper.ImageFileState.Unavailable, assetsFileState = Wallpaper.ImageFileState.Downloaded, ), @@ -231,7 +237,7 @@ class WallpapersUseCases( @Suppress("LongParameterList") @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal class DefaultInitializeWallpaperUseCase( - private val store: AppStore, + private val appStore: AppStore, private val downloader: WallpaperDownloader, private val fileManager: WallpaperFileManager, private val metadataFetcher: WallpaperMetadataFetcher, @@ -241,8 +247,9 @@ class WallpapersUseCases( ) : InitializeWallpapersUseCase { override suspend fun invoke() { Wallpaper.getCurrentWallpaperFromSettings(settings)?.let { - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(it)) + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(it)) } + val currentWallpaperName = if (settings.shouldMigrateLegacyWallpaper) { val migratedWallpaperName = migrationHelper.migrateLegacyWallpaper(settings.currentWallpaperName) @@ -252,16 +259,21 @@ class WallpapersUseCases( } else { settings.currentWallpaperName } + + if (settings.shouldMigrateLegacyWallpaperCardColors) { + migrationHelper.migrateExpiredWallpaperCardColors() + } + val possibleWallpapers = metadataFetcher.downloadWallpaperList().filter { !it.isExpired() && it.isAvailableInLocale() } val currentWallpaper = possibleWallpapers.find { it.name == currentWallpaperName } - ?: fileManager.lookupExpiredWallpaper(currentWallpaperName) + ?: fileManager.lookupExpiredWallpaper(settings) ?: Wallpaper.Default // Dispatching this early will make it accessible to the home screen ASAP. If it has been // dispatched above, we may still need to update other metadata about it. - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(currentWallpaper)) + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(currentWallpaper)) fileManager.clean( currentWallpaper, @@ -274,7 +286,7 @@ class WallpapersUseCases( } val defaultIncluded = listOf(Wallpaper.Default) + wallpapersWithUpdatedThumbnailState - store.dispatch(AppAction.WallpaperAction.UpdateAvailableWallpapers(defaultIncluded)) + appStore.dispatch(AppAction.WallpaperAction.UpdateAvailableWallpapers(defaultIncluded)) } private fun Wallpaper.isExpired(): Boolean = when (this) { @@ -350,18 +362,13 @@ class WallpapersUseCases( */ private fun Wallpaper.getLocalPathFromContext(context: Context): String { val orientation = if (context.isLandscape()) "landscape" else "portrait" - val theme = if (context.isDark()) "dark" else "light" + val theme = if (context.isSystemInDarkTheme()) "dark" else "light" return Wallpaper.legacyGetLocalPath(orientation, theme, name) } private fun Context.isLandscape(): Boolean { return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE } - - private fun Context.isDark(): Boolean { - return resources.configuration.uiMode and - Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES - } } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @@ -444,18 +451,19 @@ class WallpapersUseCases( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal class LegacySelectWallpaperUseCase( private val settings: Settings, - private val store: AppStore, + private val appStore: AppStore, ) : SelectWallpaperUseCase { /** - * Select a new wallpaper. Storage and the store will be updated appropriately. + * Select a new wallpaper. Storage and the app store will be updated appropriately. * * @param wallpaper The selected wallpaper. */ override suspend fun invoke(wallpaper: Wallpaper): Wallpaper.ImageFileState { settings.currentWallpaperName = wallpaper.name settings.currentWallpaperTextColor = wallpaper.textColor ?: 0 - settings.currentWallpaperCardColor = wallpaper.cardColor ?: 0 - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper)) + settings.currentWallpaperCardColorLight = wallpaper.cardColorLight ?: 0 + settings.currentWallpaperCardColorDark = wallpaper.cardColorDark ?: 0 + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper)) return Wallpaper.ImageFileState.Downloaded } } @@ -463,12 +471,12 @@ class WallpapersUseCases( @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) internal class DefaultSelectWallpaperUseCase( private val settings: Settings, - private val store: AppStore, + private val appStore: AppStore, private val fileManager: WallpaperFileManager, private val downloader: WallpaperDownloader, ) : SelectWallpaperUseCase { /** - * Select a new wallpaper. Storage and the store will be updated appropriately. + * Select a new wallpaper. Storage and the app store will be updated appropriately. * * @param wallpaper The selected wallpaper. */ @@ -492,11 +500,13 @@ class WallpapersUseCases( internal fun selectWallpaper(wallpaper: Wallpaper) { settings.currentWallpaperName = wallpaper.name settings.currentWallpaperTextColor = wallpaper.textColor ?: 0L - store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper)) + settings.currentWallpaperCardColorLight = wallpaper.cardColorLight ?: 0L + settings.currentWallpaperCardColorDark = wallpaper.cardColorDark ?: 0L + appStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper)) } private fun dispatchDownloadState(wallpaper: Wallpaper, downloadState: Wallpaper.ImageFileState) { - store.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(wallpaper, downloadState)) + appStore.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(wallpaper, downloadState)) } } } diff --git a/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt b/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt index a2fb3843e..4656b04d5 100644 --- a/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt +++ b/app/src/main/java/org/mozilla/gecko/search/SearchWidgetProvider.kt @@ -17,7 +17,7 @@ import android.speech.RecognizerIntent import android.view.View import android.widget.RemoteViews import androidx.annotation.Dimension -import androidx.annotation.Dimension.DP +import androidx.annotation.Dimension.Companion.DP import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources import androidx.core.graphics.drawable.toBitmap diff --git a/app/src/main/res/drawable/ic_microphone_widget.xml b/app/src/main/res/drawable/ic_microphone_widget.xml index c3275599b..a12cbdca4 100644 --- a/app/src/main/res/drawable/ic_microphone_widget.xml +++ b/app/src/main/res/drawable/ic_microphone_widget.xml @@ -1,8 +1,16 @@ - - - - + + + + + diff --git a/app/src/main/res/drawable/ic_microphone_widget_padded.xml b/app/src/main/res/drawable/ic_microphone_widget_padded.xml deleted file mode 100644 index 665b13f1b..000000000 --- a/app/src/main/res/drawable/ic_microphone_widget_padded.xml +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/app/src/main/res/layout/fragment_share.xml b/app/src/main/res/layout/fragment_share.xml index edf766367..f7a284739 100644 --- a/app/src/main/res/layout/fragment_share.xml +++ b/app/src/main/res/layout/fragment_share.xml @@ -35,16 +35,16 @@ app:layout_constraintBottom_toBottomOf="parent"> + app:layout_constraintBottom_toTopOf="@id/divider_line" /> + app:layout_constraintTop_toBottomOf="@id/divider_line" /> + + + + diff --git a/app/src/main/res/layout/search_widget_medium.xml b/app/src/main/res/layout/search_widget_medium.xml index c51ff6b61..c564ca044 100644 --- a/app/src/main/res/layout/search_widget_medium.xml +++ b/app/src/main/res/layout/search_widget_medium.xml @@ -39,5 +39,5 @@ android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:layout_marginEnd="1dp" - android:background="@drawable/ic_microphone_widget_padded" /> + android:background="@drawable/ic_microphone_widget" /> diff --git a/app/src/main/res/layout/search_widget_small.xml b/app/src/main/res/layout/search_widget_small.xml index db0531acc..91e19b896 100644 --- a/app/src/main/res/layout/search_widget_small.xml +++ b/app/src/main/res/layout/search_widget_small.xml @@ -3,7 +3,6 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> + android:background="@drawable/ic_microphone_widget" /> diff --git a/app/src/main/res/layout/top_site_item.xml b/app/src/main/res/layout/top_site_item.xml index 33cf36454..fef83a745 100644 --- a/app/src/main/res/layout/top_site_item.xml +++ b/app/src/main/res/layout/top_site_item.xml @@ -2,73 +2,65 @@ - + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/top_sites_item_margin_bottom" + android:orientation="vertical" + android:focusable="true"> + android:id="@+id/favicon_card" + style="@style/TopSite.FaviconCard" + android:importantForAccessibility="noHideDescendants" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="parent"> - - - - - - - - - - + + - + - + - + diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index de5afa496..a5efed042 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -31,8 +31,7 @@ + app:destination="@id/homeOnboardingDialogFragment" /> = 0)))", "startDate": "2022-10-05", - "enrollmentEndDate": "2022-10-29", + "enrollmentEndDate": "2022-11-01", "endDate": null, "proposedDuration": 73, "proposedEnrollment": 24, - "referenceBranch": "control" + "referenceBranch": "control", + "featureValidationOptOut": false } ] } diff --git a/app/src/main/res/values-ast/strings.xml b/app/src/main/res/values-ast/strings.xml index 53644387a..0500ed654 100644 --- a/app/src/main/res/values-ast/strings.xml +++ b/app/src/main/res/values-ast/strings.xml @@ -101,10 +101,6 @@ Llingüeta privada nueva - - %d sitios - Atrás @@ -345,7 +341,7 @@ Marcadores de recién - Pocket + Pocket Fondos de pantalla @@ -524,10 +520,6 @@ En llista En rexáu - - Grupos de busca - - Axunta los sitios rellacionaos Zarru de llingüetes @@ -676,15 +668,6 @@ Nun hai nada - - D\'otros preseos - - Anicia la sesión pa ver l\'historial sincronizáu de los otros preseos de to. - - Aniciar la sesión - - O crea una cuenta de Firefox pa comenzar a sincronizar]]> - Quitáronse les descargues @@ -704,7 +687,7 @@ Perdona mas %1$s nun pue cargar esa páxina. - Unviar un informe del fallu a Mozilla + Unviar un informe del error a Mozilla Zarrar la llingüeta @@ -895,7 +878,7 @@ Usóse apocayá - Aniciar sesión pa sincronizar + Aniciar sesión pa sincronizar Aniciar sesión en Sync @@ -1264,6 +1247,8 @@ en llinia y con nós. Sincronización de cuentes + + Sincronizar les cuentes ente preseos Cuentes guardaes @@ -1339,7 +1324,7 @@ en llinia y con nós. Cífrense los datos - Sincronizar les tarxetes en tolos preseos + Sincronizar les tarxetes ente preseos Sincronizar les tarxetes @@ -1409,7 +1394,7 @@ en llinia y con nós. Comprueba que la cadena de busca concase col formatu del exemplu - Fallu al conectar con «%s» + Prodúxose un error al conectase a «%s» Creóse %s @@ -1517,7 +1502,7 @@ en llinia y con nós. Zarrar - Cola potencia de Pocket. + Cola potencia de Pocket. Parte de la familia de Firefox. %s diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index d4f21551c..cc082f4a6 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -16,6 +16,12 @@ Увядзіце запыт або адрас + + Гісторыя пошуку + + Шукаць у закладках + + Шукаць карткі Увядзіце пошукавыя запыты @@ -40,8 +46,6 @@ - Нядаўнія закладкі - Нядаўна захаваныя Паказаць усе захаваныя закладкі @@ -127,13 +131,6 @@ Кнопка паказу ўсіх нядаўніх картак - - Вынік пошуку \"%1$s\" - - - Сайты: %d Усе сінхранізаваныя карткі @@ -256,38 +253,20 @@ Налады пошуку - - - Што новага ў %1$s - - Цяпер стала прасцей працягнуць працу там, дзе вы спыніліся. - - Персаналізаваная хатняя старонка %1$s - - Пераходзьце да адкрытых картак, закладак і гісторыі аглядання. - - Лепшая арганізацыя картак - - Пазбаўцеся бязладдзя ў картках дзякуючы палепшанаму выкладу і аўтаматычнаму закрыццю картак. - - Нядаўнія пошукі - - Вяртайцеся да сваіх апошнія пошукавых запытаў з хатняй старонкі і картак. - - - Ваша персаналізаваная галоўная старонка Firefox цяпер палягчае працяг адтуль, дзе вы спыніліся. Знайдзіце свае апошнія карткі, закладкі і вынікі пошуку. + + Гэтым разам шукаць: + + Гэтым разам шукаць у: + + Сустракайце сваю персаналізаваную хатнюю старонку. Тут будуць паказаны апошнія карткі, закладкі і вынікі пошуку. - Сардэчна запрашаем у незалежны Інтэрнэт - Сардэчна запрашаем у больш асабісты Інтэрнэт Больш колераў. Лепшая прыватнасць. Тая ж адданасць людзям, а не прыбытку. - Пераходзьце з тэлефона на ноўтбук і назад - Пераключаць экраны цяпер прасцей, чым калі-небудзь Працягвайце з таго месца, дзе спыніліся, з дапамогай картак з іншых прылад, якія зараз знаходзяцца на вашай хатняй старонцы. @@ -301,6 +280,9 @@ Вашыя карткі сінхранізуюцца! Працягвайце з таго месца, дзе спыніліся на іншай прыладзе. + + Закрыць + Адкрыць новую картку %1$s @@ -349,6 +331,14 @@ Дадаць ярлык прыватнага аглядання Рэжым «Толькі HTTPS» + + + Памяншэнне колькасці банераў кукі + + Памяншаць колькасць банераў кукі + + Firefox аўтаматычна спрабуе адхіліць запыты кукаў на банерах файлаў cookie. Калі выбар адхілення недаступны, Firefox можа прыняць усе кукі, каб закрыць банер. + Аўтаматычна спрабуе падключацца да сайтаў з выкарыстаннем пратаколу шыфравання HTTPS для павышэння бяспекі. @@ -378,7 +368,7 @@ Уліковы запіс - Паліца прылад + Паліца інструментаў Тэма @@ -456,8 +446,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Нядаўна наведаныя - Pocket + Pocket + + Гісторыі, якія прымушаюць задумацца + + Артыкулы ад %s Артыкулы ад спонсараў @@ -482,12 +476,6 @@ Не ўдалося змяніць шпалеры Падрабязней - - Змяняць шпалеры дотыкам да лагатыпа хатняй старонкі Firefox - - - Лагатып Firefox — змяніць шпалеры, кнопка Класічны %s @@ -646,6 +634,17 @@ Закрыць + + Адкрыць %d картак? + + Адкрыццё такой колькасці картак можа запаволіць %s падчас загрузкі старонак. Вы сапраўды хочаце гэта зрабіць? + + Адкрыць карткі + + Скасаваць + %d сайт @@ -675,10 +674,6 @@ Спіс Сетка - - Пошукавыя групы - - Групуйце звязаныя сайты разам Закрываць карткі @@ -831,18 +826,6 @@ Няма гісторыі - - Сінхранавана з іншых прылад - - З іншых прылад - - - Увайдзіце, каб убачыць гісторыю, сінхранізаваную з іншых вашых прылад. - - Увайсці - - Або стварыць уліковы запіс Firefox, каб пачаць сінхранізацыю]]> - Сцягванні выдалены @@ -893,6 +876,10 @@ Адкрыць у новай картцы Адкрыць у прыватнай картцы + + Адкрыць усё ў новых картках + + Адкрыць усё ў прыватных картках Выдаліць @@ -1072,6 +1059,10 @@ Падзяліцца + + Захаваць як PDF + + Немагчыма стварыць PDF Даслаць на прыладу @@ -1083,9 +1074,11 @@ Скапіявана ў буфер абмену - Увайсці ў сінхранізацыю + Увайсці ў сінхранізацыю Увайсці ў сінхранізацыю + + Сінхранізаваць і захаваць дадзеныя Даслаць на ўсе прылады @@ -1124,6 +1117,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Зрабіце %1$s сваім прадвызначаным браўзерам + + Паспрабуйце Прыватнае агляданне + + + Праглядайце без захаваных файлаў кукі або гісторыі ў %1$s + Калекцыя выдалена @@ -1250,33 +1250,20 @@ Група выдалена - - Вітаем у %s! Сардэчна запрашаем у лепшы Інтэрнэт Браўзер, створаны для людзей, а не для прыбытку. - - Сінхранізуйце Firefox паміж прыладамі Працягвайце з таго месца, дзе спыніліся - - Перанясіце закладкі, гісторыю і паролі ў %1$s на гэтай прыладзе. Сінхранізуйце карткі і паролі на ўсіх прыладах для лёгкага пераключэння экрана. - - Зарэгістравацца Увайсці Сінхранізацыя ўключана - - Прыватнасць заўжды ўключана Прадвызначаная ахова прыватнасці - - %1$s аўтаматычна спыняе таемнае сачэнне кампаній за вамі ў Інтэрнэце. Поўная ахова кукаў перашкаджае трэкерам выкарыстоўваць файлы кукі для сачэння за вамі на розных сайтах. @@ -1289,17 +1276,10 @@ Блакуе больш трэкераў, так што старонкі атрымліваюцца хутчэй, але частка іх функцый можа парушыцца. Выберыце размяшчэнне панэлі інструментаў - - Майце панэль інструментаў пад рукой. Пакіньце яе ўнізе або перамясціце ўверх. Пакіньце яе ўнізе або перамясціце наверх. - - Ваша прыватнасць Вы распараджаецеся сваімі звесткамі - - Мы распрацавалі %s, каб даць вам кантроль над тым, чым дзяліцца ў Інтэрнэце, і тым, чым вы падзеліцеся з намі. Firefox дае вам кантроль над тым, чым вы дзеліцеся ў Інтэрнэце і чым вы дзеліцеся з намі. @@ -1866,7 +1846,7 @@ Падключыць іншую прыладу. - Калі ласка, аўтарызуйцеся яшчэ раз. + Паўтарыце аўтэнтыфікацыю. Калі ласка, уключыце сінхранізацыю картак. @@ -1933,7 +1913,7 @@ Аўтазакрыццё ўключана - Наладзьце аўтаматычна адкрываць спасылкі з сайтаў, пошты і паведамленняў у Firefox. + Наладзьце аўтаматычнае адкрыццё спасылак з сайтаў, пошты і паведамленняў у Firefox. Выдаліць @@ -1955,7 +1935,9 @@ Даведайцеся больш - Працуе на Pocket. + Працуе на Pocket. + + Пры падтрымцы %s. Частка сямейства Firefox. %s @@ -1969,4 +1951,14 @@ Перайсці ў налады Прапановы Firefox + + + + згарнуць + + разгарнуць + + адкрыйце спасылку, каб даведацца больш аб гэтай калекцыі + + прачытаць артыкул diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index e124f178d..f88da4021 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -14,6 +14,12 @@ Diweredekaat ar Merdeiñ Prevez Klask pe chomlecʼh + + Klask er roll istor + + Klask er sinedoù + + Klask en ivinelloù Skrivit gerioù ar c’hlask @@ -40,6 +46,8 @@ Sinedoù nevez + + Enrollet nevez ’zo Diskouez an holl sinedoù enrollet @@ -73,6 +81,15 @@ Argas + + Argas + + + + Hor c’heweriuster prevezded araoketañ betek-hen a lak an heulierien a-gostez. + + Gouzout hiroc’h a-zivout ar gwarez toupinoù hollek + Ezhomm a zo haeziñ ar c’hamera. Kit e Arventennoù Android, stokit war an aotreoù ha stokit war aotren. @@ -118,17 +135,13 @@ Diskouez an holl afelloù ivinelloù nevez - - Ho klask evit \"%1$s\" - - Lec’hiennoù %d Gwelout an holl ivinelloù goubredet Trevnad goubredet + + Dilemel Dilemel @@ -242,6 +255,9 @@ Arventennoù ar c’hlask + + Ar wech-mañ klaskit: + Petra zo nevez e %1$s @@ -264,6 +280,31 @@ Gant ho pajenn Firefox personelaet eo aesoc’h da adstagañ lec’h m’ho peus paouezet. Klaskit e-touez hoc’h ivinelloù nevez, sinedoù ha disoc’hoù enklask. + + Kejit gant ho pajenn degemer personelaet. Ivinelloù nevez, sinedoù ha disoc’hoù enklask a vo diskouezet amañ. + + Donemat war un internet dizalc’h + + Donemat war un internet personeloc’h + + Muioc’h a livioù, muioc’h a brevezded. An hevelep youl da lakaat an dud a-raok ar gounidoù. + + Tremenit deus ar pellgomz d’an urzhiataer hezoug hag ar c’hontrefed + + Cheñch skrammoù a zo aesoc’h c’hoazh bremañ + + Adkemerit an traoù e lec’h m’ho poa laosket anezho war un trevnad all, dre ho pajenn degemer. + + Kregiñ ganti + + Kennaskañ + + Tremen + + Goubredet eo hoc’h ivinelloù! Tapit an traoù en-dro lec’h m’ho peus laosket anezho e lec’h all. + + Serriñ + Digeriñ en un ivinell %1$s nevez @@ -419,8 +460,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Gweladennet nevez ’zo - Pocket + Pocket + + Boued spered + + Pennadoù kinniget gant %s Istorioù paeroniet @@ -435,11 +480,20 @@ Drekleur hizivaet! Gwelout - - Kemmit an drekleur en ur stekiñ ouzh arlun pajenn degemer Firefox - - Arlun Firefox - kemmañ an drekleur, afell + + + N’haller ket pellgargañ an drekleur + + Klask en-dro + + N’haller ket kemmañ an drekleur + + Gouzout hiroc’h + + %s klasel + + + Embannadur bevennet @@ -582,6 +636,14 @@ Serriñ + + Digeriñ %d a ivinelloù? + + Digeriñ ivinelloù + + Nullañ + Lec’hienn %d @@ -611,10 +673,6 @@ Roll Grid - - Klask er strolladoù - - Strollañ al lec’hiennoù heñvel Serriñ an ivinelloù @@ -764,16 +822,6 @@ Roll istor ebet amañ - - Goubredet gant trevnadoù all - - Diwar trevnadoù all - - Kennaskañ - - - Pe grouit ur gont Firefox evit kregiñ gant ar c’houbredañ]]> - Pellgargadurioù dilammet @@ -823,6 +871,8 @@ Digeriñ en un ivinell nevez Digeriñ war un ivinell brevez + + Digeriñ an holl en ivinelloù nevez Dilemel @@ -1010,10 +1060,10 @@ Eilet er golver - Kennaskañ evit goubredañ + Kennaskañ evit goubredañ Kennaskañ ouzh Sync - + Kas dʼan holl drevnadoù Adkennaskañ da Sync @@ -1807,7 +1857,7 @@ Dizoloiñ muioc’h - Galloudekaet gant Pocket. + Galloudekaet gant Pocket. Ezel eus familh Firefox. %s @@ -1821,4 +1871,5 @@ Mont d’an arventennoù Firefox a ginnig - + + diff --git a/app/src/main/res/values-co/strings.xml b/app/src/main/res/values-co/strings.xml index dba74f647..afbe4a2d1 100644 --- a/app/src/main/res/values-co/strings.xml +++ b/app/src/main/res/values-co/strings.xml @@ -15,6 +15,12 @@ Disattivà a navigazione privata Ricerca o indirizzu + + Ricercà in a cronolugia + + Ricercà in l’indette + + Ricercà in l’unghjette Stampittate i termini à ricercà @@ -41,8 +47,6 @@ - Indette recente - Arregistrate pocu fà Affissà tutte l’indette arregistrate @@ -133,13 +137,6 @@ Buttone per affissà tutte l’indette recente - - A vostra ricerca di « %1$s » - - - %d siti Vede tutte l’unghjette sincrunizate @@ -260,39 +257,20 @@ Preferenze di ricerca - - - Ciò chì hè novu in %1$s - - Ora hè più faciule di rivene induve vo avete piantatu. - - Pagina d’accolta persunalizata di %1$s - - Saltà à e vostre unghjette aperte, à l’indette è à a cronolugia di navigazione. - - Unghjette chjare è organizate - - - Sbarazzà l’unghjette cù un accunciamentu più chjaru è a so chjusura autumatica. - - Ricerche recente - - Fighjate torna l’ultime ricerche da a vostra pagina d’accolta è e vostre unghjette. - - - A vostra pagina d’accolta Firefox persunalizata vi permette avà di rivene d’una manera faciule induve vo avete lasciatu. Ci truverete l’unghjette, l’indette, è i risultati di ricerca recente. + + Sta volta, ricercà cù : + + Sta volta, ricercà cù : + + Fate cunnuscenza cù a vostra pagina d’accolta. L’unghjette, l’indette è i risultati di riceca recente ci si trovanu. - Benvenuta in un Internet indipendente - Benvenuta in un Internet più persunale Più di culori. Una cunfidenzialità amendata. È u listessu impegnu per a ghjente piuttostu chè per i soldi. - Passate da u telefonu à l’urdinatore purtavule è vice versa - Passà d’un screnu à l’altru hè più faciule chè mai Ripigliate induve vi site piantati cù l’unghjette d’altri apparechji chì si trovanu avà nant’à a vostra pagina d’accolta. @@ -306,6 +284,9 @@ E vostre unghjette sò sincrunizate ! Ripigliate induve vi site piantati nant’à u vostru altru apparechju. + + Chjode + Apre una nova unghjetta in %1$s @@ -356,6 +337,15 @@ Aghjunghje un accurtatoghju per a navigazione privata Modu solu HTTPS + + + Riduzzione di e striscie di cannistrelli + + Riduce e striscie di canistrelli + + + Firefox prova autumaticamente di righjittà e dumande di canistrelli quandu ci hè striscie di canistrelli. S’è alcuna ozzione di righjettu ùn hè micca dispunibule, Firefox pò accettà tutti i canistrelli per chjode a striscia. + Tentativu autumaticu di cunnessione à i siti impieghendu u protocollu di cifratura HTTPS per aumentà a sicurità. @@ -465,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitati pocu fà - Pocket + Pocket + + Storie chì facenu riflette + + Articuli selezziunati da %s Articuli finanziati @@ -490,11 +484,6 @@ Impussibule di cambià u sfondulu di screnu Sapene di più - - Cambià u sfondulu di screnu picchichjendu u logo di a pagina d’accolta - - Logo Firefox - cambià u sfondulu di screnu, buttone %s classicu @@ -654,6 +643,17 @@ Chjode + + Apre %d unghjette ? + + L’apertura di tante unghjette pò rallentà %s durante u caricamentu di e pagine. Vulete veramente cuntinuà ? + + Apre l’unghjette + + Abbandunà + %d situ @@ -684,10 +684,6 @@ Lista Quadrittere - - Gruppi di ricerca - - Raggruppà i siti assuciati Chjode l’unghjette @@ -839,18 +835,6 @@ Alcuna cronolugia - - Sincrunizati nant’à d’altri apparechji - - Da d’altri apparechji - - - Cunnittitevi per affissà a cronolugia sincrunizata da i vostri altri apparechji. - - Cunnettesi - - O creà un contu Firefox per lancià a sincrunizazione]]> - Scaricamenti cacciati @@ -900,6 +884,10 @@ Apre in una nova unghjetta Apre in un’unghjetta privata + + Tuttu apre in unghjette nove + + Tuttu apre in unghjette private Squassà @@ -1080,6 +1068,10 @@ Sparte + + Arregistrà cum’è PDF + + Impussibule d’ingenerà un PDF Mandà à l’apparechju @@ -1091,9 +1083,11 @@ Cupiatu in u preme’papei - Cunnettesi per sincrunizà + Cunnettesi per sincrunizà Cunnettesi à Sync + + Sincrunizà è arregistrà i dati Mandà à tutti l’apparechji @@ -1129,6 +1123,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Impiegate %1$s cum’è navigatore predefinitu + + Pruvà a navigazione privata + + Navigate senza arregistrà nè canistrelli nè cronolugia in %1$s + Cullezzione squassata @@ -1249,33 +1249,20 @@ Gruppu squassatu - - Benvenuta in %s ! Benvenuta in un Internet più bellu Un navigatore cuncepitu per a ghjente, micca per i prufiti. - - Sincrunizate Firefox trà i vostri apparechji Ripigliate induve vi site piantati - - Impurtate e vostre indette, cronolugia è parolle d’intesa in %1$s nant’à st’apparechju. Sincrunizate l’unghjette è e parolle d’intesa trà i vostri apparechji per passà d’un screnu à l’altru senza straziu. - - Arregistrassi Cunnettesi Sincrunizazione attivata - - Cunfidenzialità sempre attiva Prutezzione attiva di a vita privata - - %1$s impedisce autumaticamente l’imprese di seguitavvi da manera sicreta nant’à u Web. A funzione di prutezzione tutale contr’à i canistrelli permette d’impedisce l’elementi di spiunagiu d’impiegà i canistrelli per seguitavvi d’un situ à l’altru. @@ -1288,17 +1275,10 @@ Bluccheghja più di perseguitatori è cusì e pagine si caricanu piu prestu, ma certi siti puderianu ùn micca funziunà currettamente. Sceglie a pusizione di a vostra barra d’attrezzi - - Piazzate a barra d’attrezzi à purtata di manu. Lasciatela quaghjò o dispiazzatela quassù. Lasciatela quaghjò o dispiazzatela quassù. - - A vostra vita privata Gardate u cuntrollu di i vostri dati - - Avemu cuncepitu %s per davvi u cuntrollu nant’à ciò chì vò spartite in linea è nant’à ciò chì vò spartite cù noi. Firefox vi dà u cuntrollu nant’à ciò chì vò spartite in linea è nant’à ciò chì vò spartite cù noi. @@ -1942,7 +1922,9 @@ Scoprene di più - Funziuneghja grazia à Pocket. + Funziuneghja grazia à Pocket. + + Funziuneghja grazia à %s. Parte di a famiglia Firefox. %s @@ -1956,4 +1938,14 @@ Andà à e preferenze Firefox suggerisce + + + + riduce + + allargà + + apre u liame per sapene di più nant’à sta cullezzione + + leghje l’articulu diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index aa4b4604f..4dd39aa12 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -16,6 +16,12 @@ Zakáže režim anonymního prohlížení Zadejte hledání nebo adresu + + Hledat v historii + + Hledat v záložkách + + Hledat panely Zadejte hledaný výraz @@ -41,7 +47,7 @@ - Naposledy přidané + Naposledy uložené Zobrazit všechny uložené záložky @@ -78,6 +84,9 @@ Zavřít + + Zjistit více o úplné ochraně před cookies + Pro tuto funkci je potřeba povolit přístup k fotoaparátu. Ten můžete povolit v nastavení oprávnění aplikací v systému Android. @@ -123,12 +132,6 @@ Tlačítko pro zobrazení všech nedávných panelů - - Vaše vyhledávání „%1$s“ - - Stránek: %d Zobrazit synchronizované panely @@ -253,26 +256,14 @@ Nastavení vyhledávání - - - Co je v aplikaci %1$s nového - - Jednoduše pokračujte, kde jste dříve skončili. - - Osobní domovská stránka aplikace %1$s - - Rychlý přístup k otevřeným panelům, vašim záložkám i historii. - - Úhledně srovnané panely - - Vylepšené zobrazení nebo automatické zavírání vás zbaví nepořádku v panelech. - - Nedávno vyhledávané - - Na domovské stránce najdete, co jste nedávno hledali. - - - Na své osobní domovské stránce Firefoxu vždy najdete, co jste dělali naposledy, ať už nedávno otevřené panely, záložky nebo výsledky vyhledávání. + + Začít + + Přihlásit se + + Přeskočit + + Zavřít @@ -323,6 +314,7 @@ Vytvořit zkratku pro anonymní prohlížení Režim „pouze HTTPS“ + Pro zvýšení zabezpečení se automaticky pokusí připojit k webům pomocí šifrovacího protokolu HTTPS. @@ -362,8 +354,6 @@ Přizpůsobení - S účtem Firefoxu můžete synchronizovat záložky, historii i další svá data - Pro synchronizaci svých panelů, záložek, hesel a dalších věcí se přihlaste. Účet Firefoxu @@ -432,8 +422,10 @@ a section where users see a list of tabs that they have visited in the past few days --> Nedávno navštívené - Pocket + Pocket + + Podnětné články Sponzorované články @@ -449,11 +441,16 @@ Zobrazit - - Klepnutím na logo Firefoxu na domovské stránce změnit tapetu - - Logo Firefox - klepnutím změní tapetu, tlačítko + + Zkusit znovu + + Zjistit více + + Limitovaná edice + + Zkuste barevný nádech + + Podívejte se na další tapety @@ -538,8 +535,6 @@ Povolí Mozille instalovat a spouštět studie. - - Zapnout synchronizaci Synchronizujte a ukládejte svá data @@ -600,6 +595,14 @@ Zavřít + + Otevřít %d panelů? + + Otevřít panely + + Zrušit + Jedna stránka @@ -629,10 +632,6 @@ Seznam Mřížka - - Seskupené panely vyhledávání - - Seskupí související stránky Zavírat panely @@ -738,8 +737,6 @@ Otevřít nabídku panelů Uložit panely do sbírky - - Nabídka panelů @@ -764,9 +761,6 @@ %1$s (anonymní režim) - - Další panely - Zadejte hledané výrazy @@ -795,18 +789,6 @@ Zatím nemáte žádnou historii prohlížení - - Synchronizované z jiného zařízení - - Z jiných zařízení - - - Pro zobrazení historie prohlížení z vašich ostatních zařízení se prosím přihlaste. - - Přihlásit se - - Nebo si vytvořte účet Firefox a začněte synchronizovat]]> - Stažené soubory smazány @@ -856,6 +838,10 @@ Otevřít v novém panelu Otevřít v anonymním panelu + + Otevřít vše v nových panelech + + Otevřít vše v anonymních panelech Odstranit @@ -1036,6 +1022,8 @@ Sdílet + + Uložit jako PDF Poslat do zařízení @@ -1047,9 +1035,11 @@ Zkopírováno do schránky - Přihlásit se k synchronizaci + Přihlásit se k synchronizaci Přihlásit ke službě Sync + + Synchronizace a ukládání dat Poslat do všech zařízení @@ -1177,8 +1167,6 @@ Ukončit - - Opravdu chcete smazat všechna soukromá data? Časové období mazání @@ -1203,22 +1191,14 @@ Zrušit - - - Vítá vás %s - - Synchronizace Firefoxu mezi zařízeními - - Přeneste si své záložky, historii a hesla do aplikace %1$s i na tomto zařízení. - - Přihlásit se + + Prohlížeč postavený pro lidi, ne pro peníze. + + Přihlásit se Synchronizace je zapnutá - - Soukromí pro vás a napořád - - %1$s automaticky zabrání společnostem v tajném sledování vašeho prohlížení webu. + + Ochrana soukromí již ve výchozím nastavení Standardní (výchozí) @@ -1229,13 +1209,8 @@ Blokuje více sledovacích prvků. Zrychlí i načítání stránek, ale může omezit jejich fungování. Vyberte si umístění nástrojové lišty - - Nastavte si umístění nástrojové lišty na obrazovce dole nebo nahoře, ať na ni dosáhnete. - - Vaše soukromí - - %s vám dává kontrolu nad tím, co sdílíte online a co sdílíte s námi. + + Firefox vám dává kontrolu nad tím, co sdílíte online a co sdílíte s námi. Přečíst zásady ochrany osobních údajů @@ -1347,6 +1322,8 @@ Omezuje možnosti sociálních sítí sledovat vaše aktivity napříč internetem. Sledovací cookies + + Cross-site cookies Blokuje cookies, které používají reklamní sítě a firmy ke sběru informací z mnoha serverů na internetu. @@ -1856,7 +1833,7 @@ Objevte více - Službu poskytuje Pocket. + Službu poskytuje Pocket. Součást rodiny Firefoxu. %s @@ -1870,4 +1847,14 @@ Přejít do nastavení Návrhy od Firefoxu + + + + sbalit + + rozbalit + + otevřít odkaz a zjistit více o této sbírce + + přečíst článek diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml index eada27a7d..1afabdf70 100644 --- a/app/src/main/res/values-cy/strings.xml +++ b/app/src/main/res/values-cy/strings.xml @@ -14,6 +14,12 @@ Analluogi pori preifat Chwilio neu gyfeiriad gwe + + Hanes chwilio + + Chwilio’r nodau tudalen + + Chwilio’r tabiau Rhowch dermau chwilio @@ -40,8 +46,6 @@ - Nodau tudalen diweddar - Cadwyd yn ddiweddar Dangos pob nod tudalen wedi’u cadw @@ -130,13 +134,6 @@ Dangos botwm bob tab diweddar - - Eich chwilio am \"%1$s\" - - - %d gwefan Gweld pob tab wedi’i gydweddu @@ -257,38 +254,20 @@ Gosodiadau chwilio - - - Beth sy’n newydd yn %1$s - - Mae nawr yn haws ailgychwyn o’r lle y gwnaethoch chi adael. - - Tudalen cartref personoledig %1$s - - Symudwch i’ch tabiau agored, nodau tudalen, a’ch hanes pori. - - Tabiau glân, trefnus - - Cliriwch annibendod tabiau gyda gwell cynllun a thabiau cau awtomatig. - - Chwilio diweddar - - Ailedrych ar eich chwilio diweddaraf o’ch tudalen cartref a’ch tabiau. - - - Mae eich cartref personoledig Firefox bellach yn ei gwneud hi’n haws i fynd yn ôl i le wnaethoch chi adael. Dewch o hyd i’ch tabiau, nodau tudalen a’ch canlyniadau chwilio diweddar. + + Chwiliad y tro yma: + + Y tro hwn chwiliwch yn: + + Dyma’ch gwefan cartref personol. Bydd tabiau diweddar, nodau tudalen, a chanlyniadau chwilio yn ymddangos yma. - Croeso i ryngrwyd annibynnol - Croeso i rhyngrwyd mwy personol Rhagor o liwiau. Gwell preifatrwydd. Yr un ymrwymiad i bobl ac nid elw. - Ewch o’r ffôn i’r gliniadur ac yn ôl - Mae newid sgriniau yn haws nag erioed Ewch ymlaen o’r lle roeddech chi nawr gyda thabiau o ddyfeisiau eraill ar eich tudalen cartref. @@ -301,6 +280,9 @@ Mae eich tabiau’n cydweddu! Ewch ymlaen o’r lle roeddech chi ar eich dyfais arall. + + Cau + Agor tab %1$s newydd @@ -351,6 +333,14 @@ Ychwanegu llwybr byr pori preifat Modd HTTPS-yn-Unig + + + Gostyngiad Baner Cwcis + + Lleihau baneri cwcis + + Mae Firefox yn ceisio gwrthod ceisiadau cwcis ar faneri cwcisyn awtomatig. Os nad oes dewis gwrthod ar gael, gall Firefox dderbyn pob cwci er mwyn cau’r faner. + Yn ceisio cysylltu’n awtomatig â gwefannau gan ddefnyddio’r protocol amgryptio HTTPS am fwy o ddiogelwch. @@ -390,8 +380,6 @@ Cyfaddasu - Cydweddu nodau tudalen, hanes, a mwy gyda’ch Cyfrif Firefox - Mewngofnodwch i gydweddu tabiau, nodau tudalen, cyfrineiriau, a rhagor. Cyfrif Firefox @@ -460,8 +448,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Ymwelwyd yn ddiweddar - Pocket + Pocket + + Straeon sy’n procio’r meddwl + + Erthyglau wedi’u pweru gan %s Straeon wedi’u noddi @@ -484,12 +476,6 @@ Methu newid papur wal Dysgu rhagor - - Newidiwch y papur wal trwy dapio logo tudalen hafan Firefox - - - Logo Firefox - newid y papur wal, pwyso’r botwm %s clasurol @@ -586,8 +572,6 @@ Yn caniatáu i Mozilla osod a rhedeg astudiaethau - - Cychwyn Sync Cydweddu a chadw eich data @@ -647,6 +631,17 @@ Cau + + Agor %d tab? + + Gall agor y nifer yma o dabiau arafu %s tra bod y tudalennau’n llwytho. Ydych chi’n siŵr eich bod am barhau? + + Agor tabiau + + Diddymu + %d gwefan @@ -676,10 +671,6 @@ Rhestr Grid - - Chwilio grwpiau - - Casglu gwefannau cysylltiedig ynghyd Cau tabiau @@ -805,9 +796,6 @@ %1$s (Modd Preifat) - - Tabiau eraill - Rhowch gair chwilio @@ -835,18 +823,6 @@ Dim hanes yma - - Cydweddwyd o ddyfeisiau eraill - - O ddyfeisiau eraill - - - Mewngofnodwch i weld hanes wedi’i gydweddu o’ch dyfeisiau eraill. - - Mewngofnodi - - Neu creu cyfrif Firefox i ddechrau cydweddu]]> - Llwythi Wedi’u Tynnu @@ -897,6 +873,10 @@ Agor mewn tab newydd Agor mewn tab preifat + + Agor y cyfan mewn tabiau newydd + + Agor y cyfan mewn tabiau preifat Dileu @@ -1074,6 +1054,10 @@ Rhannu + + Cadw fel PDF + + Methu cynhyrchu PDF Anfon i ddyfais @@ -1085,9 +1069,11 @@ Copïwyd i’r clipfwrdd - Mewngofnodi i gydweddu + Mewngofnodi i gydweddu Mewngofnodi i Sync + + Cydweddu a chadw data Anfon at bob dyfais @@ -1212,8 +1198,6 @@ Gadael - - Bydd hyn yn dileu’ch holl ddata pori. Ystod amser i’w ddileu @@ -1246,34 +1230,21 @@ Dilëwyd y grŵp - - Croeso i %s! Croeso i rhyngrwyd gwell Porwr a adeiladwyd ar gyfer pobl, nid elw. - - Cydweddu Firefox rhwng dyfeisiau Parhau lle roeddech o’r blaen - - Dewch â nodau tudalen, hanes, a chyfrineiriau i %1$s ar y ddyfais hon. Cydweddu tabiau a chyfrineiriau ar draws dyfeisiau ar gyfer newid sgriniau di-dor. - - Ymuno Mewngofnodi Mae Sync ymlaen - - Preifatrwydd parhaus Diogelu preifatrwydd drwy ragosodiad - - Mae %1$s yn atal cwmnïau rhag eich dilyn yn gyfrinachol o amgylch y we, yn awtomatig. Yn cynnwys Diogelwch Cwcis Llwyr i atal tracwyr rhag defnyddio cwcis i’ch stelcian ar draws gwefannau. @@ -1286,18 +1257,10 @@ Yn rhwystro mwy o dracwyr fel bod tudalennau’n llwytho’n gyflymach, ond gall dorri rhai swyddogaethau ar y dudalen. Dewiswch leoliad eich bar offer - - Rhowch y bar offer o fewn cyrraedd hawdd. Cadwch ef ar y gwaelod, neu ei symud i’r brig. Ei gadw ar y gwaelod, neu ei symud i’r brig. - - Eich preifatrwydd Chi sy’n rheoli eich data - - Rydym wedi cynllunio %s i roi rheolaeth i chi dros yr hyn rydych chi’n ei rannu ar-lein a’r hyn rydych chi’n ei rannu gyda ni. -     Mae Firefox yn rhoi rheolaeth i chi dros yr hyn rydych chi’n ei rannu ar-lein a’r hyn rydych chi’n ei rannu gyda ni. @@ -1934,7 +1897,9 @@ Darganfod rhagor - Wedi’i bweru gan Pocket. + Wedi’i bweru gan Pocket. + + Wedi’i bweru gan %s. Rhan o deulu Firefox. %s @@ -1948,4 +1913,14 @@ Mynd i gosodiadau Awgrymiadau Firefox + + + + cau + + ehangu + + agorwch y ddolen i ddysgu rhagor am y casgliad hwn + + darllen yr erthygl diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 5e1da0ecc..ba36c814d 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -14,6 +14,12 @@ Deaktiver privat browsing Søg eller indtast adresse + + Søg i historik + + Søg i bogmærker + + Søg i faneblade Indtast søgestrenge @@ -41,8 +47,6 @@ - Seneste bogmærker - Gemt for nylig Vis alle gemte bogmærker @@ -130,13 +134,6 @@ Knap til visning af alle seneste faneblade - - Din søgning efter \"%1$s\" - - - %d websteder Vis alle synkroniserede faneblade @@ -257,38 +254,20 @@ Søgeindstillinger - - - Nyheder i %1$s - - Det er blevet lettere at fortsætte, hvor du slap. - - Tilpasset startside i %1$s - - Hop til dine åbne faneblade, bogmærker og browserhistorik. - - Overskuelige faneblade - - Fjern distraherende faneblade med forbedret layout og automatisk lukning af faneblade. - - Seneste søgninger - - Besøg dine seneste søgninger igen fra din startside og faneblade. - - - Din personlige startside i Firefox gør det nu lettere at fortsætte, hvor du slap. Find dine seneste faneblade, bogmærker og søgeresultater. + + Søg denne gang med: + + Søg denne gang i: + + Mød din tilpassede startside. Seneste faneblade, bogmærker og søgeresultater vises her. - Velkommen til et uafhængigt internet - Velkommen til et mere personligt internet Flere farver. Bedre beskyttelse af dit privatliv. Samme forpligtelse til mennesker frem for profit. - Hop fra telefonen til computeren og tilbage - Det er nemmere end nogensinde før at skifte mellem skærme Fortsæt hvor du slap med faneblade fra andre enheder - nu på din startside. @@ -301,6 +280,9 @@ Dine faneblade synkroniseres! Fortsæt, hvor du slap, på din anden enhed. + + Luk + Åbn et nyt %1$s-faneblad @@ -350,6 +332,12 @@ Tilføj genvej til privat browsing Tilstanden Kun-HTTPS + + + Reduktion af cookie-bannere + + Reducer cookie-bannere + Forsøger automatisk at oprette forbindelse til websteder ved hjælp af krypteringsprotokollen HTTPS for øget sikkerhed. @@ -456,8 +444,12 @@ Besøgt for nylig - Pocket + Pocket + + Tankevækkende historier + + Artikler leveret af %s Sponsorerede historier @@ -480,12 +472,6 @@ Kunne ikke ændre baggrund Læs mere - - Skift baggrund ved at trykke på Firefox-logoet på startsiden - - - Firefox-logo - skift baggrund, knap Klassisk %s @@ -642,6 +628,17 @@ Luk + + Åbn %d faneblade? + + Åbning af så mange faneblade kan gøre %s langsommere, mens siderne indlæses. Er du sikker på, at du vil fortsætte? + + Åbn faneblade + + Annuller + %d websted @@ -671,10 +668,6 @@ Liste Gitter - - Søgegrupper - - Gruppér relaterede websteder Luk faneblade @@ -824,18 +817,6 @@ Ingen historik - - Synkroniseret fra andre enheder - - Fra andre enheder - - - Log ind for at se historik synkroniseret fra dine andre enheder. - - Log ind - - Eller opret en Firefox-konto for at starte synkroniseringen]]> - Filhentninger fjernet @@ -885,6 +866,10 @@ Åbn i nyt faneblad Åbn i privat faneblad + + Åbn alle i nye faneblade + + Åbn alle i private faneblade Slet @@ -1061,6 +1046,10 @@ Del + + Gem som PDF + + Kan ikke generere PDF-fil Send til enhed @@ -1072,9 +1061,11 @@ Kopieret til udklipsholder - Log ind for at synkronisere + Log ind for at synkronisere Log ind på Sync + + Synkroniser og gem data Send til alle enheder @@ -1231,34 +1222,20 @@ Gruppe slettet - - Velkommen til %s! - Velkommen til et bedre internet En browser lavet for mennesker, ikke profit. - - Synkroniser Firefox mellem enheder Fortsæt hvor du slap - - Synkroniser bogmærker, historik og adgangskoder med %1$s på denne enhed. Synkroniser faneblade og adgangskoder på tværs af enheder for problemfri skift mellem skærme. - - Tilmeld dig Log ind Synkronisering er slået til - - Altid aktiveret privatlivsbeskyttelse Privatlivsbeskyttelse som standard - - %1$s forhindrer automatisk virksomheder i at følge dig i smug på nettet. Med Komplet Cookiebeskyttelse, der forhindrer sporings-tjenester i at følge dig på tværs af websteder. @@ -1271,17 +1248,10 @@ Blokerer flere sporings-mekanismer. Sider indlæses hurtigere, men noget funktionalitet virker måske ikke. Vælg placeringen af din værktøjslinje - - Placer værktøjslinjen indenfor rækkevidde. Behold den nederst, eller flyt den til toppen. Behold den nederst, eller flyt den til toppen. - - Bedre beskyttelse af dit privatliv Du styrer dine data - - Vi har designet %s til at give dig kontrol over, hvad du deler på nettet - og hvad du deler med os. Firefox giver dig kontrol over, hvad du deler på nettet - og hvad du deler med os. @@ -1914,7 +1884,9 @@ Opdag mere - Leveret af Pocket. + Leveret af Pocket. + + Leveret af %s. En del af Firefox-familien. %s @@ -1928,4 +1900,14 @@ Gå til indstillinger Firefox-forslag + + + + folde sammen + + udvide + + åbne link for at læse mere om denne samling + + læse artiklen diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3b00e5fd8..a4acffd2c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -17,6 +17,12 @@ Suche oder Adresse + + Chronik durchsuchen + + Lesezeichen durchsuchen + + Tabs durchsuchen Suchbegriffe eingeben @@ -41,9 +47,6 @@ Ausgewählt - - Neueste Lesezeichen - Kürzlich gespeichert @@ -60,8 +63,8 @@ The first parameter is the name of the app defined in app_name (for example: Fenix) --> %1$s leert die eingegebenen Suchbegriffe und besuchten Webseiten aller privaten Tabs wenn Sie diese schließen oder die App beenden. Das macht Sie gegenüber Website-Betreibern und Internetanbietern nicht anonym, aber erleichtert es Ihnen, dass andere Nutzer dieses Geräts Ihre Aktivitäten nicht einsehen können. - - + + Häufige Missverständnisse über das Surfen im Privaten Modus @@ -134,13 +137,6 @@ Schaltfläche „Alle zuletzt geöffneten Tabs“ anzeigen - - Ihre Suche nach \"%1$s\" - - - %d Websites Alle synchronisierten Tabs anzeigen @@ -264,38 +260,20 @@ Sucheinstellungen - - - Was ist neu in %1$s - - Es ist jetzt einfacher, dort weiterzumachen, wo Sie aufgehört haben. - - Personalisierte %1$s-Startseite - - Wechseln Sie zu Ihren geöffneten Tabs, Lesezeichen und Ihrer Surf-Chronik. - - Übersichtliche, organisierte Tabs - - Dank verbessertem Layout und automatisch schließenden Tabs ist Schluss mit Unordnung. - - Letzte Suchanfragen - - Rufen Sie Ihre letzten Suchanfragen von Ihrer Startseite und Ihren Tabs aus erneut auf. - - - Ihre personalisierte Firefox-Startseite macht es jetzt einfacher, dort weiterzumachen, wo Sie aufgehört haben. Finden Sie Ihre letzten Tabs, Lesezeichen und Suchergebnisse. + + Dieses Mal suchen: + + + Dieses Mal suchen in: + Lernen Sie Ihre personalisierte Startseite kennen. Hier werden zuletzt verwendete Tabs, Lesezeichen und Suchergebnisse angezeigt. - Willkommen in einem unabhängigen Internet - Willkommen in einem persönlicheren Internet Mehr Farben. Bessere Privatsphäre. Gleiches Engagement für Menschen über Gewinne. - Wechseln Sie vom Handy zum Laptop und zurück - Das Wechseln zwischen Bildschirmen ist einfacher als je zuvor Machen Sie da weiter, wo Sie aufgehört haben – ab sofort finden Sie Tabs von anderen Geräten auf Ihrer Startseite. @@ -309,6 +287,9 @@ Ihre Tabs werden synchronisiert! Machen Sie dort weiter, wo Sie auf Ihrem anderen Gerät aufgehört haben. + + Schließen + Neuen %1$s-Tab öffnen @@ -359,6 +340,14 @@ Verknüpfung zum privaten Modus hinzufügen Nur-HTTPS-Modus + + + Reduzierung von Cookie-Bannern + + Cookie-Banner reduzieren + + Firefox versucht automatisch, Cookie-Anfragen auf Cookie-Bannern abzulehnen. Wenn keine Ablehnungsoption verfügbar ist, akzeptiert Firefox möglicherweise alle Cookies, um das Banner zu schließen. + Automatisch versuchen, eine Verbindung zu Websites herzustellen, die das HTTPS-Verschlüsselungsprotokoll verwenden, um die Sicherheit zu erhöhen. @@ -398,8 +387,6 @@ Anpassen - Synchronisieren Sie Lesezeichen, Chronik und mehr mit Ihrem Firefox-Konto - Melden Sie sich an, um Tabs, Lesezeichen, Passwörter und mehr zu synchronisieren. Firefox-Konto @@ -468,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Kürzlich besucht - Pocket + Pocket + + Geschichten, die zum Nachdenken anregen + + Artikel unterstützt von %s Gesponserte Geschichten @@ -492,12 +483,6 @@ Hintergrundbild konnte nicht geändert werden Weitere Informationen - - Hintergrundbild durch Tippen auf das Logo der Firefox-Startseite ändern - - - Firefox-Logo – Hintergrundbild ändern, Schaltfläche %s klassisch @@ -598,9 +583,6 @@ Ermöglicht Mozilla die Installation und Durchführung von Studien - - Sync aktivieren - Ihre Daten synchronisieren und speichern @@ -660,6 +642,17 @@ Schließen + + %d Tabs öffnen? + + Das Öffnen so vieler Tabs könnte %s verlangsamen, während die Seiten geladen werden. Sind Sie sicher, dass Sie fortfahren möchten? + + Tabs öffnen + + Abbrechen + %d Website @@ -690,10 +683,6 @@ Liste Raster - - Gruppen durchsuchen - - Zusammengehörige Websites gruppieren Tabs schließen @@ -820,9 +809,6 @@ %1$s (Privater Modus) - - Andere Tabs - Suchbegriffe eingeben @@ -851,18 +837,6 @@ Keine Chronik vorhanden - - Von anderen Geräten synchronisiert - - Von anderen Geräten - - - Melden Sie sich an, um die von Ihren anderen Geräten synchronisierte Chronik anzuzeigen. - - Anmelden - - Oder erstellen Sie ein Firefox-Konto, um mit der Synchronisation zu beginnen]]> - Downloads entfernt @@ -914,6 +888,10 @@ In neuem Tab öffnen In privatem Tab öffnen + + Alle in neuen Tabs öffnen + + Alle in privaten Tabs öffnen Löschen @@ -1105,6 +1083,10 @@ Teilen + + Als PDF speichern + + PDF kann nicht generiert werden An Gerät senden @@ -1116,9 +1098,11 @@ In Zwischenablage kopiert - Zum Synchronisieren anmelden + Zum Synchronisieren anmelden Bei Sync anmelden + + Daten synchronisieren und speichern An alle Geräte senden @@ -1156,6 +1140,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s als Ihren Standardbrowser festlegen + + Probieren Sie den Privaten Modus aus + + Surfen Sie mit %1$s ohne Cookies oder eine Chronik zu speichern + Sammlung gelöscht @@ -1251,8 +1241,6 @@ Beenden - - Dadurch werden alle Ihre Browser-Daten gelöscht. Zu löschender Zeitraum @@ -1286,33 +1274,20 @@ Gruppe gelöscht - - Willkommen bei %s! Willkommen in einem besseren Internet Ein Browser für Menschen, nicht für Profit. - - Synchronisieren Sie Firefox zwischen Geräten Machen Sie da weiter, wo Sie aufgehört haben - - Übertragen Sie Lesezeichen, Chronik und Passwörter zu %1$s auf diesem Gerät. Synchronisieren Sie Tabs und Passwörter geräteübergreifend für einen nahtlosen Bildschirmwechsel. - - Registrieren Anmelden Sync ist aktiviert - - Privatsphäre ab Werk Privatsphäre-Schutz als Standard - - %1$s verhindert automatisch, dass Unternehmen heimlich Ihre Aktivitäten im Internet verfolgen. Mit vollständigem Cookie-Schutz, um Tracker daran zu hindern, Cookies zu verwenden, um Sie über Websites hinweg zu verfolgen. @@ -1325,17 +1300,10 @@ Blockiert weitere Elemente zur Aktivitätenverfolgung, sodass Seiten schneller geladen werden, aber einige Seiten funktionieren dann eventuell nicht richtig. Wählen Sie die Position für Ihre Symbolleiste - - Platzieren Sie die Symbolleiste in Reichweite. Behalten Sie sie unten oder verschieben Sie sie nach oben. Unten lassen oder nach oben verschieben. - - Ihre Privatsphäre Sie kontrollieren Ihre Daten - - Wir haben %s so konzipiert, dass Sie die Kontrolle darüber haben, was Sie im Internet und was Sie mit uns teilen. Firefox gibt Ihnen die Kontrolle darüber, was Sie im Internet preisgeben und was Sie mit uns teilen. @@ -1522,10 +1490,10 @@ Einfügen & Los Einfügen - + URL in Zwischenablage kopiert - + Zum Startbildschirm hinzufügen @@ -1972,7 +1940,9 @@ Mehr entdecken - Bereitgestellt von Pocket + Bereitgestellt von Pocket + + Unterstützt durch %s. Teil der Firefox-Familie. %s @@ -1986,4 +1956,14 @@ Einstellungen öffnen Firefox-Vorschläge + + + + Einklappen + + Ausklappen + + Link öffnen, um mehr über diese Sammlung zu erfahren + + den Artikel zu lesen diff --git a/app/src/main/res/values-dsb/strings.xml b/app/src/main/res/values-dsb/strings.xml index 92c6eb99c..e5d3161e1 100644 --- a/app/src/main/res/values-dsb/strings.xml +++ b/app/src/main/res/values-dsb/strings.xml @@ -130,13 +130,6 @@ Tłocašk „Njedawno wócynjone rejtariki“ pokazaś - - Wašo pytanje za \"%1$s\" - - - Sedła: %d Synchronizěrowane rejtariki pokazaś @@ -302,6 +295,9 @@ Waše rejtariki se synchronizěruju! Pókšačujśo, źož sćo pśestał na drugem rěźe. + + Zacyniś + Nowy rejtarik %1$s wócyniś @@ -483,12 +479,6 @@ Slězynowy wobraz njedajo se změniś Dalšne informacije - - Pótusniśo logo startowego boka Firefox, aby slězynowy wobraz změnił - - - Logo Firefox - slězynowy wobraz změniś, tłocašk Klasiski %s @@ -674,10 +664,6 @@ Lisćina Kśidno - - Pytańske kupki - - Gromadu słušajuce sedła rědowaś Rejtariki zacyniś @@ -830,18 +816,6 @@ How žedna historija njejo - - Z drugich rědow synchronizěrowane - - Z drugich rědow - - - Pśizjawśo se, aby historiju wiźeł, kótaruž sćo synchronizěrował ze swójich drugich rědow. - - Pśizjawiś - - Abo załožćo konto Firefox, aby synchronizěrowanje zachopił]]> - Ześěgnjenja wótwónoźone @@ -1069,6 +1043,8 @@ Źěliś + + Ako PDF składowaś Rědoju pósłaś @@ -1080,9 +1056,11 @@ Do mjazyskłada kopěrowane - Pla Sync pśizjawiś + Pla Sync pśizjawiś Pla Sync pśizjawiś + + Synchronizěrowaś a daty składowaś Na wše rědy pósłaś @@ -1939,4 +1917,12 @@ K nastajenjam Naraźenja Firefox + + + + schowaś + + pokazaś + + wocyńśo wótkaz, aby wěcej wó toś tej zběrce zgónił diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 6a613c0f0..605e597ad 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -17,6 +17,12 @@ Αναζήτηση ή εισαγωγή διεύθυνσης + + Αναζήτηση ιστορικού + + Αναζήτηση σελιδοδεικτών + + Αναζήτηση καρτελών Εισαγωγή όρων αναζήτησης @@ -43,9 +49,6 @@ Επιλέχθηκε - - Πρόσφατοι σελιδοδείκτες - Πρόσφατα αποθηκευμένα @@ -136,13 +139,6 @@ Κουμπί «Εμφάνιση όλων των πρόσφατων καρτελών» - - Η αναζήτησή σας για «%1$s» - - - %d ιστότοποι Προβολή όλων των συγχρονισμένων καρτελών @@ -265,38 +261,19 @@ Ρυθμίσεις αναζήτησης - - - Τι νέο υπάρχει στο %1$s - - Τώρα είναι ευκολότερο να επιστρέψετε εκεί όπου σταματήσατε. - - Εξατομικευμένη αρχική σελίδα %1$s - - Μεταβείτε στις ανοικτές καρτέλες, τους σελιδοδείκτες και το ιστορικό περιήγησής σας. - - Σαφείς, οργανωμένες καρτέλες - - Κλείστε περιττές καρτέλες με τη βελτιωμένη διάταξη και το αυτόματο κλείσιμο καρτελών. - - Πρόσφατες αναζητήσεις - - Επισκεφθείτε ξανά τις τελευταίες αναζητήσεις σας από την αρχική σελίδα και τις καρτέλες σας. - - - Η εξατομικευμένη αρχική σελίδα του Firefox διευκολύνει την επιστροφή στο σημείο που σταματήσατε. Βρείτε τις πρόσφατες καρτέλες, τους σελιδοδείκτες και τα αποτελέσματα αναζήτησής σας. + + Αυτήν τη φορά, αναζήτηση: + + Αυτήν τη φορά, αναζήτηση σε: + Γνωρίστε την εξατομικευμένη αρχική σας σελίδα. Οι πρόσφατες καρτέλες, οι σελιδοδείκτες και τα αποτελέσματα αναζήτησης θα εμφανίζονται εδώ. - Καλώς ορίσατε σε ένα ανεξάρτητο διαδίκτυο - Καλώς ορίσατε σε ένα πιο προσωπικό διαδίκτυο Περισσότερα χρώματα. Ενισχυμένο απόρρητο. Η ίδια δέσμευση να βάζουμε τον άνθρωπο πάνω από το κέρδος. - Εναλλαγή από τηλέφωνο σε υπολογιστή και αντίστροφα - Η εναλλαγή οθονών είναι πιο εύκολη από ποτέ Συνεχίστε από εκεί που σταματήσατε, με καρτέλες από άλλες συσκευές στην αρχική σας σελίδα. @@ -310,6 +287,9 @@ Οι καρτέλες σας συγχρονίζονται! Συνεχίστε από εκεί που σταματήσατε στην άλλη συσκευή σας. + + Κλείσιμο + Άνοιγμα νέας καρτέλας %1$s @@ -360,6 +340,14 @@ Προσθήκη συντόμευσης ιδιωτικής περιήγησης Λειτουργία «Μόνο HTTPS» + + + Μείωση μπάνερ cookie + + Μείωση μπάνερ cookie + + Το Firefox προσπαθεί αυτόματα να απορρίψει τα αιτήματα cookie σε μπάνερ cookie. Εάν δεν διατίθεται επιλογή απόρριψης, το Firefox μπορεί να αποδεχτεί όλα τα cookies για να απορρίψει το μπάνερ. + Προσπαθεί αυτόματα να συνδεθεί σε ιστοτόπους με το πρωτόκολλο κρυπτογράφησης HTTPS για αυξημένη ασφάλεια. @@ -400,8 +388,6 @@ Προσαρμογή - Συγχρονισμός σελιδοδεικτών, ιστορικού και άλλων δεδομένων με τον λογαριασμό Firefox σας - Συνδεθείτε για να συγχρονίσετε τις καρτέλες, τους σελιδοδείκτες, τους κωδικούς πρόσβασης και πολλά άλλα. Λογαριασμός Firefox @@ -469,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Πρόσφατες επισκέψεις - Pocket + Pocket + + Άρθρα που σας βάζουν σε σκέψεις + + Τα άρθρα παρέχονται από το %s Χορηγούμενα άρθρα @@ -494,12 +484,6 @@ Δεν ήταν δυνατή η αλλαγή ταπετσαρίας Μάθετε περισσότερα - - Αλλαγή ταπετσαρίας από το λογότυπο του Firefox στην αρχική σελίδα - - - Λογότυπο Firefox - κουμπί αλλαγής ταπετσαρίας Κλασικό %s @@ -597,9 +581,6 @@ Επιτρέπει στο Mozilla την εγκατάσταση και εκτέλεση μελετών - - Ενεργοποίηση Sync - Συγχρονισμός και αποθήκευση δεδομένων @@ -659,6 +640,17 @@ Κλείσιμο + + Άνοιγμα %d καρτελών; + + Το άνοιγμα τόσο πολλών καρτελών ενδέχεται να επιβραδύνει το %s κατά τη φόρτωση των σελίδων. Θέλετε σίγουρα να συνεχίσετε; + + Άνοιγμα καρτελών + + Ακύρωση + %d ιστότοπος @@ -689,10 +681,6 @@ Λίστα Πλέγμα - - Αναζήτηση ομάδων - - Ομαδοποίηση σχετικών ιστοτόπων Κλείσιμο καρτελών @@ -817,9 +805,6 @@ %1$s (Ιδιωτική λειτουργία) - - Άλλες καρτέλες - Εισαγωγή όρων αναζήτησης @@ -848,18 +833,6 @@ Δεν υπάρχει ιστορικό - - Συγχρονισμένα από άλλες συσκευές - - Από άλλες συσκευές - - - Συνδεθείτε για να δείτε το ιστορικό από τις άλλες συσκευές σας. - - Σύνδεση - - Ή δημιουργήστε έναν λογαριασμό Firefox για να ξεκινήσει ο συγχρονισμός]]> - Οι λήψεις διαγράφηκαν @@ -910,6 +883,10 @@ Άνοιγμα σε νέα καρτέλα Άνοιγμα σε ιδιωτική καρτέλα + + Άνοιγμα όλων σε νέες καρτέλες + + Άνοιγμα όλων σε ιδιωτικές καρτέλες Διαγραφή @@ -1087,6 +1064,10 @@ Κοινή χρήση + + Αποθήκευση ως PDF + + Δεν είναι δυνατή η δημιουργία PDF Αποστολή σε συσκευή @@ -1098,9 +1079,11 @@ Αντιγράφηκε στο πρόχειρο - Σύνδεση για συγχρονισμό + Σύνδεση για συγχρονισμό Σύνδεση στο Sync + + Συγχρονισμός και αποθήκευση δεδομένων Αποστολή σε όλες τις συσκευές @@ -1138,6 +1121,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Ορισμός του %1$s ως προεπιλεγμένου προγράμματος περιήγησης + + Δοκιμάστε την ιδιωτική περιήγηση + + Περιηγηθείτε χωρίς αποθηκευμένα cookies ή ιστορικό στο %1$s + Η συλλογή διαγράφηκε @@ -1228,8 +1217,6 @@ Έξοδος - - Αυτό θα διαγράψει όλα τα δεδομένα περιήγησής σας. Χρονικό διάστημα διαγραφής @@ -1263,34 +1250,21 @@ Η ομάδα διαγράφηκε - - Καλώς ορίσατε στο %s! Καλώς ήρθατε σε ένα καλύτερο διαδίκτυο Ένα πρόγραμμα περιήγησης που δημιουργήθηκε για τους ανθρώπους, όχι το κέρδος. - - Συγχρονισμός Firefox μεταξύ συσκευών Συνεχίστε από εκεί που σταματήσατε - - Φέρτε σελιδοδείκτες, ιστορικό και κωδικούς πρόσβασης στο %1$s σε αυτήν τη συσκευή. Συγχρονίστε καρτέλες και κωδικούς πρόσβασης με τις συσκευές σας για απρόσκοπτη εναλλαγή οθονών. - - Εγγραφή Σύνδεση Το Sync είναι ενεργό - - Μόνιμη προστασία απορρήτου Προστασία απορρήτου από προεπιλογή - - Το %1$s εμποδίζει την καταγραφή της διαδικτυακής δραστηριότητάς σας από εταιρείες. Η Ολική προστασία cookie εμποδίζει τη χρήση των cookies από ιχνηλάτες που σας καταγράφουν μεταξύ ιστοτόπων. @@ -1303,17 +1277,10 @@ Φραγή περισσότερων ιχνηλατών για ταχύτερη φόρτωση σελίδων. Ορισμένες λειτουργίες της σελίδας ενδέχεται να δυσλειτουργούν. Επιλογή τοποθεσίας γραμμής εργαλείων - - Τοποθετήστε τη γραμμή εργαλείων σε κοντινή απόσταση. Κρατήστε την στο κάτω μέρος ή μετακινήστε την στο πάνω μέρος. Διατηρήστε τη στο κάτω μέρος ή μετακινήστε τη στο πάνω μέρος. - - Το απόρρητό σας Εσείς ελέγχετε τα δεδομένα σας - - Έχουμε σχεδιάσει το %s έτσι, ώστε να ελέγχετε τι κοινοποιείτε στο διαδίκτυο και σε εμάς. Το Firefox σάς επιτρέπει να ελέγχετε τι κοινοποιείτε στο διαδίκτυο και σε εμάς. @@ -1960,7 +1927,9 @@ Ανακαλύψτε περισσότερα - Με την υποστήριξη του Pocket. + Με την υποστήριξη του Pocket. + + Με την υποστήριξη του %1$s. Μέρος της οικογένειας του Firefox. %s @@ -1974,4 +1943,14 @@ Μετάβαση στις ρυθμίσεις Προτάσεις Firefox + + + + σύμπτυξη + + ανάπτυξη + + άνοιγμα συνδέσμου για περισσότερες πληροφορίες σχετικά με αυτήν τη συλλογή + + ανάγνωση του άρθρου diff --git a/app/src/main/res/values-en-rCA/strings.xml b/app/src/main/res/values-en-rCA/strings.xml index 577d648bc..d131e5211 100644 --- a/app/src/main/res/values-en-rCA/strings.xml +++ b/app/src/main/res/values-en-rCA/strings.xml @@ -15,6 +15,12 @@ Disable private browsing Search or enter address + + Search history + + Search bookmarks + + Search tabs Enter search terms @@ -131,13 +137,6 @@ Show all recent tabs button - - Your search for \"%1$s\" - - - %d sites See all synced tabs @@ -258,6 +257,9 @@ Search settings + + This time search: + What’s new in %1$s @@ -302,6 +304,9 @@ Your tabs are syncing! Pick up where you left off on your other device. + + Close + Open a new %1$s tab @@ -457,8 +462,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Recently visited - Pocket + Pocket + + Thought-provoking stories + + Articles powered by %s Sponsored stories @@ -473,11 +482,30 @@ Wallpaper updated! View - - Change wallpaper by tapping Firefox homepage logo - - Firefox logo - change the wallpaper, button + + Couldn’t download wallpaper + + Try again + + Couldn’t change wallpaper + + Learn more + + + Classic %s + + Limited Edition + + The new Independent Voices collection. %s + + The new Independent Voices collection. + + + Try a splash of colour + + Choose a wallpaper that speaks to you. + + Explore more wallpapers @@ -618,6 +646,17 @@ Close + + Open %d tabs? + + Opening this many tabs may slow down %s while the pages are loading. Are you sure you want to continue? + + Open tabs + + Cancel + %d site @@ -647,10 +686,6 @@ List Grid - - Search groups - - Group related sites together Close tabs @@ -801,18 +836,6 @@ No history here - - Synced from other devices - - From other devices - - - Sign in to see history synced from your other devices. - - Sign in - - Or create a Firefox account to start syncing]]> - Downloads Removed @@ -862,6 +885,10 @@ Open in new tab Open in private tab + + Open all in new tabs + + Open all in private tabs Delete @@ -1038,6 +1065,10 @@ Share + + Save as PDF + + Unable to generate PDF Send to device @@ -1049,9 +1080,11 @@ Copied to clipboard - Sign in to sync + Sign in to sync Sign in to Sync + + Sync and save data Send to all devices @@ -1210,18 +1243,32 @@ Welcome to %s! + + Welcome to a better internet + + A browser built for people, not profits. Sync Firefox between devices + + Pick up where you left off Bring bookmarks, history, and passwords to %1$s on this device. + + Sync tabs and passwords across devices for seamless screen-switching. Sign up + + Sign in Sync is on Always-on privacy + + Privacy protection by default %1$s automatically stops companies from secretly following you around the web. + + Featuring Total Cookie Protection to stop trackers from using cookies to stalk you across sites. Standard (default) @@ -1234,14 +1281,22 @@ Pick your toolbar placement Put the toolbar within easy reach. Keep it on the bottom, or move it to the top. + + Keep it on the bottom, or move it to the top. Your privacy + + You control your data We’ve designed %s to give you control over what you share online and what you share with us. + + Firefox gives you control over what you share online and what you share with us. Read our privacy notice + + Ready to open up an amazing internet? Start browsing @@ -1868,7 +1923,9 @@ Discover more - Powered by Pocket. + Powered by Pocket. + + Powered by %s. Part of the Firefox family. %s @@ -1882,4 +1939,14 @@ Go to settings Firefox Suggest + + + + collapse + + expand + + open link to learn more about this collection + + read the article diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml index 97c06910a..b7415bde6 100644 --- a/app/src/main/res/values-en-rGB/strings.xml +++ b/app/src/main/res/values-en-rGB/strings.xml @@ -14,6 +14,12 @@ Disable private browsing Search or enter address + + Search history + + Search bookmarks + + Search tabs Enter search terms @@ -39,8 +45,6 @@ - Recent bookmarks - Recently saved Show all saved bookmarks @@ -129,13 +133,6 @@ Show all recent tabs button - - Your search for \"%1$s\" - - - %d sites See all synchronised tabs @@ -256,38 +253,20 @@ Search settings - - - What’s new in %1$s - - It’s now easier to pick back up where you left off. - - Personalised %1$s homepage - - Jump to your open tabs, bookmarks and browsing history. - - Clean, organised tabs - - Clear away tab clutter with improved layout and auto-closing tabs. - - Recent searches - - Revisit your latest searches from your homepage and tabs. - - - Your personalised Firefox homepage now makes it easier to pick up where you left off. Find your recent tabs, bookmarks and search results. + + This time search: + + This time search in: + + Meet your personalised homepage. Recent tabs, bookmarks, and search results will appear here. - Welcome to an independent internet - Welcome to a more personal internet More colours. Better privacy. Same commitment to people over profits. - Hop from phone to laptop and back - Switching screens is easier than ever Pick up where you left off with tabs from other devices now on your homepage. @@ -301,6 +280,9 @@ Your tabs are synchronising! Pick up where you left off on your other device. + + Close + Open a new %1$s tab @@ -350,6 +332,14 @@ Add private browsing shortcut HTTPS-Only Mode + + + Cookie Banner Reduction + + Reduce cookie banners + + Firefox automatically tries to reject cookie requests on cookie banners. If a reject option isn’t available, Firefox may accept all cookies to dismiss the banner. + Automatically attempts to connect to sites using HTTPS encryption protocol for increased security. @@ -390,8 +380,6 @@ Customise - Synchronise bookmarks, history and more with your Firefox Account - Sign in to synchronise tabs, bookmarks, passwords, and more. Firefox Account @@ -459,8 +447,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Recently visited - Pocket + Pocket + + Thought-provoking stories + + Articles powered by %s Sponsored stories @@ -483,12 +475,6 @@ Couldn’t change wallpaper Learn more - - Change wallpaper by tapping Firefox homepage logo - - - Firefox logo - change the wallpaper, button Classic %s @@ -585,8 +571,6 @@ Allows Mozilla to install and run studies - - Turn on Sync Synchronise and save your data @@ -646,6 +630,17 @@ Close + + Open %d tabs? + + Opening this many tabs may slow down %s while the pages are loading. Are you sure you want to continue? + + Open tabs + + Cancel + %d site @@ -675,10 +670,6 @@ List Grid - - Search groups - - Group related sites together Close tabs @@ -804,9 +795,6 @@ %1$s (Private Mode) - - Other tabs - Enter search terms @@ -834,18 +822,6 @@ No history here - - Synchronised from other devices - - From other devices - - - Sign in to see history synchronised from your other devices. - - Sign in - - Or create a Firefox account to start synchronising]]> - Downloads Removed @@ -895,6 +871,10 @@ Open in new tab Open in private tab + + Open all in new tabs + + Open all in private tabs Delete @@ -1072,6 +1052,10 @@ Share + + Save as PDF + + Unable to generate PDF Send to device @@ -1083,9 +1067,11 @@ Copied to clipboard - Sign in to synchronise + Sign in to synchronise Sign in to Sync + + Synchronise and save data Send to all devices @@ -1121,6 +1107,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Make %1$s your default browser + + Try private browsing + + Browse with no saved cookies or history in %1$s + Collection deleted @@ -1209,8 +1201,6 @@ Quit - - This will delete all of your browsing data. Time range to delete @@ -1243,33 +1233,20 @@ Group deleted - - Welcome to %s! Welcome to a better internet A browser built for people, not profits. - - Synchronise Firefox between devices Pick up where you left off - - Bring bookmarks, history, and passwords to %1$s on this device. Synchronise tabs and passwords across devices for seamless screen-switching. - - Sign up Sign in Sync is on - - Always-on privacy Privacy protection by default - - %1$s automatically stops companies from secretly following you around the web. Featuring Total Cookie Protection to stop trackers from using cookies to stalk you across sites. @@ -1282,17 +1259,10 @@ Blocks more trackers so pages load faster, but some on-page functionally may break. Pick your toolbar placement - - Put the toolbar within easy reach. Keep it on the bottom, or move it to the top. Keep it on the bottom, or move it to the top. - - Your privacy You control your data - - We’ve designed %s to give you control over what you share online and what you share with us. Firefox gives you control over what you share online and what you share with us. @@ -1926,7 +1896,9 @@ Discover more - Powered by Pocket + Powered by Pocket + + Powered by %s. Part of the Firefox family. %s @@ -1940,4 +1912,14 @@ Go to settings Firefox Suggest + + + + collapse + + expand + + open link to learn more about this collection + + read the article diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 8347c3717..3483fd9ea 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -15,6 +15,12 @@ Malaktivigi privatan retumon Serĉo aŭ adreso + + Serĉi en historio + + Serĉi legosignojn + + Serĉi langetojn Tajpu serĉan tekston @@ -128,12 +134,6 @@ Butono por montri ĉiujn lastajn langetojn - - Via serĉo de \"%1$s\" - - %d retejoj Montri ĉiujn spegulitajn langetojn @@ -254,6 +254,9 @@ Agordoj de serĉo + + Ĉi foje serĉi: + Novaĵoj en %1$s @@ -299,6 +302,9 @@ Viaj langetoj estas spegulataj! Daŭrigu kie vi haltis en via alia aparato. + + Fermi + Malfermi novan langeton de %1$s @@ -455,7 +461,11 @@ a section where users see a list of tabs that they have visited in the past few days --> Ĵusaj retpaĝoj - Pocket + Pocket + + Pensigaj artikoloj + + Artikoloj sugestitaj de %s Patronitaj artikoloj @@ -479,11 +489,6 @@ Ne eblis ŝanĝi ekranfonon Pli da informo - - Ŝanĝi ekranfonon per tuŝeto de la emblemo de Firefox en la eka paĝo - - Emblemo de Firefox – ŝanĝi ekranfonon, butono Klasika %s @@ -642,6 +647,17 @@ Fermi + + Ĉu malfermi %d langetojn? + + Malfermi tiom da langetoj povas malrapidigi %s, dum la paĝoj ŝargiĝas. Ĉu vi certe volas daŭrigi? + + Malfermi langetojn + + Nuligi + %d retejo @@ -672,10 +688,6 @@ Listo Krado - - Grupoj de serĉoj - - Grupigi rilatitajn retejojn Fermi langetojn @@ -828,18 +840,6 @@ Neniu historio estas ĉi tie - - Spegulita de aliaj aparatoj - - El aliaj aparatoj - - - Komencu seancon por vidi la spegulitan historion el viaj aliaj aparatoj. - - Komenci seancon - - Aŭ kreu konton de Firefox por komenci speguli]]> - Elŝutoj forigitaj @@ -890,6 +890,10 @@ Malfermi en nova langeto Malfermi en privata langeto + + Malfermi ĉiujn en novaj langetoj + + Malfermi ĉiujn en privataj langetoj Forigi @@ -1070,6 +1074,10 @@ "Share" button. Opens the share menu when pressed. --> Dividi + + Konservi kiel PDF + + Ne eblas krei dosieron PDF Sendi al aparato @@ -1081,9 +1089,11 @@ Kopiita al la tondujo - Komenci seancon por speguli + Komenci seancon por speguli Komenci seancon en Speguli + + Speguli kaj konservi datumojn Sendi al ĉiuj aparatoj @@ -1937,7 +1947,9 @@ Malkovri pli da aferoj - Pelata de Pocket. + Pelata de Pocket. + + Kun teknologio de %s. Parto de la familio de Firefox. %s @@ -1951,4 +1963,14 @@ Iri al agordoj Sugestoj de Firefox + + + + faldi + + malfaldi + + malfermi ligilon por havi pli da informo pri tiu ĉi kolekto + + legi la artikolon diff --git a/app/src/main/res/values-es-rAR/strings.xml b/app/src/main/res/values-es-rAR/strings.xml index 8e2bbbff6..4c6143fad 100644 --- a/app/src/main/res/values-es-rAR/strings.xml +++ b/app/src/main/res/values-es-rAR/strings.xml @@ -15,6 +15,12 @@ Deshabilitar la navegación privada Buscar o ingresar la dirección + + Buscar en historial + + Buscar en marcadores + + Buscar pestañas Ingresar términos de búsqueda @@ -40,8 +46,6 @@ - Marcadores recientes - Guardados recientemente Mostrar todos los marcadores guardados @@ -131,13 +135,6 @@ Botón para mostrar todas las pestañas recientes - - La búsqueda de \"%1$s\" - - - %d sitios Ver todas las pestañas sincronizadas @@ -262,39 +259,20 @@ Configuración de búsqueda - - - ¿Qué hay de nuevo en %1$s? - - Ahora es más fácil continuar donde lo dejaste. - - Página de inicio personalizada de %1$s - - Accedé a tus pestañas abiertas, marcadores y al historial de navegación. - - Pestañas claras y organizadas - - Eliminá el desorden de las pestañas con un diseño mejorado y cierre automático. - - Búsquedas recientes - - - Revisá tus últimas búsquedas desde tu página de inicio y pestañas. - - - Tu página de inicio de Firefox personalizada hace que ahora sea más fácil continuar donde lo habías dejado. Encontrá tus pestañas, marcadores y resultados de búsqueda recientes. + + Esta vez buscá: + + Esta vez, buscar en: + + Conocé tu página de inicio personalizada. Las pestañas recientes, los marcadores y los resultados de búsqueda aparecerán aquí. - Bienvenido a una Internet independiente - Bienvenido a una Internet más personal Más colores. Mejor privacidad. Mismo compromiso con las personas por encima de los beneficios. - - Cambiá de teléfono a computadora y viceversa Cambiar de pantallas es más fácil que nunca @@ -309,6 +287,9 @@ ¡Tus pestañas se están sincronizando! Continuá donde lo dejaste en tu otro dispositivo. + + Cerrar + Abrir una nueva pestaña de %1$s @@ -358,6 +339,14 @@ Agregar atajo de navegación privada Modo solo HTTPS + + + Reducción de pancarta de cookies + + Reducir las pancartas de cookies + + Firefox intenta rechazar automáticamente las solicitudes de cookies en las pancartas de cookies. Si una opción de rechazo no está disponible, Firefox puede aceptar todas las cookies para descartar la pancarta. + Intenta conectarse automáticamente a sitios usando el protocolo de cifrado HTTPS para mayor seguridad. @@ -397,8 +386,6 @@ Personalizar - Sincronizar marcadores, historial y más con tu cuenta Firefox - Iniciá la sesión para sincronizar pestañas, marcadores, contraseñas y más. Cuenta Firefox @@ -467,8 +454,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitados recientemente - Pocket + Pocket + + Historias que te hacen reflexionar + + Artículos impulsados por %s Historias patrocinadas @@ -491,12 +482,6 @@ No se pudo cambiar el fondo de pantalla Conocer más - - Cambiar el fondo de pantalla tocando el logotipo de la página de inicio de Firefox - - - Logotipo de Firefox - cambiar el fondo de pantalla, botón %s clásico @@ -598,8 +583,6 @@ - - Activar Sync Sincronizá y guardá los datos @@ -662,6 +645,17 @@ Cerrar + + ¿Abrir %d pestañas? + + Abrir tantas pestañas puede ralentizar a %s mientras se cargan las páginas. ¿Estás seguro de que querés continuar? + + Abrir pestañas + + Cancelar + %d sitio @@ -691,10 +685,6 @@ Lista Cuadrícula - - Buscar en grupos - - Agrupar sitios relacionados Cerrar pestañas @@ -823,9 +813,6 @@ %1$s (modo privado) - - Otras pestañas - Ingresar términos de búsqueda @@ -854,18 +841,6 @@ Aquí no hay historial - - Sincronizados de otros dispositivos - - Desde otros dispositivos - - - Iniciá la sesión para ver el historial sincronizado desde tus otros dispositivos. - - Iniciar la sesión - - O creá una cuenta de Firefox para comenzar a sincronizar]]> - Descargas eliminadas @@ -916,6 +891,10 @@ Abrir en una nueva pestaña Abrir en una pestaña privada + + Abrir todo en pestañas nuevas + + Abrir todo en pestañas privadas Eliminar @@ -1096,6 +1075,10 @@ Compartir + + Guardar como PDF + + No se pudo generar el PDF Enviar al dispositivo @@ -1107,9 +1090,11 @@ Copiado al portapapeles - Iniciá sesión para sincronizar + Iniciá sesión para sincronizar Iniciar sesión en Sync + + Sincronizar y guardar datos Enviar a todos los dispositivos @@ -1147,6 +1132,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Hacer que %1$s sea el navegador predeterminado + + Probá la navegación privada + + Navegá sin cookies ni historial guardados en %1$s + Se eliminó la colección @@ -1237,8 +1228,6 @@ Salir - - Esto eliminará todos tus datos de navegación. Intervalo de tiempo para borrar @@ -1272,33 +1261,20 @@ Grupo eliminado - - ¡Bienvenido a %s! Bienvenido a una Internet mejor Un navegador hecho para la gente, no por el dinero. - - Sincronizar Firefox entre dispositivos Continuá desde donde dejaste - - Traer marcadores, historial y contraseñas a %1$s en este dispositivo. Sincronizá pestañas y contraseñas entre dispositivos para cambiar de pantalla sin problemas. - - Registrate Iniciar sesión La sincronización está activada - - Privacidad siempre activada Protección de privacidad de manera predetermina - - %1$s impide automáticamente que las compañías te sigan en secreto por la web. Incluye Total Cookie Protection para evitar que los rastreadores usen cookies para espiarte entre sitios. @@ -1311,18 +1287,11 @@ Bloquea más rastreadores para que las páginas se carguen más rápido, pero pueden fallar algunas funcionalidades de la página. Elegí la ubicación de la barra de herramientas - - Poné la barra de herramientas a tu alcance. Mantenela abajo, o movela hacia arriba. Mantenela en la parte inferior o movela a la parte superior. - - Tu privacidad Controlás tus datos - - Diseñamos %s para que puedas controlar lo que compartís en línea y lo que compartís con nosotros. Firefox te da el control sobre lo que compartís en línea y lo que compartís con nosotros. @@ -1503,7 +1472,7 @@ The first parameter is number of long clicks left to enable the menu --> Menú de depuración: %1$d clic(s) para habilitarlo Menú de depuración habilitado - + Copiar @@ -1511,10 +1480,10 @@ Pegar e ir Pegar - + URL copiada al portapapeles - + Agregar a pantalla de inicio @@ -1964,7 +1933,9 @@ Descubrir más - Desarrollado por Pocket. + Desarrollado por Pocket. + + Impulsado por %s. Parte de la familia de Firefox. %s @@ -1978,4 +1949,14 @@ Ir a ajustes Sugerencia de Firefox + + + + contraer + + expandir + + abrir enlace para conocer más sobre esta colección + + diff --git a/app/src/main/res/values-es-rCL/strings.xml b/app/src/main/res/values-es-rCL/strings.xml index 60dceea24..2600dd6d4 100644 --- a/app/src/main/res/values-es-rCL/strings.xml +++ b/app/src/main/res/values-es-rCL/strings.xml @@ -14,6 +14,12 @@ Desactivar la navegación privada Buscar o ingresar dirección + + Buscar en historial + + Buscar marcadores + + Buscar pestañas Ingresar términos de búsqueda @@ -39,8 +45,6 @@ - Marcadores recientes - Guardados recientemente Mostrar todos los marcadores guardados @@ -130,13 +134,6 @@ Botón mostrar todas las pestañas recientes - - Tu búsqueda de \"%1$s\" - - - %d sitios Ver todas las pestañas sincronizadas @@ -257,38 +254,20 @@ Buscar ajustes - - - Qué hay de nuevo en %1$s - - Ahora es más fácil retomar desde donde quedaste. - - Página de inicio personalizada de %1$s - - Salta a tus pestañas abiertas, marcadores e historial de navegación. - - Pestañas limpias y organizadas - - Elimina el desorden de pestañas con un diseño mejorado y pestañas con cierre automático. - - Búsquedas recientes - - Revise tus últimas búsquedas desde tu página de inicio y pestañas. - - - Tu página de inicio personalizada de Firefox ahora hace que sea mucho más fácil continuar desde donde quedaste. Encuentra tus pestañas, marcadores y resultados de búsqueda recientes. + + Esta vez buscar: + + Esta vez buscar en: + + Conoce tu página de inicio personalizada. Las pestañas recientes, marcadores y resultados de búsqueda aparecerán aquí. - Te damos la bienvenida a un internet independiente - Te damos la bienvenida a un internet más personal Más colores. Mejor privacidad. Mismo compromiso con las personas por encima de los beneficios. - Salta del teléfono al computador y viceversa - Cambiar de pantalla es más fácil que nunca Continua donde lo dejaste con pestañas de otros dispositivos ahora en tu página de inicio. @@ -302,6 +281,9 @@ ¡Tus pestañas se están sincronizando! Continua donde te quedaste en otro dispositivo. + + Cerrar + Abrir una nueva pestaña de %1$s @@ -351,6 +333,14 @@ Añadir acceso directo a la navegación privada Modo solo HTTPS + + + Reducción de banner de cookies + + Reducir los banners de cookies + + Firefox intenta rechazar automáticamente las solicitudes de cookies en los banners de cookies. Si una opción de rechazo no está disponible, Firefox podría aceptar todas las cookies para cerrar el banner. + Intenta conectarse automáticamente a sitios utilizando el protocolo de cifrado HTTPS para mayor seguridad. @@ -458,8 +448,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitados recientemente - Pocket + Pocket + + Historias que te hacen reflexionar + + Artículos recomendados por %s Historias patrocinadas @@ -483,12 +477,6 @@ No se pudo cambiar el fondo de pantalla Aprender más - - Cambia el fondo de pantalla tocando el logo de Firefox en la página de inicio - - - Logotipo de Firefox - cambiar el fondo de pantalla, botón %s clásico @@ -645,6 +633,17 @@ Cerrar + + ¿Abrir %d pestañas? + + Abrir esta cantidad de pestañas podría dejar muy lento a %s mientras se cargan las páginas. ¿Estás seguro de quieres continuar? + + Pestañas abiertas + + Cancelar + %d sitio @@ -674,10 +673,6 @@ Lista Cuadrícula - - Buscar en grupos - - Agrupar sitios relacionados Cerrar pestañas @@ -830,18 +825,6 @@ Sin historial aquí - - Sincronizado de otro dispositivo - - Desde otros dispositivos - - - Conéctate para ver el historial sincronizado de tus otros dispositivos. - - Conectarse - - O crea una cuenta de Firefox para empezar a sincronizar]]> - Descargas removidas @@ -891,6 +874,10 @@ Abrir en nueva pestaña Abrir en pestaña privada + + Abrir todo en pestañas nuevas + + Abrir todo en pestañas privadas Eliminar @@ -1067,6 +1054,10 @@ Compartir + + Guardar como PDF + + No se pudo generar el PDF Enviar a dispositivo @@ -1078,9 +1069,11 @@ Copiado al portapapeles - Conectarse para sincronizar + Conectarse para sincronizar Conectarse para sincronizar + + Sincronizar y guardar datos Enviar a todos los dispositivos @@ -1117,6 +1110,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Establecer %1$s como tu navegador predeterminado + + Prueba la navegación privada + + Navega sin guardar cookies ni historial en %1$s + Colección eliminada @@ -1237,34 +1236,20 @@ Grupo eliminado - - ¡Te damos la bienvenida a %s! - Te damos la bienvenida a un mejor internet Un navegador desarrollado para las personas, no para lucrar. - - Sincroniza Firefox entre dispositivos Continúa donde quedaste - - Trae marcadores, historial y contraseñas a %1$s en este dispositivo. Sincroniza pestañas y contraseñas entre dispositivos para cambiar de pantalla de forma fluida. - - Registrarse Conectarse Sincronización activada - - Privacidad siempre activa Protección de privacidad por defecto - - %1$s automáticamente detiene a las compañías que te siguen en secreto por la web. Incluye la protección total contra cookies para evitar que los rastreadores usen cookies para seguirte entre sitios. @@ -1277,18 +1262,11 @@ Bloquea más rastreadores para que las páginas se carguen más rápido, pero algunas funcionalidades de la página pueden fallar. Elige la ubicación de la barra de herramientas - - Coloca la barra de herramientas al alcance de la mano. Mantenla en la parte inferior o muévela hacia arriba. Mantenla en la parte inferior o muévela a la parte superior. - - Tu privacidad Tu controlas tus datos - - Hemos diseñado %s para darte el control sobre lo que compartes en línea y lo que compartes con nosotros. Firefox te da control sobre lo que compartes en línea y lo que compartes con nosotros. @@ -1925,7 +1903,9 @@ Descubrir más - Impulsado por Pocket. + Impulsado por Pocket. + + Con la tecnología de %s. Parte de la familia Firefox. %s @@ -1939,4 +1919,14 @@ Ir a ajustes Sugerencias de Firefox + + + + contraer + + expandir + + abrir enlace para aprender más acerca de esta colección + + leer el artículo diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index c5c1b44c6..bf3352b7a 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -17,6 +17,12 @@ Buscar o escribir dirección + + Buscar en el historial + + Buscar marcadores + + Buscar pestañas Introducir términos de búsqueda @@ -42,9 +48,6 @@ Seleccionada - - Marcadores recientes - Guardado recientemente @@ -134,13 +137,6 @@ Mostrar el botón de todas las pestañas recientes - - Tu búsqueda por \"%1$s\" - - - %d sitios Ver todas las pestañas sincronizadas @@ -264,37 +260,19 @@ Configuración de búsquedas - - - Novedades de %1$s - - Ahora es más fácil continuar donde lo habías dejado. - - Página de inicio de %1$s personalizada - - Accede a tus pestañas abiertas, marcadores y al historial de navegación. - - Pestañas claras y organizadas - - Elimina el desorden de pestañas con un diseño mejorado y con cierre automático. - - Búsquedas recientes - - Revisa tus últimas búsquedas desde tu página de inicio y pestañas. - - - Tu página de inicio de Firefox personalizada hace que ahora sea más fácil continuar donde lo habías dejado. Encuentra tus pestañas, marcadores y resultados de búsqueda recientes. + + Buscar esta vez: + + + Esta vez buscar en: + Descubre tu página de inicio personalizada. Las pestañas recientes, marcadores y resultados de búsqueda aparecerán aquí. - Te damos la bienvenida a un internet independiente - Te damos la bienvenida a un Internet más personal Más colores. Mejor privacidad. Mismo compromiso con las personas por encima de los beneficios. - - Salta del teléfono al ordenador y viceversa Cambiar de pantalla es más fácil que nunca @@ -309,6 +287,9 @@ ¡Tus pestañas se están sincronizando! Continúa donde lo dejaste en otro dispositivo. + + Cerrar + Abrir una pestaña nueva de %1$s @@ -360,6 +341,14 @@ Agregar acceso directo a navegación privada Modo solo HTTPS + + + Reducción de avisos de cookies + + Reducir los avisos de cookies + + Firefox intenta rechazar automáticamente las solicitudes de cookies en los avisos de cookies. Si no está disponible una opción de rechazo, Firefox podría aceptar todas las cookies para cerrar el aviso. + Intenta conectarse automáticamente a sitios utilizando el protocolo de cifrado HTTPS para mayor seguridad. @@ -467,8 +456,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitados recientemente - Pocket + Pocket + + Historias que te hacen reflexionar + + Artículos impulsados por %s Historias patrocinadas @@ -491,11 +484,6 @@ No se ha podido cambiar el fondo de pantalla Saber más - - Cambia el fondo de pantalla tocando el logotipo de la página de inicio de Firefox - - Logotipo de Firefox - cambiar el fondo de pantalla, botón %s clásico @@ -655,6 +643,17 @@ Cerrar + + ¿Abrir %d pestañas? + + Abrir tantas pestañas puede ralentizar %s mientras se cargan las páginas. ¿Estás seguro de que quieres continuar? + + Abrir pestañas + + Cancelar + %d sitio @@ -684,10 +683,6 @@ Lista Cuadrícula - - Buscar en grupos - - Agrupar sitios relacionados Cerrar pestañas @@ -840,18 +835,6 @@ No hay ningún historial - - Sincronizado desde otros dispositivos - - Desde otros dispositivos - - - Inicia sesión para ver una lista de pestañas de tus otros dispositivos. - - Iniciar sesión - - O crea una cuenta de Firefox para empezar a sincronizar]]> - Descargas eliminadas @@ -903,6 +886,10 @@ Abrir en una nueva pestaña Abrir en una pestaña privada + + Abrir todo en pestañas nuevas + + Abrir todo en pestañas privadas Eliminar @@ -1092,6 +1079,10 @@ Compartir + + Guardar como PDF + + No se puede generar PDF Enviar a dispositivo @@ -1103,9 +1094,11 @@ Copiado al portapapeles - Inicia sesión para sincronizar + Inicia sesión para sincronizar Iniciar sesión en Sync + + Sincronizar y guardar datos Enviar a todos los dispositivos @@ -1272,34 +1265,20 @@ Grupo eliminado - - ¡Te damos la bienvenida a %s! - Te damos la bienvenida a un mejor Internet Un navegador creado para las personas, no para el lucro. - - Sincronizar Firefox entre dispositivos Continúa donde lo dejaste. - - Traer marcadores, historial y contraseñas a %1$s en este dispositivo. Sincroniza pestañas y contraseñas entre dispositivos para cambiar de pantalla sin interrupciones. - - Registrarse Iniciar sesión Sync está activado - - Privacidad siempre activada Protección de privacidad de manera predeterminada - - %1$s bloquea automáticamente a las compañías que te siguen en secreto por la web. Incluye Total Cookie Protection para evitar que los rastreadores usen cookies para espiarte entre sitios. @@ -1312,17 +1291,10 @@ Bloquea más rastreadores para que las páginas se carguen más rápido, pero pueden fallar algunas funcionalidades de la página. Escoge la posición de la barra de herramientas - - Pon la barra de herramientas a tu alcance. Mantenla abajo, o muévela hacia arriba. Mantenlo en la parte inferior o muévelo a la parte superior. - - Tu privacidad Tú controlas tus datos - - Hemos diseñado %s para darte el control sobre lo que compartes en línea y lo que compartes con nosotros. Firefox te da control sobre lo que compartes en línea y lo que compartes con nosotros. @@ -1373,7 +1345,7 @@ Desconectar Cancelar - + No se pueden editar las carpetas predeterminadas @@ -1511,10 +1483,10 @@ Pegar e ir Pegar - + URL copiada al portapapeles - + Añadir a la pantalla de inicio @@ -1965,7 +1937,9 @@ Descubrir más - Desarrollado por Pocket. + Desarrollado por Pocket. + + Impulsado por %s. Parte de la familia Firefox. %s @@ -1979,4 +1953,14 @@ Ir a ajustes Firefox Suggest + + + + contraer + + expandir + + abrir enlace para saber más sobre esta colección + + leer el artículo diff --git a/app/src/main/res/values-es-rMX/strings.xml b/app/src/main/res/values-es-rMX/strings.xml index 76354b0c7..15f2040e4 100644 --- a/app/src/main/res/values-es-rMX/strings.xml +++ b/app/src/main/res/values-es-rMX/strings.xml @@ -14,6 +14,12 @@ Deshabilitar navegación privada Buscar o ingresar dirección + + Buscar el historial + + Buscar marcadores + + Buscar pestañas Ingresa los términos de búsqueda @@ -39,8 +45,6 @@ - Marcadores recientes - Guardado recientemente Mostrar todos los marcadores guardados @@ -128,13 +132,6 @@ Mostrar el botón de todas las pestañas recientes - - Tu búsqueda de \"%1$s\" - - - %d sitios Ver todas las pestañas sincronizadas @@ -257,39 +254,20 @@ Ajustes de búsqueda - - - Qué hay de nuevo en %1$s - - Ahora es más fácil continuar donde lo dejaste. - - Página de inicio de %1$s personalizada - - Salta a tus pestañas abiertas, marcadores e historial de navegación. - - Pestañas limpias y organizadas - - Elimina el desorden de pestañas con un diseño mejorado y cierre automático. - - Búsquedas recientes - - - Revisa tus últimas búsquedas desde tú página de inicio y pestañas. - - - Tú página de inicio personalizada de Firefox ahora hace que sea más fácil continuar donde lo dejaste. Encuentra tus pestañas, marcadores y resultados de búsqueda recientes. + + Busca esta vez: + + Esta vez buscar en: + + Conoce tu página de inicio personalizada. Las pestañas recientes, marcadores y resultados de búsqueda aparecerán aquí. - Te damos la bienvenida a un internet independiente - Te damos la bienvenida a un internet más personal Más colores. Mejor privacidad. Mismo compromiso con las personas por encima de los beneficios. - Cambia del teléfono a la computadora y viceversa - Cambiar de pantalla es más fácil que nunca Continuar donde lo dejaste con pestañas de otros dispositivos ahora en tu página de inicio. @@ -303,6 +281,9 @@ ¡Tus pestañas se están sincronizando! Continua donde te quedaste en otro dispositivo. + + Cerrar + Abrir una nueva pestaña en %1$s @@ -353,6 +334,14 @@ Agregar acceso directo a navegación privada Modo solo HTTPS + + + Reducción de banner de cookies + + Reducir banners de cookies + + Firefox intenta rechazar automáticamente las solicitudes de cookies en los banners de cookies. Si una opción de rechazo no está disponible, Firefox puede aceptar todas las cookies para descartar el banner. + Intentar conectarse automáticamente a sitios que utilizan el protocolo de encriptación HTTPS para mayor seguridad. @@ -392,8 +381,6 @@ Personalizar - Sincronizar marcadores, historial y más con tu cuenta de Firefox - Inicia sesión para sincronizar pestañas, marcadores, contraseñas y más. Cuenta de Firefox @@ -462,8 +449,12 @@ Visitados recientemente - Pocket + Pocket + + Historias que invitan a la reflexión + + Artículos desarrollados por %s Historias patrocinadas @@ -488,12 +479,6 @@ No se pudo cambiar el fondo de pantalla Saber más - - Cambia el fondo de pantalla tocando el logotipo de la página de inicio de Firefox - - - Logotipo de Firefox - cambiar el fondo de pantalla, botón Clásico %s @@ -590,8 +575,6 @@ Permite a Mozilla instalar y ejecutar estudios - - Activar Sync Sincroniza y guarda tu información @@ -652,6 +635,17 @@ Cerrar + + ¿Abrir %d pestañas? + + Abrir varias pestañas puede ralentizar a %s mientras se cargan las páginas. ¿Estás seguro de que deseas continuar? + + Abrir pestañas + + Cancelar + %d sitio @@ -681,10 +675,6 @@ Lista Cuadrícula - - Buscar en grupos - - Agrupar sitios relacionados Cerrar pestañas @@ -808,9 +798,6 @@ %1$s (Modo Privado) - - Otras pestañas - Ingresa los términos de búsqueda @@ -838,18 +825,6 @@ No hay ningún historial - - Sincronizado desde otros dispositivos - - Desde otros dispositivos - - - Inicia sesión para ver el historial sincronizado desde tus otros dispositivos. - - Iniciar sesión - - O crea una cuenta de Firefox para comenzar a sincronizar]]> - Descargas removidas @@ -899,6 +874,10 @@ Abrir en una nueva pestaña Abrir en una pestaña privada + + Abrir todo en pestañas nuevas + + Abrir todo en pestañas privadas Eliminar @@ -1076,6 +1055,10 @@ Compartir + + Guardar como PDF + + No se puede generar PDF Enviar a dispositivo @@ -1087,9 +1070,11 @@ Copiado al portapapeles - Iniciar sesión para sincronizar + Iniciar sesión para sincronizar Iniciar sesión en Sync + + Sincronizar y guardar datos Enviar a todos los dispositivos @@ -1126,6 +1111,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Haz que %1$s sea tu navegador predeterminado + + Prueba la navegación privada + + Navega sin guardar cookies ni historial en %1$s + Colección eliminada @@ -1214,8 +1205,6 @@ Salir - - Se eliminarán todos tus datos de navegación. Rango de tiempo a eliminar @@ -1249,33 +1238,20 @@ Grupo eliminado - - ¡Te damos la bienvenida a %s! Te damos la bienvenida a un mejor internet Un navegador creado para las personas, no para las ganancias. - - Sincronizar Firefox entre dispositivos Continúa donde lo dejaste - - Lleva marcadores, historial y contraseñas a %1$s en este dispositivo. Sincroniza pestañas y contraseñas entre dispositivos para cambiar de pantalla sin problemas. - - Registrarse Iniciar sesión Sync está activado - - Privacidad siempre activada Protección a tu privacidad de forma predeterminada - - %1$s automáticamente detiene compañías que secretamente te siguen en la web. Cuenta con protección total de cookies para evitar que los rastreadores las usen para espiarte cuando navegues. @@ -1289,18 +1265,11 @@ Bloquea más rastreadores para que las páginas se carguen más rápido, pero pueden fallar algunas funcionalidades de la página. Escoge la posición de la barra de herramientas - - Coloca la barra de herramientas al alcance de la mano. Mantenla en la parte inferior o muévela hacia arriba. Manténlo en la parte inferior o muévelo a la parte superior. - - Tu privacidad Tu controlas tus datos - - Hemos diseñado %s para darte el control sobre lo que compartes en línea y lo que compartes con nosotros. Firefox te da control sobre lo que compartes en línea y lo que compartes con nosotros. @@ -1937,7 +1906,9 @@ Descubrir más - Desarrollado por Pocket. + Desarrollado por Pocket. + + Impulsado por %s. Parte de la familia Firefox. %s @@ -1951,4 +1922,14 @@ Ir a la configuración Firefox Suggest + + + + contraer + + aumentar + + abrir enlace para saber más sobre esta colección + + leer el artículo diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c5c1b44c6..bf3352b7a 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -17,6 +17,12 @@ Buscar o escribir dirección + + Buscar en el historial + + Buscar marcadores + + Buscar pestañas Introducir términos de búsqueda @@ -42,9 +48,6 @@ Seleccionada - - Marcadores recientes - Guardado recientemente @@ -134,13 +137,6 @@ Mostrar el botón de todas las pestañas recientes - - Tu búsqueda por \"%1$s\" - - - %d sitios Ver todas las pestañas sincronizadas @@ -264,37 +260,19 @@ Configuración de búsquedas - - - Novedades de %1$s - - Ahora es más fácil continuar donde lo habías dejado. - - Página de inicio de %1$s personalizada - - Accede a tus pestañas abiertas, marcadores y al historial de navegación. - - Pestañas claras y organizadas - - Elimina el desorden de pestañas con un diseño mejorado y con cierre automático. - - Búsquedas recientes - - Revisa tus últimas búsquedas desde tu página de inicio y pestañas. - - - Tu página de inicio de Firefox personalizada hace que ahora sea más fácil continuar donde lo habías dejado. Encuentra tus pestañas, marcadores y resultados de búsqueda recientes. + + Buscar esta vez: + + + Esta vez buscar en: + Descubre tu página de inicio personalizada. Las pestañas recientes, marcadores y resultados de búsqueda aparecerán aquí. - Te damos la bienvenida a un internet independiente - Te damos la bienvenida a un Internet más personal Más colores. Mejor privacidad. Mismo compromiso con las personas por encima de los beneficios. - - Salta del teléfono al ordenador y viceversa Cambiar de pantalla es más fácil que nunca @@ -309,6 +287,9 @@ ¡Tus pestañas se están sincronizando! Continúa donde lo dejaste en otro dispositivo. + + Cerrar + Abrir una pestaña nueva de %1$s @@ -360,6 +341,14 @@ Agregar acceso directo a navegación privada Modo solo HTTPS + + + Reducción de avisos de cookies + + Reducir los avisos de cookies + + Firefox intenta rechazar automáticamente las solicitudes de cookies en los avisos de cookies. Si no está disponible una opción de rechazo, Firefox podría aceptar todas las cookies para cerrar el aviso. + Intenta conectarse automáticamente a sitios utilizando el protocolo de cifrado HTTPS para mayor seguridad. @@ -467,8 +456,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitados recientemente - Pocket + Pocket + + Historias que te hacen reflexionar + + Artículos impulsados por %s Historias patrocinadas @@ -491,11 +484,6 @@ No se ha podido cambiar el fondo de pantalla Saber más - - Cambia el fondo de pantalla tocando el logotipo de la página de inicio de Firefox - - Logotipo de Firefox - cambiar el fondo de pantalla, botón %s clásico @@ -655,6 +643,17 @@ Cerrar + + ¿Abrir %d pestañas? + + Abrir tantas pestañas puede ralentizar %s mientras se cargan las páginas. ¿Estás seguro de que quieres continuar? + + Abrir pestañas + + Cancelar + %d sitio @@ -684,10 +683,6 @@ Lista Cuadrícula - - Buscar en grupos - - Agrupar sitios relacionados Cerrar pestañas @@ -840,18 +835,6 @@ No hay ningún historial - - Sincronizado desde otros dispositivos - - Desde otros dispositivos - - - Inicia sesión para ver una lista de pestañas de tus otros dispositivos. - - Iniciar sesión - - O crea una cuenta de Firefox para empezar a sincronizar]]> - Descargas eliminadas @@ -903,6 +886,10 @@ Abrir en una nueva pestaña Abrir en una pestaña privada + + Abrir todo en pestañas nuevas + + Abrir todo en pestañas privadas Eliminar @@ -1092,6 +1079,10 @@ Compartir + + Guardar como PDF + + No se puede generar PDF Enviar a dispositivo @@ -1103,9 +1094,11 @@ Copiado al portapapeles - Inicia sesión para sincronizar + Inicia sesión para sincronizar Iniciar sesión en Sync + + Sincronizar y guardar datos Enviar a todos los dispositivos @@ -1272,34 +1265,20 @@ Grupo eliminado - - ¡Te damos la bienvenida a %s! - Te damos la bienvenida a un mejor Internet Un navegador creado para las personas, no para el lucro. - - Sincronizar Firefox entre dispositivos Continúa donde lo dejaste. - - Traer marcadores, historial y contraseñas a %1$s en este dispositivo. Sincroniza pestañas y contraseñas entre dispositivos para cambiar de pantalla sin interrupciones. - - Registrarse Iniciar sesión Sync está activado - - Privacidad siempre activada Protección de privacidad de manera predeterminada - - %1$s bloquea automáticamente a las compañías que te siguen en secreto por la web. Incluye Total Cookie Protection para evitar que los rastreadores usen cookies para espiarte entre sitios. @@ -1312,17 +1291,10 @@ Bloquea más rastreadores para que las páginas se carguen más rápido, pero pueden fallar algunas funcionalidades de la página. Escoge la posición de la barra de herramientas - - Pon la barra de herramientas a tu alcance. Mantenla abajo, o muévela hacia arriba. Mantenlo en la parte inferior o muévelo a la parte superior. - - Tu privacidad Tú controlas tus datos - - Hemos diseñado %s para darte el control sobre lo que compartes en línea y lo que compartes con nosotros. Firefox te da control sobre lo que compartes en línea y lo que compartes con nosotros. @@ -1373,7 +1345,7 @@ Desconectar Cancelar - + No se pueden editar las carpetas predeterminadas @@ -1511,10 +1483,10 @@ Pegar e ir Pegar - + URL copiada al portapapeles - + Añadir a la pantalla de inicio @@ -1965,7 +1937,9 @@ Descubrir más - Desarrollado por Pocket. + Desarrollado por Pocket. + + Impulsado por %s. Parte de la familia Firefox. %s @@ -1979,4 +1953,14 @@ Ir a ajustes Firefox Suggest + + + + contraer + + expandir + + abrir enlace para saber más sobre esta colección + + leer el artículo diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 6f256d446..98f8e757c 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -15,6 +15,12 @@ Desgaitu nabigatze pribatua Bilatu edo idatzi helbidea + + Bilatu historia + + Bilatu laster-markak + + Bilatu fitxak Idatzi bilaketa-terminoak @@ -41,8 +47,6 @@ - Azken laster-markak - Gordetako azkenak Erakutsi gordetako laster-marka guztiak @@ -131,13 +135,6 @@ Azken fitxa guztiak erakusteko botoia - - Zure bilaketa: \"%1$s\" - - - %d gune Ikusi sinkronizatutako fitxa guztiak @@ -261,38 +258,19 @@ Bilaketa-ezarpenak - - - %1$s(r)en nobedadeak - - Errazagoa da orain utzi zenuen tokitik jarraitzea. - - %1$s hasiera-orri pertsonalizatua - - Saltatu irekitako zure fitxa, laster-marka eta nabigazio-historiara. - - Fitxa txukun eta antolatuak - - Kendu soberan dagoena hobetutako diseinu eta automatikoki ixten diren fitxekin. - - Azken bilaketak - - Itzuli zure azken bilaketetara zure hasiera-orri eta fitxetatik. - - - Errazagoa da utzitako lekutik jarraitzea Firefoxen pertsonalizatutako hasiera-orriarekin. Aurkitu zure azken fitxak, laster-markak eta bilaketa-emaitzak. + + Oraingoan, bilatu: + + Oraingoan, bilatu honekin: + Ezagut ezazu zure hasiera-orri pertsonalizatua. Azken fitxak, laster-markak eta bilaketa-emaitzak hemen agertuko dira. - Ongi etorri Internet independente batera - Ongi etorri Internet pertsonalago batera Kolore gehiago. Pribatutasun hobea. Irabazi-asmoen gainetik, jendearekiko betidaniko konpromisoa. - Egin salto telefonotik ordenagailu eramangarrira eta atzera - Pantailak aldatzea inoiz baino errazagoa da Berrekin utzitako lekutik zure hasierako orriko beste gailuetako fitxekin. @@ -306,6 +284,9 @@ Zure fitxak sinkronizatzen ari dira! Jarraitu zure beste gailuan utzi zenuen tokitik. + + Itxi + Ireki %1$s fitxa berria @@ -355,6 +336,15 @@ Gehitu nabigatze pribaturako lasterbidea HTTPS-Only modua + + + Cookie iragarki-banden murrizpena + + Murriztu cookie iragarki-bandak + + + Firefox automatikoki saiatzen da cookie iragarki-bandetako eskaerak ukatzen. Ukatzeko aukera ez badago erabilgarri, Firefoxek cookie guztiak onar litzake iragarki-banda baztertzeko. + Automatikoki saiatzen da guneetara konektatzen HTTPS zifratze-protokoloa erabiliz, segurtasun gehiago lortzeko. @@ -462,8 +452,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Bisitatutako azkenak - Pocket + Pocket + + Hausnartzeko moduko istorioak + + %s(e)k hornitutako artikuluak Babesleen istorioak @@ -486,11 +480,6 @@ Ezin da horma-papera aldatu Argibide gehiago - - Aldatu horma-papera Firefoxen hasiera-orriko logoa sakatuz - - Firefox logoa - aldatu horma-papera, botoia %s klasikoa @@ -652,6 +641,17 @@ Itxi + + Ireki %d fitxa? + + Hainbeste fitxa irekitzeak %s moteldu dezake orriak kargatzen diren bitartean. Ziur zaude jarraitu nahi duzula? + + Ireki fitxak + + Utzi + Gune bat @@ -681,10 +681,6 @@ Zerrenda Sareta - - Bilaketa-taldeak - - Taldekatu antzerako guneak Itxi fitxak @@ -835,18 +831,6 @@ Historiarik ez hemen - - Beste gailuetatik sinkronizatuta - - Beste gailuetakoa - - - Hasi saioa zure beste gailuetatik sinkronizatutako historia ikusteko. - - Hasi saioa - - Edo sortu Firefox kontua sinkronizatzen hasteko]]> - Deskargak kenduta @@ -896,6 +880,10 @@ Ireki fitxa berrian Ireki fitxa pribatuan + + Ireki guztiak fitxa berrietan + + Ireki guztiak fitxa pribatuetan Ezabatu @@ -1075,6 +1063,10 @@ Partekatu + + Gorde PDF gisa + + Ezin da PDFa sortu Bidali gailura @@ -1086,9 +1078,11 @@ Arbelean kopiatuta - Hasi saioa sinkronizatzeko + Hasi saioa sinkronizatzeko Hasi saioa Sync-en + + Sinkronizatu eta gorde datuak Bidali gailu guztietara @@ -1248,34 +1242,21 @@ Taldea ezabatuta - - Ongi etorri %s(e)ra! Ongi etorri Internet hobeago batera Herriarentzat egindako nabigatzailea, ez irabazi-asmoentzat. - - Sinkronizatu Firefox gailuen artean Jarraitu utzi zenuen tokitik - - Ekarri laster-markak, historia eta pasahitzak gailu honetako %1$s(e)ra. Sinkronizatu gailuen artean fitxak eta pasahitzak, pantailen artean di-da aldatzeko. - - Eman izena Hasi saioa Sinkronizazioa aktibo dago - - Pribatutasuna beti aktibo Pribatutasunaren babesa lehenespenez - - %1$s(e)k automatikoki eragozten du konpainiek sekretuki zu webean zehar jarraitzea. Cookien erabateko babesarekin, jarraipen-elementuei guneen artean zelatatzen zaituzten cookieak erabiltzea galarazten zaie. @@ -1288,17 +1269,10 @@ Jarraipen-elementu gehiago blokeatzen ditu orriak azkarrago karga daitezen baina orriko zenbait eginbide hauts litezke. Hautatu tresna-barraren kokapena - - Izan tresna-barra esku-eskura. Manten ezazu behean edo eraman ezazu gora. Manten ezazu behean edo eramazu gora. - - Zure pribatutasuna Zuk kontrolatzen dituzu zure datuak - - Online partekatzen duzunaren eta gurekin partekatzen duzunaren inguruko kontrola emateko diseinatu dugu %s. Online partekatzen duzunaren eta gurekin partekatzen duzunaren inguruko kontrola ematen dizu Firefoxek. @@ -1478,7 +1452,7 @@ The first parameter is number of long clicks left to enable the menu --> Arazketa-menua: %1$d klik falta dira gaitzeko Arazketa-menua gaituta - + Kopiatu @@ -1489,7 +1463,7 @@ URLa arbelean kopiatu da - + Gehitu hasierako pantailan @@ -1934,7 +1908,9 @@ Aurkitu gehiago - Pocket-ek hornitua. + Pocket-ek hornitua. + + %s(e)k hornitua. Firefoxen familiakoa. %s @@ -1948,4 +1924,14 @@ Joan ezarpenetara Firefoxen iradokizunak + + + + tolestu + + zabaldu + + ireki lotura bilduma honi buruzko argibide gehiagorako + + irakurri artikulua diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index a9dec0061..70cca99f6 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -16,6 +16,12 @@ Poista yksityinen selaus käytöstä Hae tai kirjoita osoite + + Etsi historiasta + + Etsi kirjanmerkeistä + + Etsi välilehdistä Kirjoita hakuehdot @@ -41,8 +47,6 @@ - Viimeisimmät kirjanmerkit - Äskettäin tallennettu Näytä kaikki tallennetut kirjanmerkit @@ -132,13 +136,6 @@ Näytä kaikki viimeisimmät välilehdet -painike - - Hakusi ehdoilla \"%1$s\" - - - %d sivustoa Näytä kaikki synkronoidut välilehdet @@ -263,38 +260,20 @@ Hakuasetukset - - - Mitä uutta %1$s sisältää - - Nyt on aiempaa helpompaa jatkaa siitä, mihin jäit. - - Personoitu %1$s-kotisivu - - Siirry avoimiin välilehtiisi, kirjanmerkkeihisi ja selaushistoriaasi. - - Siistit, järjestetyt välilehdet - - Estä välilehtien sotku parannetulla asettelulla ja automaattisesti sulkeutuvilla välilehdillä. - - Viimeisimmät haut - - Palaa viimeisimpiin hakuihin etusivultasi ja välilehdiltäsi. - - - Sinulle mukautetun Firefox-kotisivun avulla on helpompi jatkaa siitä, mihin jäit. Löydä viimeisimmät välilehdet, kirjanmerkit ja hakutulokset. + + Tällä kertaa hae: + + Tällä kertaa hae: + + Tutustu henkilökohtaiseen kotisivuusi. Viimeisimmät välilehdet, kirjanmerkit ja hakutulokset näkyvät tässä. - Tervetuloa itsenäiseen internetiin - Tervetuloa entistä henkilökohtaisempaan internetiin Lisää värejä. Parempi yksityisyys. Ihmisiin sitoutumisen priorisointi liikevoittojen edelle. - Hyppää puhelimelta kannettavalle tietokoneelle ja takaisin - Näyttöjen vaihtaminen on helpompaa kuin koskaan Jatka siitä, mihin jäit muiden laitteidesi välilehdillä. @@ -308,6 +287,9 @@ Välilehtiäsi synkronoidaan! Jatka siitä, mihin jäit toisella laitteellasi. + + Sulje + Avaa uusi %1$s-välilehti @@ -359,6 +341,14 @@ Lisää yksityisen selauksen pikakuvake Vain HTTPS -tila + + + Evästeilmoitusten vähennys + + Vähennä evästeisiin liittyviä ilmoituksia + + Firefox yrittää automaattisesti hylätä evästeilmoituksissa olevat evästepyynnöt. Jos hylkäysvaihtoehto ei ole käytettävissä, Firefox voi hyväksyä kaikki evästeet ilmoituksen poistamiseksi näkyvistä. + Yrittää muodostaa automaattisesti yhteyden sivustoihin käyttämällä salattua HTTPS-protokollaa turvallisuuden parantamiseksi. @@ -398,8 +388,6 @@ Mukauta - Synkronoi kirjanmerkit, historia ja paljon muuta Firefox-tilillä - Kirjaudu sisään synkronoidaksesi välilehtesi, kirjanmerkkisi, salasanasi ja muita tietoja. Firefox-tili @@ -468,8 +456,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Äskettäin vierailtu - Pocket + Pocket + + Ajatuksia herättäviä tarinoita + + Artikkelit tarjoaa %s Sponsoroidut tarinat @@ -493,12 +485,6 @@ Taustakuvaa ei voitu vaihtaa Lue lisää - - Vaihda taustakuvaa napauttamalla Firefoxin etusivun logoa - - - Firefox-logo - vaihda taustakuva, painike Klassinen %s @@ -597,8 +583,6 @@ Salli Mozillan asentaa ja suorittaa tutkimuksia - - Ota Sync käyttöön Synkronoi ja tallenna tietosi @@ -659,6 +643,17 @@ Sulje + + Avataanko %d välilehteä? + + Näin monen välilehden avaaminen voi hidastaa %sia sivujen latautuessa. Haluatko varmasti jatkaa? + + Avaa välilehdet + + Peruuta + %d sivusto @@ -688,10 +683,6 @@ Lista Ruudukko - - Hakuryhmät - - Ryhmitä toisiinsa liittyvät sivustot yhteen Sulje välilehdet @@ -818,9 +809,6 @@ %1$s (yksityinen tila) - - Muut välilehdet - Kirjoita hakuehdot @@ -849,19 +837,6 @@ Ei historiaa täällä - - Synkronoitu muilta laitteilta - - Muilta laitteilta - - - Kirjaudu sisään, jotta voit katsella historiaa synkronoituna muista laitteistasi. - - Kirjaudu sisään - - - Tai luo Firefox-tili aloittaaksesi synkronoinnin]]> - Lataukset poistettu @@ -911,6 +886,10 @@ Avaa uudessa välilehdessä Avaa yksityisessä välilehdessä + + Avaa kaikki uusissa välilehdissä + + Avaa kaikki yksityisissä välilehdissä Poista @@ -1090,6 +1069,10 @@ Jaa + + Tallenna PDF-muodossa + + PDF:n luominen ei onnistu Lähetä laitteeseen @@ -1101,9 +1084,11 @@ Kopioitu leikepöydälle - Kirjaudu Sync-palveluun + Kirjaudu Sync-palveluun Kirjaudu sisään Synciin + + Synkronoi ja tallenna tiedot Lähetä kaikkiin laitteisiin @@ -1140,6 +1125,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Aseta %1$s oletusselaimeksi + + Kokeile yksityistä selaamista + + %1$s mahdollistaa selaamisen ilman evästeiden tai historian tallentamista + Kokoelma poistettu @@ -1233,9 +1224,6 @@ Lopeta - - Kaikki selaustietosi poistetaan. - Tyhjennettävä aikajakso @@ -1269,33 +1257,20 @@ Ryhmä poistettu - - Tervetuloa %siin! Tervetuloa parempaan internetiin Selain, joka on tehty ihmisiä, ei tuottoa, varten. - - Synkronoi Firefox laitteidesi välillä Jatka siitä mihin jäit - - Tuo kirjanmerkit, historia ja salasanat %1$siin tässä laitteessa. Synkronoi välilehdet ja salasanat eri laitteiden välillä, jotta laitteen vaihtaminen on saumatonta. - - Rekisteröidy Kirjaudu sisään Sync on käytössä - - Yksityisyys aina päällä Yksityisyyden suoja oletuksena - - %1$s estää automaattisesti yrityksiä seuraamasta sinua salaa ympäri verkkoa. Totaalinen evästesuoja estää seuraimia käyttämästä evästeitä vaanimiseen sivustojen välillä. @@ -1308,17 +1283,10 @@ Estää enemmän seuraimia, joten sivut latautuvat nopeammin, mutta jotkin sivujen toiminnot saattavat rikkoutua. Valitse työkalupalkin sijoitus - - Sijoita työkalupalkki helposti ulottuville. Pidä se alhaalla tai siirrä se ylös. Pidä se alhaalla tai siirrä se ylös. - - Yksityisyytesi Sinä hallitset tietojasi - - Olemme suunnitelleet %sin siten, että voit hallita mitä jaat verkossa ja mitä jaat kanssamme. Firefoxin avulla voit hallita, mitä jaat verkossa ja mitä jaat kanssamme. @@ -1498,7 +1466,7 @@ The first parameter is number of long clicks left to enable the menu --> Vianjäljitysvalikko: napsautuksia jäljellä %1$d Vianjäljitysvalikko käytössä - + Kopioi @@ -1506,10 +1474,10 @@ Liitä ja avaa Liitä - + Osoite kopioitu leikepöydälle - + Lisää aloitusnäytölle @@ -1958,7 +1926,9 @@ Löydä lisää - Taustavoimana Pocket. + Taustavoimana Pocket. + + Mahdollistajana %s. Osa Firefox-perhettä. %s @@ -1972,4 +1942,14 @@ Siirry asetuksiin Firefox-ehdotukset + + + + supista + + laajenna + + avataksesi linkin, josta saat lisätietoja tästä kokoelmasta + + lukeaksesi artikkelin diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 81a77f602..f70689e8a 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,6 +17,12 @@ Recherche ou adresse + + Rechercher dans l’historique + + Rechercher dans les marque-pages + + Rechercher dans les onglets Saisissez les termes à rechercher @@ -42,8 +48,6 @@ - Marque-pages récents - Récemment enregistrés Afficher tous les marque-pages enregistrés @@ -131,13 +135,6 @@ Afficher le bouton des onglets récents - - Votre recherche de « %1$s » - - - %d sites Voir tous les onglets synchronisés @@ -261,39 +258,20 @@ Paramètres de recherche - - - Nouveautés dans %1$s - - Il est désormais plus facile de reprendre là où vous en étiez. - - Accueil personnalisé de %1$s - - Accédez à vos onglets ouverts, vos marque-pages et votre historique de navigation. - - Onglets nets et organisés - - Éliminez le fouillis d’onglets grâce à une présentation améliorée et des onglets qui se ferment automatiquement. - - Recherches récentes - - - Consultez vos dernières recherches depuis votre page d’accueil et vos onglets. - - - L’accueil personnalisé de Firefox permet désormais de reprendre plus facilement là où vous en étiez. Retrouvez vos onglets, marque-pages et résultats de recherche récents. + + Pour cette recherche : + + Pour cette recherche : + + Découvrez votre page d’accueil personnalisée. Onglets récents, marque-pages et résultats de recherche y apparaissent. - Bienvenue sur un Internet indépendant - Bienvenue sur un Internet plus personnel Plus de couleurs. Une confidentialité améliorée. Mais toujours le même engagement pour les gens plutôt que pour les profits. - Passez du téléphone à l’ordinateur portable et vice-versa - Passer d’un écran à l’autre est plus facile que jamais Reprenez là où vous en étiez avec des onglets d’autres appareils qui figurent désormais sur votre page d’accueil. @@ -307,6 +285,9 @@ Vos onglets sont synchronisés ! Reprenez là vous en étiez sur votre autre appareil. + + Fermer + Ouvrir un nouvel onglet %1$s @@ -357,6 +338,14 @@ Ajouter un raccourci pour la navigation privée Mode HTTPS uniquement + + + Réduction des bannières de cookies + + Réduire les bannières de cookies + + Firefox essaie automatiquement de refuser les demandes de dépôt de cookies quand une bannière de cookies s’affiche. Si aucune option de rejet n’est disponible, Firefox peut accepter tous les cookies pour fermer la bannière. + Essayer de se connecter automatiquement aux sites en utilisant le protocole de chiffrement HTTPS pour une sécurité accrue. @@ -464,8 +453,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visités récemment - Pocket + Pocket + + Des articles qui font réfléchir + + Articles mis en avant par %s Articles sponsorisés @@ -488,12 +481,6 @@ Impossible de changer le fond d’écran En savoir plus - - Changez le fond d’écran en appuyant sur le logo Firefox de la page d’accueil - - - Logo Firefox - changer le fond d’écran, bouton %s classique @@ -654,6 +641,17 @@ Fermer + + Ouvrir %d onglets ? + + Ouvrir autant d’onglets pourrait ralentir %s lors du chargement des pages. Voulez-vous vraiment continuer ? + + Ouvrir les onglets + + Annuler + %d site @@ -683,10 +681,6 @@ Liste Grille - - Groupes de recherches - - Regrouper les sites liés Fermer les onglets @@ -840,18 +834,6 @@ Pas d’historique - - Synchronisé depuis d’autres appareils - - Depuis d’autres appareils - - - Connectez-vous pour consulter l’historique synchronisé à partir de vos autres appareils. - - Se connecter - - Ou créer un compte Firefox pour lancer la synchronisation]]> - Téléchargements supprimés @@ -903,6 +885,10 @@ Ouvrir dans un nouvel onglet Ouvrir dans un onglet privé + + Tout ouvrir dans de nouveaux onglets + + Tout ouvrir dans des onglets privés Supprimer @@ -1093,6 +1079,10 @@ Partager + + Enregistrer en PDF + + Impossible de générer le PDF Envoyer à l’appareil @@ -1104,9 +1094,11 @@ Copié dans le presse-papiers - Se connecter pour synchroniser + Se connecter pour synchroniser Se connecter à Sync + + Synchroniser et enregistrer les données Envoyer à tous les appareils @@ -1144,6 +1136,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Faites de %1$s votre navigateur par défaut + + Essayez la navigation privée + + Naviguez sans enregistrer ni cookies ni historique dans %1$s + Collection supprimée @@ -1272,35 +1270,21 @@ Groupe supprimé - - Bienvenue dans %s ! - Bienvenue dans un meilleur Internet Un navigateur conçu pour les gens, pas pour l’argent. - - Synchronisez Firefox entre vos appareils Reprenez là où vous en étiez - - Importez vos marque-pages, votre historique et vos mots de passe dans %1$s sur cet appareil. Synchronisez onglets et mots de passe entre vos appareils pour passer d’un écran à l’autre sans accroc. - - Se connecter Connexion Synchronisation activée - - Confidentialité toujours assurée Protection de la vie privée par défaut - - %1$s empêche automatiquement les entreprises de vous suivre secrètement sur le Web. La protection totale contre les cookies incluse empêche les traqueurs d’utiliser des cookies pour vous pister de site en site. @@ -1313,17 +1297,10 @@ Bloque davantage de traqueurs, accélérant le chargement des pages, mais quelques dysfonctionnements peuvent s’ensuivre. Choisissez l’emplacement de votre barre d’outils - - Placez la barre d’outils à portée de main. Laissez-la en bas ou déplacez-la en haut. Conservez-la en bas ou déplacez-la en haut. - - Votre vie privée Vous gardez le contrôle de vos données - - Nous avons conçu %s pour vous donner le contrôle de ce que vous partagez en ligne et de ce que vous partagez avec nous. Firefox vous donne le contrôle de ce que vous partagez en ligne et de ce que vous partagez avec nous. @@ -1510,10 +1487,10 @@ Coller et ouvrir Coller - + Adresse copiée dans le presse-papiers - + Ajouter à l’écran d’accueil @@ -1959,7 +1936,9 @@ En découvrir davantage - Fonctionne grâce à Pocket. + Fonctionne grâce à Pocket. + + Mis en avant par %s. Membre de la famille Firefox. %s @@ -1973,4 +1952,14 @@ Ouvrir les paramètres Firefox suggère + + + + réduire + + développer + + ouvrir le lien pour en savoir plus sur cette collection + + lire l’article diff --git a/app/src/main/res/values-fy-rNL/strings.xml b/app/src/main/res/values-fy-rNL/strings.xml index 2f9286d0b..9a3467602 100644 --- a/app/src/main/res/values-fy-rNL/strings.xml +++ b/app/src/main/res/values-fy-rNL/strings.xml @@ -14,6 +14,12 @@ Priveenavigaasje útskeakelje Fier sykterm of adres yn + + Skiednis trochsykje + + Blêdwizers trochsykje + + Ljepblêden trochsykje Fier syktermen yn @@ -39,8 +45,6 @@ - Resinte blêdwizers - Koartlyn bewarre Alle bewarre blêdwizers toane @@ -56,9 +60,9 @@ The first parameter is the name of the app defined in app_name (for example: Fenix) --> %1$s wisket jo syk- en browserskiednis sa gau as jo de tapassing ôfslute of alle priveeljepblêden slute. Hoewol dit jo net anonym makket foar websites of jo ynternetprovider, makket dit it makliker om wat jo online dogge privee te hâlden tsjinoer oaren dy’t dit apparaat brûke. - + Faaks hearde myten oer priveenavigaasje - + @@ -131,13 +135,6 @@ Knop Alle resinte ljepblêden toane - - Jo sykopdracht nei ‘%1$s’ - - - %d websites Alle syngronisearre ljepblêden besjen @@ -260,38 +257,20 @@ Sykynstellingen - - - Wat is der nij yn %1$s - - It is no ienfâldiger fierder te gean wêr’t jo bleaun wiene. - - Personalisearre %1$s-startside - - Spring nei jo iepen ljepblêden, blêdwizers en navigaasjeskiednis. - - Kreaze, oardere ljepblêden - - Smyt ljepblêdrommel fuort mei in ferbettere opmaak en automatysk slutende ljepblêden. - - Resinte sykopdrachten - - Besjoch jo lêste sykopdrachten opnij fan jo startside en ljepblêden ôf. - - - Jo personalisearre Firefox-startside makket it no ienfâldiger om fierder te gean wêr’t jo bleaun wiene. Fyn jo resinte ljepblêden, blêdwizers, en sykresultaten. + + Diskear sykje yn: + + + Diskear sykje yn: + Kom yn de kunde mei jo personalisearre startside. Resinte ljepblêden, blêdwizers en sykresultaten wurde hjir werjûn. - Wolkom by in ûnôfhinklik ynternet - Wolkom by in mear persoanlike ynternet Mear kleuren. Bettere privacy. Deselde ynset foar minsken boppe winst. - Ljep fan telefoan nei laptop en tebek - Fan skermen wikselje is makliker as ea Gean fan jo startside ôf fierder wêr’t jo stoppe binne mei ljepblêden fan oare apparaten. @@ -305,6 +284,9 @@ Jo ljepblêden wurde syngronisearre! Gean fierder wêr’t jo bleaun wiene op jo oare apparaat. + + Slute + In nij %1$s-ljepblêd iepenje @@ -354,6 +336,14 @@ Fluchkeppeling nei priveenavigaasje tafoegje Allinnich-HTTPS-modus + + + Reduksje fan cookiebanners + + Cookiebanners redusearje + + Firefox probearret automatysk cookie-oanfragen op cookiebanners te wegerjen. As der gjin wegeringsopsje beskikber is, akseptearret Firefox mooglik alle cookies om de banner te sluten. + Probearret foar in bettere befeiliging automatysk mei it HTTPS-fersiferingsprotokol ferbining te meitsjen mei websites. @@ -393,8 +383,6 @@ Oanpasse - Syngronisearje blêdwizers, skiednis en mear mei jo Firefox-account - Meld jo oan om jo ljepblêden, blêdwizers, wachtwurden en mear te syngronisearjen. Firefox-account @@ -463,8 +451,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Koartlyn besocht - Pocket + Pocket + + Ferhalen dy’t ta neitinken stimme + + Artikelen mooglik makke troch %s Sponsore ferhalen @@ -487,12 +479,6 @@ Kin eftergrûn net wizigje Mear ynfo - - Wizigje jo eftergrûn troch op it Firefox-startsidelogo te tikken - - - Firefox-logo – de eftergrûn, de knop wizigje Klassike %s @@ -589,8 +575,6 @@ Stelt Mozilla yn steat om ûndersiken te ynstallearjen en út te fieren - - Sync ynskeakelje Syngronisearje en jo gegevens bewarje @@ -650,6 +634,17 @@ Slute + + %d ljepblêden iepenje? + + As jo safolle ljepblêden iepenje, kin dit %s fertrage wylst it laden fan de siden. Binne jo wis dat jo trochgean wolle? + + Ljepblêden iepenje + + Annulearje + %d website @@ -679,10 +674,6 @@ List Roaster - - Groepen sykje - - Relatearre websites groepearje Ljepblêden slute @@ -805,9 +796,6 @@ %1$s (priveemodus) - - Oare ljeplêden - Fier syktermen yn @@ -835,18 +823,6 @@ Gjin skiednis hjir - - Syngronisearre fan oare apparaten ôf - - Fan oare apparaten ôf - - - Meld jo oan om fan jo oare apparaten syngronisearre skiednis te besjen. - - Oanmelde - - Of meitsje in Firefox-account om te begjinnen mei syngronisaasje]]> - Downloads fuortsmiten @@ -896,6 +872,10 @@ Iepenje yn nij ljepblêd Iepenje yn priveeljepblêd + + Alles yn nije ljepblêden iepenje + + Alles yn proveeljepblêden iepenje Fuortsmite @@ -1072,6 +1052,10 @@ Diele + + Bewarje as PDF + + Kin PDF net oanmeitsje Ferstjoere nei apparaat @@ -1083,9 +1067,11 @@ Kopiearre nei klamboerd - Oanmelde om te syngronisearjen + Oanmelde om te syngronisearjen Oanmelde by Sync + + Syngronisearje en gegevens bewarje Ferstjoere nei alle apparaten @@ -1122,6 +1108,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s jo standertbrowser meitsje + + Probearje priveenavigaasje + + Sneupje sûnder bewarre cookies of skiednis yn %1$s + Kolleksje fuortmsiten @@ -1212,8 +1204,6 @@ Ofslute - - Hjirtroch wurde al jo navigaasjegegevens fuortsmiten. Te wiskjen tiidrek @@ -1246,33 +1236,20 @@ Groep fuortsmiten - - Wolkom by %s! Wolkom by in better ynternet In browser dy’t boud is foar minsken, net foar winst. - - Syngronisearje Firefox tusken apparaten Gean troch wêr’t jo bleaun wiene - - Bring blêdwizers, skiednis en wachtwurden nei %1$s op dit apparaat. Syngronisearje ljepblêden en wachtwurden op ferskate apparaten foar maklik wikseljen tusken skermen. - - Registrearje Oanmelde Syngronisaasje is ynskeakele - - Privacy dy’t altyd oan stiet Standert privacybeskerming - - %1$s soarget der automatysk foar dat bedriuwen jo net stikem folgje op ynternet. Mei Totale cookiebeskerming om foar te kommen dat trackers cookies brûke om jo stikem op it ynternet te folgjen. @@ -1285,19 +1262,10 @@ Blokkearret mear trackers, sadat siden rapper laden wurde, mar guon funksjonaliteit op in side wurket mooglik net. Kies jo arkbalkepleatsing - - Pleats de arkbalke binnen hânberik. Hâld him ûnderoan of ferpleats him nei boppe. Hâld him ûnderoan, of ferpleats him nei boppe. - - Jo privacy Jo beheare jo gegevens - - Wy hawwe %s ûntwurpen om jo kontrôle te jaan oer wat jo online diele en wat jo mei ús diele. - - Firefox jout jo kontrôle oer wat jo online diele en wat jo mei ús diele. @@ -1937,7 +1905,9 @@ Mear ûntdekke - Mooglik makke troch Pocket. + Mooglik makke troch Pocket. + + Mooglik makke troch %s. Underdiel fan de Firefox-famylje. %s @@ -1951,4 +1921,14 @@ Nei Ynstellingen Firefox Suggestjes + + + + ynklappe + + útklappe + + keppeling iepenje foar mear ynfo oer dizze kolleksje + + it artikel te lêzen diff --git a/app/src/main/res/values-gn/strings.xml b/app/src/main/res/values-gn/strings.xml index 2e93c4254..b376dafef 100644 --- a/app/src/main/res/values-gn/strings.xml +++ b/app/src/main/res/values-gn/strings.xml @@ -16,6 +16,12 @@ Eheka térã ehai kundaharape + + Eheka tembiasakuépe + + Eheka techaukahápe + + Eheka tendayke Emoinge ñe’ẽ ehekaséva @@ -41,8 +47,6 @@ - Techaukaha ramoguáva - Oñeñongaturamóva Ehechaukapaite techaukaha ñongatupyre @@ -81,6 +85,9 @@ Mboyke + + + Ore rembiapo tekoñemigua iporãvéva omboyke tapykuehoha tendakuéra pa’ũme. Maranduve kookie ñemo’ã guasu rehegua @@ -129,13 +136,6 @@ Ehechauka votõ opaite tendayke ramoguápe - - Eheka \"%1$s\" rupive - - - %d tendakuéra Ehechapaite tendayke mbojuehepyre @@ -258,36 +258,23 @@ Mba’epytyvõrã jeheka - - - %1$s mba’epyahu - - Ko’ág̃a ndahasyive eku’ejeývo eheja haguégui. - - %1$s kuatiarogue ñepyrũgua mboavapyre - - Eike ne rendayke ijurujáva, techaukaha ha tembiasakue rembiasakue. - - Tendayke hesakã ha hendaporãva - - Emboguete tendayke oĩvaipáva oikoporãvéva ndive ha oñembotýva ha’eño. - - Ojeheka ramóva - - - Ehecha eheka ramovéva kuatiarogue ñepyrũ ha tendayke guive. - - - Nde kuatiarogue ñepyrũgua mboavapyre Firefox pegua nombohasyive eñepyrũjeývo eheja haguégui. Ejuhu ne rendayke, techaukaha ha ehekaramovéva. + + Eheka peteĩjey: - - Eg̃uahẽporãite ñanduti ijeheguívape + + Ko’ág̃a eheka amo: + + + + Ehecha nde kuatiarogue ñepyrũha. Umi tendayke ramovegua, techaukaha ha jeheka rapykuere oĩta ápe. Eg̃uahẽporãite ñanduti mba’eguáva - - Eva pumbyrýgui mohendahápe ha ambueháicha + + Sa’yve. Tekorosãve. Roykekove tapichakuérape roma’ẽ’ỹre virúre. Mba’erechaha ñemoambue ndahasyiete + + Eku’ejey eheja haguégui tendayke ambue mba’e’oka ndive nde kuatiarogue ñepyrũme. Eñepyrũ @@ -295,6 +282,11 @@ Jepo + + ¡Tendayke oñembojuehehína! Eku’ejey eheja haguégui ambue mba’e’okápe. + + Mboty + Embojuruja tendayke pyahu %1$s mba’e @@ -345,6 +337,15 @@ Embojuaju jeike pya’eha tendayke ñemiguáre HTTPS ayvúpe añoite + + + Kookie Banner Ñemomichĩ + + Emomichĩ kookie banner + + + Firefox omboykese ijehegui kookie mba’ejerure kookie banner ndive. Ndaipóriramo emboykekuaa hag̃ua, Firefox omoneĩkuaa opaite kookie omboyke hag̃ua pe banner. + Eñeha’ã eike hag̃ua tendakuérape eipurúvo pe taperekoite HTTPS ipapapýva tekorosãverã. @@ -384,8 +385,6 @@ Ñemomba’ete - Embojuehe techaukaha, tembiasakue ha mba’ete Firefox pegua ndive - Eñepyrũ tembiapo embojuehe hag̃ua tendayke, techaukaha, ñe’ẽñemi ha hetave. Firefox Account @@ -453,8 +452,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Ojeikeramohague - Pocket + Pocket + + Tembiasakue nemyakãngetáva + + Jehaipy oykekóva %s Tembiasakue jehepyme’ẽguáva @@ -478,23 +481,24 @@ Noñemoambuekuaái mba’erechaha rugua Kuaave - - Emoambue mba’erechaha rugua opokóvo Firefox kuatiarogue ñepyrũ ra’ãnga’i - - - Firefox ra’ãnga’i - emoambue mba’erechaha rugua, votõ Jepokuaa %s Ñemoheñói sa’íva + + Pe ñembyaty pyahu Voces Independientes. %s + + Pe ñembyaty pyahu Voces Independientes. Eipurukuaa sa’y sa’imi Eiporavo mba’erechaha rugua nde ehecharamóva. + + Ema’ẽjeyjey mba’erechaha ruguáre + Pe moĩmbaha ndojokupytýi @@ -577,8 +581,6 @@ Emoneĩ Mozilla-pe omohenda ha omongu’évo ñembokatupyry - - Emyandy Sync Embojuehe ha eñongatu mba’ekuaarã @@ -641,6 +643,17 @@ Mboty + + ¿Embojuruja %d tendayke? + + Embojurujávo heta tendayke omombeguekuaa %s henyhẽnguévo umi kuatiarogue. ¿Añetehápepa rehoseve hese? + + Embojuruja tendayke + + Heja + %d tenda @@ -670,10 +683,6 @@ Tysýi Kora’ieta - - Eheka atýhápe - - Ambyaty tenda ojueheguáva Emboty tendayke @@ -802,9 +811,6 @@ %1$s (Ayvu Ñemigua) - - Ambue tendayke - Emoinge ñe’ẽ ehekaséva @@ -834,20 +840,6 @@ Ndaipóri tembiasakue - - Oñembojuehepyre ambue mba’e’okáre - - - Ambue mba’e’oka guive - - - Eike ehecha hag̃ua tembiasakue mbojojapyre ambue nemba’e’okagua. - - Eñemboheraguapy - - - Térã emoheñói Firefox mba’ete embojuehe hag̃ua]]> - Ñemboguejy Mboguetepyre @@ -897,6 +889,10 @@ Embojuruja tendayke pyahu Embojuruja tendayke pyahúpe + + Embojurujapa tendayke pyahúpe + + Embojurujapa tendayke ñemíme Mboguete @@ -1077,6 +1073,10 @@ "Share" button. Opens the share menu when pressed. --> Moherakuã + + Eñongatu PDF ramo + + Nderejapokuaái PDF Emondo mba’e’okápe @@ -1089,9 +1089,11 @@ Emondo kuatiajohápe - Eike embojuehe hag̃ua + Eike embojuehe hag̃ua Eñepyrũ tembiapo Sync-pe + + Embojuehe ha eñongatu mba’ekuaarã Emondo opaite mba’e’okápe @@ -1130,6 +1132,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Ejapo %1$s kundahára ypyguávarõ + + Kundaha ñemi jepuru + + + Eikundaha kookie ha tembiasakue ñongatu’ỹre %1$s-pe + Ñembyatyha mboguetepyre @@ -1219,8 +1228,6 @@ Ñesẽ - - Oñemboguepáta opaite ne kundahára mba’ekuaarã. Pa’ũ embogue hag̃ua @@ -1256,25 +1263,20 @@ Aty mboguepyre - - ¡Eg̃uahẽporãite %s-pe! - - Embojuehe Firefox mba’e’oka pa’ũme - - Egueru techaukaha, tembiasakue ha ñe’ẽñemi %1$s-pe ko mba’e’okápe. - - Eñemboheraguapy + + Eg̃uahẽporãite ñanduti iporãvévape + + Kundahára heñóiva tapichápe g̃uarã, ndaha’éi virurã. + + Eku’ejey eheja haguégui + + Embojuehe tendayke ha ñe’ẽñemi mba’e’oka pa’ũme emoambue hag̃ua mba’erechaha oso’ỹre. Eñepyrũ tembiapo Sync oñemyandýma - - Tekoñemi hendymeme Omo’ã ñemigua ijeheguiete - - %1$s ojoko ijehegui umi atyguasúpe ani ohapykueho ñanduti rupive kañyhápe. Ñemo’ãmbaite kookie rovake omboyke tapykuehohápe oipurúvo kookie nde rapykueho hag̃ua ñandutípe. @@ -1287,19 +1289,18 @@ Ejoko tapykuehoha kuatiarogue henyhẽ pya’évape g̃uarã, hákatu ojavykuaáva peteĩva kuatiarogue rembiapoite. Eiporavo tembipuru renda oĩha - - Emoĩ tembipuru renda nde ykére. Eguereko yvy gotyo, térã emongu’e yvate gotyo. - - Ne ñemigua + + Ereko yvy gotyo térã emogu’e yvate gotyo. Ehechameme ne mba’ekuaarã - - Rojapo %s eñangareko hag̃ua emoherakuãva ñandutípe rehe ha emoherakuãva orendive avei. + + Firefox ome’ẽ ndéve pokatu emoherakuãva ñandutípe rehe ha emoherakuãva orendive avei. Emoñe’ẽ ore marandu’i ñemigua + + ¿Embojurujakuaáma ñanduti oikoitéva? Eñepyrũ eikundaha @@ -1417,6 +1418,8 @@ Kookie tenda ojuasáva Ejoko kookie oipurúva ñanduti marandugua ha mba’apohaguasu mba’ekuaarã resa’ỹijoha ombyatýva kundahára mba’ekuaarã oikévo tendápe. + + Ñemo’ãmbaite kookie rovake oreko kookie tenda reimehápe g̃uarã, avei tapykuehoha ndojepurukuaái ohapykueho hag̃ua tendakuéra pa’ũme. Criptominero @@ -1944,7 +1947,9 @@ Ejuhukuaave - Pocket omoheñoipyre. + Pocket omoheñoipyre. + + Omboguatáva %s. Firefox reheguaite. %s @@ -1958,4 +1963,14 @@ Eho ñembohekópe Firefox Kuave’ẽmby + + + + pa’ãmba + + myasãi + + embojuruja juajuha eikuaave hag̃ua ko ñembyaty + + emoñe’ẽ jehaipy diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml index 37ef3f0d9..7fc017d31 100644 --- a/app/src/main/res/values-hr/strings.xml +++ b/app/src/main/res/values-hr/strings.xml @@ -41,7 +41,9 @@ - Nedavne zabilješke + Nedavne zabilješke + + Nedavno spremljeno Prikaži sve spremljene zabilješke @@ -121,18 +123,13 @@ Prikaži tipku za prikaz svih nedavnih kartica - - Tvoja pretraga za \"%1$s\" - - - %d stranica Pogledaj sve sinkronizirane kartice Sinkronizirani uređaj + + Ukloni Ukloni @@ -249,24 +246,31 @@ - Što je novo u %1$s + Što je novo u %1$s - Sada je lakše nastaviti pregledavati web. + Sada je lakše nastaviti pregledavati web. - %1$s personalizirana početna stranica + %1$s personalizirana početna stranica - Skoči na svoje otvorene kartice, zabilješke i povijest pregledavanja. + Skoči na svoje otvorene kartice, zabilješke i povijest pregledavanja. - Čiste, organizirane kartice + Čiste, organizirane kartice - Očisti nered među karticama pomoću poboljšanog rasporeda i automatskog zatvaranja kartica. + Očisti nered među karticama pomoću poboljšanog rasporeda i automatskog zatvaranja kartica. - Nedavne pretrage + Nedavne pretrage - Ponovno pregledaj svoja posljednja pretraživanja na početnoj stranici i karticama. + Ponovno pregledaj svoja posljednja pretraživanja na početnoj stranici i karticama. - Tvoja personalizirana Firefoxova početna stranica sada ti olakšava da nastaviš pretraživati. Pronađi svoje nedavne kartice, zabilješke i rezultate pretraživanja. + Tvoja personalizirana Firefoxova početna stranica sada ti olakšava da nastaviš pretraživati. Pronađi svoje nedavne kartice, zabilješke i rezultate pretraživanja. + + + Prijavi se + + Preskoči + + Zatvori @@ -353,8 +357,6 @@ Geste Prilagodi - - Sinkroniziraj zabilješke, lozinke i ostalo sa svojim Firefox računom Firefox račun @@ -422,7 +424,7 @@ a section where users see a list of tabs that they have visited in the past few days --> Nedavno posjećeno - Pocket + Pocket Sponzorirane priče @@ -438,11 +440,11 @@ Pozadina ažurirana! Prikaži - - Promijeni sliku pozadine dodirom na logotip početne stranice Firefoxa - - Firefox logo - promijenite pozadinu, tipka + + + Pokušaj ponovo + + Saznaj više @@ -525,8 +527,6 @@ Omogućuje Mozilli instalaciju i pokretanje istraživanja - - Uključi sinkronizaciju Sinkronizirajte i spremite svoje podatke @@ -588,6 +588,11 @@ Zatvori + + Otvori kartice + + Odustani + %d stranica @@ -618,10 +623,6 @@ Popis Mreža - - Grupe pretraživanja - - Grupiraj povezane web-stranice Zatvori kartice @@ -727,8 +728,6 @@ Izbornik za otvorene kartice Spremi kartice u zbirku - - Izbornik za kartice Izbriši zbirku @@ -748,9 +747,6 @@ %1$s (privatni modus) - - Ostale kartice - Upiši pojmove pretrage @@ -781,15 +777,6 @@ Nema povijesti - - Sinkronizirano s drugih uređaja - - S drugih uređaja - - Prijava - - Ili stvorite Firefox račun za početak sinkronizacije]]> - Uklonjena preuzimanja @@ -1019,6 +1006,8 @@ Dijeli + + Spremi kao PDF Pošalji na uređaj @@ -1030,9 +1019,11 @@ Kopirano u međuspremnik - Prijavi se za sinkronizaciju + Prijavi se za sinkronizaciju Prijavi se za sinkronizaciju + + Sinkroniziraj i spremi podatke Pošalji na sve uređaje @@ -1157,9 +1148,6 @@ Zatvori - - Ovo će izbrisati sve tvoje podatke pregledavanja. - Vremenski opseg za brisanje @@ -1194,16 +1182,18 @@ - Dobro došao, dobro došla u %s! + Dobro došao, dobro došla u %s! - Sinkroniziraj Firefox između uređaja + Sinkroniziraj Firefox između uređaja - Registriraj se + Registriraj se + + Prijavi se Sinkronizacija je uključena - Uvijek uključena privatnost + Uvijek uključena privatnost Standardno (zadano) @@ -1215,13 +1205,13 @@ Odaberi položaj alatne trake - Stavi alatnu traku na dohvat ruke. Zadrži ju na dnu ili premjesti na vrh. + Stavi alatnu traku na dohvat ruke. Zadrži ju na dnu ili premjesti na vrh. - Tvoja privatnost + Tvoja privatnost - %s smo stvorili za jednostavno upravljanje podacima koje dijeliš na mreži i koje dijeliš s nama. + %s smo stvorili za jednostavno upravljanje podacima koje dijeliš na mreži i koje dijeliš s nama. Pročitaj naša pravila privatnosti @@ -1512,6 +1502,11 @@ Izbornik sortiranja prijava + + + Automatsko ispunjavanje + + Adrese Kreditne kartice @@ -1528,6 +1523,11 @@ Upravljaj spremljenim karticama + + Dodaj adresu + + Upravljaj adresama + Dodaj karticu @@ -1546,6 +1546,8 @@ Izbriši karticu Izbriši karticu + + Izbriši Spremi @@ -1577,6 +1579,52 @@ Otključ za korištenje spremljenih podataka o kreditnim karticama + + Dodaj adresu + + Uredi adresu + + Upravljaj adresama + + Ime + + Srednje ime + + Prezime + + Ulica + + Grad + + Država + + Pokrajina + + Poštanski broj + + Zemlja ili regija + + Telefon + + + E-mail adresa + + Spremi + + Odustani + + Izbriši adresu + + Stvano želiš izbrisati ovu adresu? + + Izbriši + + Odustani + + Spremi adresu + + Izbriši adresu + Dodaj tražilicu @@ -1646,6 +1694,10 @@ Bez izuzetih web-stranica Sigurno želiš izbrisati ovu zabilješku? + + Dodaj u prečace + + Ukloni iz prečaca Potvrđuje: %1$s @@ -1657,6 +1709,8 @@ Sigurno izbrisati ovu prijavu? Izbriši + + Odustani Opcije prijave @@ -1717,7 +1771,9 @@ Prečaci Naziv - + + Ime prečaca + U redu Odustani @@ -1735,6 +1791,11 @@ Zatvori sve neaktivne kartice + + Rasklopi neaktivne kartice + + Sklopi neaktivne kartice + Automatski zatvoriti nakon jednog mjeseca? @@ -1769,10 +1830,22 @@ Otkrij više - Pokreće Pocket. + Pokreće Pocket. Dio Firefoxove obitelji. %s Saznaj više + + Sponzorirano + + + Idi u postavke + Firefox prijedlozi + + + + sklopi + + rasklopi diff --git a/app/src/main/res/values-hsb/strings.xml b/app/src/main/res/values-hsb/strings.xml index 872de2ee1..58558ee87 100644 --- a/app/src/main/res/values-hsb/strings.xml +++ b/app/src/main/res/values-hsb/strings.xml @@ -14,6 +14,12 @@ Priwatny modus znjemóžnić Pytać abo adresu zapodać + + Historiju přepytać + + Zapołožki přepytać + + Rajtarki přepytać Pytanske wurazy zapodać @@ -130,13 +136,6 @@ Tłóčatko „Njedawno wočinjene rajtarki“ pokazać - - Waše pytanje za \"%1$s\" - - - Sydła: %d Wšě synchronizowane rajtarki pokazać @@ -257,6 +256,9 @@ Pytanske nastajenja + + Tónkróć pytać: + Nowe funkcije a změny w %1$s @@ -302,6 +304,9 @@ Waše rajtarki so synchronizuja! Pokročujće, hdźež sće na druhim graće přestał. + + Začinić + Nowy rajtark %1$s wočinić @@ -458,8 +463,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Njedawno wopytane - Pocket + Pocket + + Stawiznički, kotrež k přemyslowanju pohonjeja + + Nastawki spěchowane wot %s Sponsorowane stawizny @@ -483,12 +492,6 @@ Pozadkowy wobraz njeda so změnić Dalše informacije - - Podótkńće so loga startoweje strony Firefox, zo byšće pozadkowy wobraz změnił - - - Logo Firefox - pozadkowy wobraz změnić, tłóčatko Klasiski %s @@ -647,6 +650,14 @@ Začinić + + Slědowacu ličbu rajtarkow wočinić? %d + + Wočinjene rajtarki + + Přetorhnyć + %d sydło @@ -677,10 +688,6 @@ Lisćina Lěsyca - - Pytanske skupiny - - Přiwuzne sydła zeskupić Rajtarki začinić @@ -835,18 +842,6 @@ Tu žana historija njeje - - Z druhich gratow synchronizowane - - Z druhich gratow - - - Přizjewće so, zo byšće historiju widźał, kotruž sće ze swojich druhich gratow synchronizował. - - Přizjewić - - Abo załožće konto Firefox, zo byšće synchronizowanje započał]]> - Sćehnjenja wotstronjene @@ -896,6 +891,10 @@ W nowym rajtarku wočinić W priwatnym rajtarku wočinić + + Wšě w nowych rajtarkach wočinić + + Wšě w priwatnych rajtarkach wočinić Zhašeć @@ -1073,6 +1072,10 @@ Dźělić + + Jako PDF składować + + PDF njeda so wutworić Na grat pósłać @@ -1084,9 +1087,11 @@ Do mjezyskłada kopěrowane - Pola Sync přizjewić + Pola Sync přizjewić Pola Sync přizjewić + + Daty synchronizować a składować Na wšě graty pósłać @@ -1931,7 +1936,9 @@ Wjace wotkryć - Wot Pocket spěchowany + Wot Pocket spěchowany + + Spěchowany wot %s. Dźěl swójby Firefox. %s @@ -1945,4 +1952,14 @@ K nastajenjam Namjety Firefox + + + + schować + + pokazać + + wočińće wotkaz, zo byšće wjace wo tutej zběrce zhonił + + nastawk čitać diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 2a89dd1a6..447a7913d 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -15,6 +15,12 @@ Privát böngészés letiltása Keressen, vagy adjon meg címet + + Keresés előzményei + + Könyvjelzők keresése + + Lapok keresése Adja meg a keresési kifejezéseket @@ -40,8 +46,6 @@ - Friss könyvjelzők - Nemrég mentett Összes mentett könyvjelző megjelenítése @@ -130,13 +134,6 @@ Öösszes legutóbbi lap megjelenítése gomb - - Az Ön keresése erre: „%1$s” - - - %d webhely Összes szinkronizált lap megtekintése @@ -260,39 +257,20 @@ Keresési beállítások - - - A %s újdonságai - - Mostantól könnyebb ott folytatni, ahol abbahagyta. - - Személyre szabott %1$s kezdőoldal - - Ugrás a megnyitott lapokra, könyvjelzőkre és az előzményekre. - - Tiszta, rendszerezett lapok - - Számoljon le a lapok rendezetlenségével a jobb elrendezés és az automatikusan bezáródó lapok segítségével. - - Legutóbbi keresések - - - Tekintse meg újra a legutóbbi kereséseit a kezdőlapról és a lapokról. - - - A személyre szabott Firefox kezdőlapja megkönnyíti, hogy ott folytassa, ahol abbahagyta. Találja meg a legutóbbi lapjait, könyvjelzőit és keresési találatait. + + Ezúttal keresés ezzel: + + Ezúttal keresés ebben: + + Ismerje meg személyre szabott kezdőlapját. Itt jelennek meg a legutóbbi lapok, könyvjelzők és keresési találatok. - Üdvözöljük egy független interneten - Üdvözöljük egy személyesebb interneten Több szín. Jobb adatvédelem. Ugyanaz az elkötelezettség: az emberek a profit előtt. - Váltson át a telefonról a laptopra és vissza - A képernyők közötti váltás egyszerűbb, mint valaha Folytassa onnan, ahol abbahagyta, és most már a kezdőlapján megjelennek a többi eszközről származó lapjai is. @@ -306,6 +284,9 @@ A lapjai szinkronizálódnak! Folytassa onnan, ahol abbahagyta a másik eszközén. + + Bezárás + Új %1$s lap megnyitása @@ -355,6 +336,14 @@ Privát böngészési indítóikon hozzáadása Csak HTTPS mód + + + Sütibannerek számának csökkentése + + A sütibannerek számának csökkentése + + A Firefox automatikusan megpróbálja elutasítani a sütibannereken megjelenő sütikéréseket. Ha nem áll rendelkezésre elutasítási lehetőség, akkor a Firefox minden sütit elfogadhat a banner elrejtéséhez. + Automatikusan HTTPS titkosítási protokoll használatával próbál meg csatlakozni a webhelyekhez a fokozott biztonság érdekében. @@ -394,8 +383,6 @@ Testreszabás - Könyvjelzők, előzmények és egyebek szinkronizálása a Firefox-fiókjával - Jelentkezzen be a lapok, könyvjelzők, jelszavak és sok más szinkronizálásához. Firefox-fiók @@ -464,8 +451,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nemrég felkeresett - Pocket + Pocket + + Elgondolkodtató történetek + + A cikkek forrása: %s Szponzorált történetek @@ -489,12 +480,6 @@ Nem sikerült megváltoztatni a háttérképet További tudnivalók - - A háttérkép módosításához koppintson a Firefox kezdőlap logójára - - - Firefox logó – háttérkép megváltoztatása, gomb Klasszikus %s @@ -591,8 +576,6 @@ Engedélyezés, hogy a Mozilla tanulmányokat telepítsen és futtasson - - Sync bekapcsolása Szinkronizálja és mentse adatait @@ -656,6 +639,17 @@ Bezárás + + Megnyit %d lapot? + + Ennyi lap megnyitása lelassíthatja a %s programot, miközben a lapok betöltődnek. Biztos, hogy folytatja? + + Nyitott lapok + + Mégse + %d webhely @@ -685,10 +679,6 @@ Lista Rács - - Keresési csoportok - - Kapcsolódó webhelyek csoportosítása Lapok bezárása @@ -814,9 +804,6 @@ %1$s (privát mód) - - Más lapok - Adja meg a keresési kifejezéseket @@ -844,18 +831,6 @@ Nincsenek előzmények - - Másik eszközről szinkronizálva - - Más eszközről - - - Jelentkezzen be a más eszközeiről származó előzményeinek megjelenítéséhez. - - Bejelentkezés - - Vagy hozzon létre egy Firefox-fiókot a szinkronizálás megkezdéséhez]]> - Letöltések eltávolítva @@ -905,6 +880,10 @@ Megnyitás új lapon Megnyitás privát lapon + + Összes megnyitása új lapon + + Összes megnyitása privát lapon Törlés @@ -1083,6 +1062,10 @@ Megosztás + + Mentés PDF-ként + + A PDF nem állítható elő Küldés eszközre @@ -1094,9 +1077,11 @@ Vágólapra másolva - Jelentkezzen be a szinkronizálásba + Jelentkezzen be a szinkronizálásba Jelentkezzen be a Syncbe + + Adatok szinkronizálása és mentése Küldés az összes eszközre @@ -1135,6 +1120,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> A %1$s alapértelmezett böngészővé tétele + + Próbálja ki a privát böngészést + + Böngésszen mentett sütik vagy előzmények nélkül a %1$sban + Gyűjtemény törölve @@ -1224,8 +1215,6 @@ Kilépés - - Ez törli az összes böngészési adatot. Törlendő időtartomány @@ -1260,33 +1249,20 @@ Csoport törölve - - Üdvözli a %s! Üdvözöljük egy jobb interneten Egy böngésző az emberekért, nem a haszonért. - - A Firefox szinkronizálása az eszközök közt Folytassa ott, ahol abbahagyta - - Adjon hozzá könyvjelzőket, előzményeket és jelszavakat a %1$shoz ezen az eszközön. Szinkronizálja a lapokat és a jelszavakat az eszközök között a zökkenőmentes képernyőváltás érdekében. - - Regisztráció Bejelentkezés A Sync be van kapcsolva - - Mindig bekapcsolt adatvédelem Adatvédelem alapértelmezetten - - A %1$s automatikusan megakadályozza, hogy a cégek titokban kövessék Önt a weben. Bemutatkozik a Teljes sütivédelem, amely megakadályozza, hogy a nyomkövetők arra használhassák a sütiket, hogy kövessék a webhelyek között. @@ -1299,18 +1275,10 @@ Több nyomkövetőt blokkol, így az oldalak gyorsabban töltenek be, de egyes oldalfunkciók meghibásodhatnak. Válassza ki az eszköztár elhelyezését - - Helyezze az eszköztárat könnyen elérhető helyre. Tartsa az alján, vagy mozgassa a tetejére. Tartsa továbbra is lent, vagy vigye a tetejére. - - Adatvédelem Ön irányítja az adatait - - Úgy terveztük a %s böngészőt, hogy irányítást adjunk afelett, hogy mit oszt meg online, és mit oszt meg velünk. - A Firefox irányítást ad afelett, hogy mit oszt meg online, és mit oszt meg velünk. @@ -1492,7 +1460,7 @@ The first parameter is number of long clicks left to enable the menu --> Hibakeresési menü: %1$d kattintás van hátra az engedélyezésig Hibakeresési menü engedélyezve - + Másolás @@ -1500,10 +1468,10 @@ Beillesztés és ugrás Beillesztés - + URL a vágólapra másolva - + Kezdőképernyőhöz adás @@ -1950,7 +1918,9 @@ Folytassa a felfedezést - A motorháztető alatt: Pocket. + A motorháztető alatt: Pocket. + + A motorháztető alatt: %s. A Firefox család tagja. %s @@ -1964,4 +1934,14 @@ Ugrás a beállításokhoz Firefox Suggest + + + + összecsukás + + kibontás + + hivatkozás megnyitása, hogy többet tudjon meg a gyűjteményről + + a cikk elolvasása diff --git a/app/src/main/res/values-hy-rAM/strings.xml b/app/src/main/res/values-hy-rAM/strings.xml index e615d81ae..f26362123 100644 --- a/app/src/main/res/values-hy-rAM/strings.xml +++ b/app/src/main/res/values-hy-rAM/strings.xml @@ -15,6 +15,12 @@ Անջատել գաղտնի դիտարկումը Մուտքագրեք որոնում կամ կայք + + Որոնման պատմություն + + Որոնել էջանիշեր + + Որոնել ներդիրներ Մուտքագրեք որոնվող բառը @@ -40,8 +46,6 @@ - Վերջին Էջանիշերը - Վերջերս պահպանված Ցուցադրել բոլոր էջանիշերը @@ -129,13 +133,6 @@ Ցուցադրել բոլոր վերջին ներդիրների կոճակները - - Ձեր որոնումը \"%1$s\"-ի համար - - - %d կայքեր Դիտեք բոլոր համաժամացված ներդիրները @@ -257,38 +254,17 @@ Որոնման կարգավորում - - - Ինչն է նոր %1$s-ում - - Այժմ ավելի հեշտ է շարունակել այն տեղից, որտեղ կանգ եք առել: - - Անհատականացված %1$s գլխավոր էջ - - Անցեք ձեր բաց ներդիրներին, էջանիշերին և զննման պատմությանը: - - Մաքուր, կազմակերպված ներդիրներ - - Կարգի բերեք ներդիրները դասավորությունը լավարկելու և ինքնափակելու միջոցով: - - Վերջին որոնումները - - Վերանայեք ձեր վերջին որոնումները ձեր տնային էջից և ներդիրներից: - - - Ձեր անհատականացված Firefox-ի տնային էջը այժմ հեշտացնում է աշխատանքը շարունակելու այն կետից, որում կանգնել եք: Գտեք ձեր վերջին ներդիրները, էջանիշերը և որոնման արդյունքները: + + Այս անգամվա որոնում. + Դիտեք ձեր անհատականացված գլխավոր էջը: Վերջին ներդիրները, էջանիշները և որոնման արդյունքները կհայտնվեն այստեղ: - Բարի գալուստ անկախ համացանց - Բարի գալուստ ավելի անձնական համացանց Ավելի շատ գույներ: Ավելի լավ գաղտնիություն: Նույն հանձնառությունը մարդկանց նկատմամբ շահույթի նկատմամբ: - Անցեք հեռախոսից նոութբուք և հետ - Էկրանների փոխարկումն ավելի հեշտ է, քան երբևէ Շարունակեք այնտեղ, որտեղ դադարեցիք, այլ սարքերի ներդիրներով՝ այժմ ձեր գլխավոր էջում: @@ -301,6 +277,9 @@ Ձեր ներդիրները համաժամացվում են: Շարունակեք այնտեղից, որտեղ դադարեցրել եք ձեր մյուս սարքում: + + Փակել + Բացել նոր %1$s ներդիր @@ -389,8 +368,6 @@ Հարմարեցնել - Համաժամեցրեք էջանիշները, պատմությունը և ավելին ձեր Firefox հաշվի հետ - Մուտք գործեք՝ ներդիրները, էջանիշերը, գաղտնաբառերը և ավելին համաժամեցնելու համար: Firefox-ի հաշիվ @@ -459,8 +436,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Վերջերս այցելած - Pocket + Pocket + + Մտահանգման պատմություններով + + %s-ի կողմից ստեղծված հոդվածներ Հովանավորված @@ -483,12 +464,6 @@ Չհաջողվեց փոխել պաստառը Իմանալ ավելին - - Փոխեք պաստառը՝ կտտացնելով Firefox-ի գլխավոր էջի պատկերանշանին - - - Firefox լոգոն` փոխել պաստառը, կոճակը Դասական %s @@ -585,8 +560,6 @@ Թույլ է տալիս Mozilla-ին տեղադրել և իրականացնել ուսումնասիրություններ - - Միացնել համաժամեցումը Համաժամեցրեք և պահեք ձեր տվյալները @@ -647,6 +620,17 @@ Փակել + + Բացե՞լ %d ներդիր: + + Այսքան ներդիրներ բացելը կարող է դանդաղեցնել %s-ը, մինչ էջերը բեռնվում են: Վստա՞հ եք, որ ցանկանում եք շարունակել: + + Բաց ներդիրներ + + Չեղարկել + %d կայք @@ -676,10 +660,6 @@ Ցանկ Ցանց - - Որոնել խմբեր - - Խմբավորել առնչվող կայքերը միասին Փակել ներդիրները @@ -802,9 +782,6 @@ %1$s (Գաղտնի կերպ) - - Այլ ներդիրներ - Մուտքագրեք որոնվող բառը @@ -832,18 +809,6 @@ Այստեղ պատմություն չկա - - Համաժամեցված այլ սարքից - - Այլ սարքերից - - - Մուտք գործե՛ք՝ տեսնելու Ձեր այլ սարքերից համաժամեցված պատմությունը: - - Մուտք գործել - - Կամ ստեղծեք Firefox հաշիվ՝ համաժամացումը սկսելու համար]]> - Ներբեռնումները հեռացված են @@ -893,6 +858,10 @@ Բացել նոր ներդիր Բացել Գաղտնի ներդիրում + + Բացեք բոլորը նոր ներդիրներում + + Բացեք բոլորը մասնավոր ներդիրներում Ջնջել @@ -1073,6 +1042,10 @@ "Share" button. Opens the share menu when pressed. --> Համօգտագործել + + Պահել որպես PDF + + Անհնար է ստեղծել PDF Ուղարկել սարքի @@ -1084,9 +1057,11 @@ Պատճենվել է սեղմատախտակին - Մուտք գործեք՝ համաժամեցնելու համար + Մուտք գործեք՝ համաժամեցնելու համար Մուտք գործել Համաժամեցում + + Համաժամեցնել և պահել տվյալները Ուղարկել բոլոր սարքերին @@ -1212,8 +1187,6 @@ Փակել - - Սա կջնջի ձեր դիտարկման բոլոր տվյալները: Ջնջելու ենթակա ժամանակահատվածը @@ -1247,34 +1220,20 @@ Խումբը ջնջված է - - Բարի գալուստ %s: - Բարի գալուստ ավելի լավ համացանց Զննարկիչ, որը ստեղծված է մարդկանց համար, ոչ առևտրային: - - Համաժամեցնել Firefox-ը Շարունակեք այնտեղից, որտեղ որ կանգնել էիք: - - Այս սարքում բերեք էջանիշները, պատմությունը և գաղտնաբառերը %1$s-ում: Համաժամացրեք ներդիրներն ու գաղտնաբառերը սարքերի միջև՝ էկրանն անխափան փոխելու համար: - - Գրանցվել Մուտք գործել Համաժամեցումը միացված է - - Միշտ գաղտնիություն Գաղտնիության պաշտպանություն սկզբնադիր - - %1$s-ը ինքնաշխատ կանգնեցնում է ընկերություններին՝ Ձեզ առցանց հետևելուց: Հատկանշվում է Total Cookie Protection-ը, որը թույլ չի տալիս հետագծողներին օգտագործել թխուկներ՝ կայքերում ձեզ հետապնդելու համար: @@ -1287,18 +1246,11 @@ Արգելափակում է ավելի շատ հետագծիչներ, որ էջերը արագ բեռնվեն, բայց էջի որոշ գործույթներ կարող են ընդհատվեն: Ընտրեք գործիքագոտու տեղը - - Գործիքագոտին դրեք հեշտ հասանելի տեղ: Պահեք այն ներքևում կամ տեղափոխեք վերև: Պահեք այն ներքևում կամ տեղափոխեք այն վերև: - - Ձեր գաղտնիությունը Դուք վերահսկում եք ձեր տվյալները - - Մենք պատրաստել ենք %s-ը, որպեսզի դուք կառավարեք այն, ինչ համօգտագործում եք առցանց և թե ինչով եք կիսվում մեզ հետ: Firefox-ը ձեզ հնարավորություն է տալիս վերահսկել, թե ինչ եք կիսվում առցանց և ինչ եք կիսում մեզ հետ: @@ -1933,7 +1885,9 @@ Բացահայտի՛ր ավելին - Pocket-ի կողմից: + Pocket-ի կողմից: + + Աշխատում է %s-ի կողմից: Firefox ընտանիքի մի մասը: %s @@ -1947,4 +1901,14 @@ Անցնել Կարգավորումներին Firefox-ի առաջարկ + + + + Կոծկել + + Ընդարձակել + + բացեք հղումը՝ այս հավաքածուի մասին ավելին իմանալու համար + + կարդալ հոդվածը diff --git a/app/src/main/res/values-ia/strings.xml b/app/src/main/res/values-ia/strings.xml index dc6b6ede6..7275e2437 100644 --- a/app/src/main/res/values-ia/strings.xml +++ b/app/src/main/res/values-ia/strings.xml @@ -17,6 +17,12 @@ Disactivar le navigation private. Insere un adresse o face un recerca + + Cercar in le chronologia + + Cercar in le marcapaginas + + Cercar in schedas Inserer terminos pro le recerca @@ -40,8 +46,6 @@ - Marcapaginas recente - Salvate recentemente Monstrar tote le marcapaginas salvate @@ -125,19 +129,12 @@ - Revenir in + Saltar retro Monstrar toto - Monstrar tote le recente button de schedas - - Tu recerca de \"%1$s\" - - - %d sitos + Button pro monstrar tote le schedas recente Vider tote le schedas synchronisate @@ -260,39 +257,20 @@ Parametros de recerca - - - Lo que es nove in %1$s - - Ora il es plus veloce seliger retro ubi tu abandonava. - - Pagina principal de %1$s personalisate - - Salta a tu schedas aperte, marcapaginas e chronologia de navigation. - - Schedas clar, organisate - - Elimina le disordine del schedas con le disposition meliorate e le auto-clausura. - - Recercas recente - - - Revisita tu ultime recercas ab tu pagina principal e schedas. - - - Tu pagina principal personalisate de Firefox ora simplifica reprender de ubi tu lassava. Trova tu recente schedas, marcapaginas e resultatos del recerca. + + Iste vice cercar per: + + Iste vice cercar in: + + Incontra tu pagina principal personalisate. Le schedas recente, le marcapaginas e le resultatos del recerca apparera ci. - Benvenite in un internet independente - Benvenite in un internet plus personal Plus de colores. Melior confidentialitate. Mesme dedication al personas super le profitos. - Passa ab le telephono al portabile e retro - Cambiar le paginas es plus facile que mais Reprende de ubi tu exiva con le schedas de altere apparatos ora sur tu pagina principal. @@ -306,6 +284,9 @@ Tu schedas es synchronisate! Reprende de ubi tu exiva sur un tu altere apparato. + + Clauder + Aperir un nove scheda %1$s @@ -356,6 +337,15 @@ Adder accesso directe de navigation private Modo solo HTTPS + + + Reduction de banner pro le cookie + + Reducer banners pro le cookie + + + Firefox automaticamente proba a rejectar requestas de cookies sur banners pro cookies. Si un option pro rejectar non es disponibile, Firefox pote acceptar tote le cookies pro dimitter le banner. + Automaticamente tenta de connecter se al sitos per le protocollo de cryptation HTTPS pro major securitate. @@ -395,8 +385,6 @@ Personalisar - Synchronisa marcapaginas, chronologia e altero ancora con tu Firefox Account - Authentica te pro synchronisar tu schedas, marca-paginas, contrasignos e plus. Firefox Account @@ -459,15 +447,19 @@ - Revenir hic + Saltar retro Marcapaginas recente Visitate recentemente - Pocket + Pocket + + Historias que face pensar + + Articulos supportate per %s Articulos sponsorisate @@ -491,12 +483,6 @@ Impossibile cambiar fundo Pro saper plus - - Cambia le fundo toccante le logo de Firefox in le pagina initial - - - Logo Firefox, button cambiar le fundo %s classic @@ -602,10 +588,6 @@ - - Activar Sync - - Synchronisar e salvar datos @@ -673,6 +655,17 @@ Clauder + + Aperir %d schedas? + + Aperir tante schedas pote relentar %s durante que le paginas es cargate. Desira tu vermente continuar? + + Aperir schedas + + Cancellar + %d sito @@ -702,10 +695,6 @@ Lista Grillia - - Cercar gruppos - - Aggruppar sitos associate Clauder le schedas @@ -797,7 +786,7 @@ - Marcapaginas + Adder al marcapaginas Clauder @@ -837,9 +826,6 @@ %1$s (modo private) - - Altere schedas - Insere le terminos de recerca @@ -869,18 +855,6 @@ Nulle chronologia hic - - Synchronisate ab altere apparatos - - Ab altere apparatos - - - Accede pro vider le chronologia synchronisate de tu altere apparatos. - - Acceder - - O crea un conto Firefox pro initiar a synchronisar]]> - Discargamentos removite @@ -929,6 +903,10 @@ Aperir in scheda private + + Aperir totos in nove schedas + + Aperir totos in nove schedas private Deler @@ -937,7 +915,7 @@ The first parameter is the number of bookmarks selected --> %1$d seligite - Rediger le marcapaginas + Modificar marcapagina Modificar dossier @@ -1111,6 +1089,10 @@ "Share" button. Opens the share menu when pressed. --> Compartir + + Salvar como PDF + + Impossibile generar file PDF Inviar a un apparato @@ -1123,9 +1105,11 @@ Copiate al area de transferentia - Accede pro synchronisar + Accede pro synchronisar Aperir session in Sync + + Synchronisar e salvar datos Inviar a tote le apparatos @@ -1163,6 +1147,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Rende %1$s tu navigator predefinite + + Essaya le navigation private + + + Navigar sin cookies o chronologia salvate in %1$s + Collection delite @@ -1254,8 +1245,6 @@ Quitar - - Isto delera tote tu datos de navigation. Intervallo pro deler @@ -1289,33 +1278,20 @@ Gruppo delete - - Benvenite a %s! Benvenite a in un internet melior Un navigator pro le gente, non pro le profitos. - - Synchronisar Firefox inter apparatos Reprende de ubi tu lassava - - Apporta marcapaginas, chronologia e contrasignos de %1$s sur iste dispositivo. Synchronisa schedas e contrasignos inter apparatos pro facilemente mutar schermo. - - Inscribe te Aperir session Sync es activate - - Confidentialitate sempre active Preconfigurate pro le vita private - - %1$s automaticamente impedi le companias de sequer secretemente tu movimentos circum le Web. Eligente le Protection total del cookies, tu stoppa le traciatores de usar le cookies pro sequer te furtivemente circum le web. @@ -1329,17 +1305,10 @@ Elige le ubication de tu barra del instrumentos - - Pone le barra del instrumentos pro attinger lo facilemente. Mantene lo fundo pagina o move lo in alto. - - Tu confidentialitate Tu controla tu datos - - Nos ha concipite %s pro dar te le controlo de lo que tu comparti in linea e lo que tu comparti con nos. Firefox te da le controlo sur lo que tu comparti in linea e lo que tu comparti con nos. @@ -1990,7 +1959,9 @@ Discoperi plus - Potentiate per Pocket + Potentiate per Pocket + + Potentiate per %s. Parte del familia de Firefox. %s @@ -2004,4 +1975,14 @@ Ir a parametros Firefox suggere + + + + contraher + + expander + + aperi le ligamine pro apprender plus re iste collection + + leger le articulo diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index 8c2d2ce9c..36f1e4162 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -16,6 +16,12 @@ Cari atau masukkan alamat + + Riwayat pencarian + + Cari markah + + Cari tab Masukkan istilah pencarian @@ -41,8 +47,6 @@ - Markah terbaru - Baru saja disimpan Tampilkan semua markah tersimpan @@ -131,13 +135,6 @@ Tampilkan tombol semua tab terbaru - - Pencarian Anda untuk \"%1$s\" - - - %d situs Lihat semua tab tersinkron @@ -262,39 +259,20 @@ Setelan pencarian - - - Yang baru di %1$s - - Sekarang lebih mudah untuk melanjutkan dari sesi sebelumnya. - - Beranda %1$s yang dipersonalisasi - - Lompat ke tab terbuka, markah, dan riwayat penjelajahan Anda. - - Tab bersih dan terorganisir - - - Hilangkan tab berantakan dengan tata letak baru dan tab yang menutup otomasi. - - Pencarian terkini - - Kunjungi kembali penelusuran terkini dari beranda dan tab Anda. - - - Sekarang, halaman beranda Firefox yang dipersonalisasi memudahkan Anda melanjutkan pekerjaan dari sesi sebelumnya. Temukan tab, markah, dan hasil pencarian Anda yang terkini. + + Kali ini temukan dengan: + + Kali ini, cari di: + + Temui beranda pribadi Anda. Tab, markah, dan hasil pencarian terkini akan muncul di sini. - Selamat datang di internet yang independen - Selamat datang di Internet yang lebih pribadi Lebih banyak warna. Privasi yang lebih baik. Komitmen yang sama pada masyarakat di atas laba. - Lompat dari ponsel ke laptop dan sebaliknya - Beralih layar lebih mudah dari sebelumnya Lanjutkan dari bagian terakhir yang Anda tinggalkan dengan tab dari perangkat lain sekarang di beranda Anda. @@ -308,6 +286,9 @@ Tab Anda sedang disinkronkan! Lanjutkan di mana Anda tinggalkan di perangkat Anda yang lain. + + Tutup + Buka di tab %1$s baru @@ -359,6 +340,14 @@ Tambahkan pintasan penjelajahan pribadi Mode Hanya HTTPS + + + Pengurangan Spanduk Kuki + + Kurangi spanduk kuki + + Firefox secara otomatis mencoba menolak permintaan kuki di spanduk kuki. Jika opsi menolak tidak tersedia, Firefox akan menerima semua kuki untuk menutup spanduk tersebut. + Secara otomatis mencoba terhubung ke situs menggunakan protokol enkripsi HTTPS untuk meningkatkan keamanan. @@ -466,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Baru dikunjungi - Pocket + Pocket + + Cerita yang menggugah pikiran + + Artikel diberdayakan oleh %s Konten bersponsor @@ -490,11 +483,6 @@ Tidak dapat mengubah wallpaper Pelajari lebih lanjut - - Ubah wallpaper dengan mengetuk logo beranda Firefox - - Logo Firefox - ubah wallpaper, tombol %s Klasik @@ -653,6 +641,17 @@ Tutup + + Buka %d tab? + + Membuka banyak tab seperti ini dapat memperlambat %s saat laman sedang dimuat. Yakin ingin melanjutkan? + + Tab terbuka + + Batal + %d situs @@ -682,10 +681,6 @@ Daftar Grid - - Cari grup - - Kelompokkan situs terkait bersama-sama Tutup tab @@ -837,18 +832,6 @@ Tidak ada riwayat di sini - - Disinkronkan dari perangkat lain - - Dari perangkat lainnya - - - Masuk untuk melihat riwayat yang disinkronkan dari perangkat Anda yang lain. - - Masuk - - Atau buat Firefox Account untuk memulai sinkronisasi]]> - Unduhan Dihapus @@ -899,6 +882,10 @@ Buka di tab baru Buka di tab pribadi + + Buka semua di tab baru + + Buka semua di tab pribadi Hapus @@ -1078,6 +1065,10 @@ Bagikan + + Simpan sebagai PDF + + Gagal membuat PDF Kirim ke peranti @@ -1089,9 +1080,11 @@ Tersalin ke papan klip - Masuk untuk menyinkronkan + Masuk untuk menyinkronkan Masuk ke Sync + + Sinkronkan dan simpan data Kirim ke semua peranti @@ -1129,6 +1122,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Jadikan %1$s sebagai peramban baku Anda + + Coba penjelajahan pribadi + + + Menjelajah tanpa kuki atau riwayat tersimpan di %1$s + Koleksi dihapus @@ -1252,34 +1252,20 @@ Grup dihapus - - Selamat datang di %s! - Selamat datang di Internet yang lebih baik Peramban yang dibuat untuk masyarakat, bukan profit. - - Sinkronkan Firefox antar perangkat Mulai dari situasi saat Anda pergi - - Bawa markah, riwayat, dan kata sandi ke %1$s di perangkat ini. Sinkronkan tab dan kata sandi di berbagai perangkat untuk peralihan layar yang mulus. - - Daftar Masuk Sinkronisasi aktif - - Privasi selalu aktif Perlindungan privasi secara bawaan - - %1$s secara otomatis menghentikan perusahaan yang mengikuti Anda di web secara rahasia. Menghadirkan Perlindungan Kuki Total untuk mencegah pelacak gunakan kuki untuk menguntit Anda di web. @@ -1292,17 +1278,10 @@ Blokir lebih banyak pelacak sehingga laman dimuat lebih cepat, tetapi beberapa fungsionalitas pada laman mungkin rusak. Pilih penempatan bilah alat Anda - - Letakkan bilah alat agar mudah dijangkau. Tetap di bawah, atau pindahkan ke atas. Simpan di bawah, atau pindahkan ke atas. - - Privasi Anda Anda mengendalikan data Anda - - Kami merancang %s agar Anda dapat mengendalikan apa saja yang Anda bagikan secara daring dan apa yang Anda bagikan kepada kami. Firefox memberi Anda kendali atas apa saja yang Anda bagikan secara daring dan apa yang Anda bagikan kepada kami. @@ -1490,10 +1469,10 @@ Tempelkan & Kunjungi Tempel - + URL disalin ke papan klip - + Tambahkan ke Beranda @@ -1935,7 +1914,9 @@ Temukan lebih banyak - Diberdayakan oleh Pocket. + Diberdayakan oleh Pocket. + + Diberdayakan oleh %s. Bagian dari keluarga Firefox. %s @@ -1949,4 +1930,14 @@ Buka pengaturan Saran Firefox + + + + ciutkan + + bentangkan + + buka tautan untuk mempelajari lebih lanjut tentang koleksi ini + + baca artikel diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index ac3a23442..deb9e034c 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -14,6 +14,12 @@ Afvirkja huliðsvöfrun Leitaðu eða sláðu inn vistfang + + Leita í ferli + + Leita í bókamerkjum + + Leita í flipum Settu inn leitarorð @@ -40,8 +46,6 @@ - Nýleg bókamerki - Nýlega vistað Sýna öll vistuð bókamerki @@ -128,12 +132,6 @@ Birta allt Sýna hnapp fyrir alla nýlega flipa - - Leitin þín að \"%1$s\" - - %d vefsvæði Sjá alla samstillta flipa @@ -256,39 +254,20 @@ Leitarstillingar - - - Hvað er nýtt í %1$s - - Nú er auðveldara að halda áfram þar sem frá var horfið. - - Persónuleg %1$s upphafssíða - - Hoppaðu í opna flipa, bókamerki og vafraferil. - - Hreinlegir, skipulagðir flipar - - Hreinsaðu flipaóreiðuna með bættu skipulagi og sjálfvirkri lokun flipa. - - Nýlegar leitir - - - Skoðaðu nýjustu leitirnar þínar af upphafssíðunni þinni og flipum. - - - Sérsniðin Firefox-upphafssíða þín gerir það nú auðveldara að halda áfram þar sem frá var horfið. Finndu nýlega flipa, bókamerki og leitarniðurstöður. + + Leita núna með: + + + Leita núna í: + Kynntu þér persónulegu upphafssíðuna þína. Nýlegir flipar, bókamerki og leitarniðurstöður munu birtast hér. - Velkomin á sjálfstætt internet - Velkomin á persónulegra internet Fleiri litir. Betri persónuvarnir. Sama skuldbindingin sem setur fólk fram yfir hagnað. - Hoppaðu úr síma yfir í fartölvu og svo aftur til baka - Það er auðveldara en nokkru sinni að skipta á milli skjáa Haltu áfram þar sem þú hættir með flipum af öðrum tækjum, sem núna eru á upphafssíðunni þinni. @@ -301,6 +280,9 @@ Fliparnir þínir eru að samstillast! Haltu áfram þar sem frá var horfið í hinu tækinu þínu. + + Loka + Opna nýjan %1$s-flipa @@ -351,6 +333,14 @@ Bæta við flýtileið fyrir huliðsglugga Einungis-HTTPS-hamur + + + Fækkun vefkökuborða + + Fækka vefkökuborðum + + Firefox reynir sjálfkrafa að hafna vefkökubeiðnum á vefkökuborðum. Ef ekki er boðið upp á að hafna vefkökum getur Firefox samþykkt allar vefkökur til að hafna borðanum. + Reynir sjálfkrafa að tengjast vefsvæðum með HTTPS dulritunareglum til að auka öryggi. @@ -390,8 +380,6 @@ Sérsníða - Samstilla bókamerki, feril og fleira með Firefox reikningnum þínum - Skráðu þig inn til að samstilla flipana þína, bókamerki, lykilorð og fleira. Firefox reikningur @@ -459,8 +447,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nýlega heimsótt - Pocket + Pocket + + Umhugsunarverðar sögur + + Greinar knúnar með %s Kostaðar sögur @@ -483,12 +475,6 @@ Gat ekki skipt um bakgrunnsmynd Kanna nánar - - Skiptu um bakgrunn með því að smella á táknmynd Firefox-heimasíðunnar - - - Firefox merki - breyta bakgrunni, hnappur Klassískt %s @@ -586,8 +572,6 @@ Leyfir Mozilla að setja upp og keyra rannsóknir - - Kveikja á samstillingu Samstilltu og vistaðu gögnin þín @@ -649,6 +633,17 @@ Loka + + Opna %d flipa? + + Að opna þetta marga flipa gæti hægt á %s á meðan síðurnar eru að hlaðast inn. Ertu viss um að þú viljir halda áfram? + + Opna flipa + + Hætta við + %d vefsvæði @@ -678,10 +673,6 @@ Listi Reitir - - Leita að hópum - - Hópa tengd vefsvæði saman Loka flipum @@ -803,9 +794,6 @@ %1$s (huliðshamur) - - Aðrir flipar - Settu inn leitarorð @@ -834,18 +822,6 @@ Ekkert ferli hér - - Samstillt frá öðrum tækjum - - Frá öðrum tækjum - - - Skráðu þig inn til að skoða samstilltan feril frá öðrum tækjum. - - Skrá inn - - Eða búðu til Firefox-reikning til að hefja samstillingu]]> - Sóttar skrár fjarlægðar @@ -893,6 +869,10 @@ Opna nýjan flipa Opna flipa í huliðsstillingu + + Opna allt í nýjum flipum + + Opna allt í huliðsflipum Eyða @@ -1070,6 +1050,10 @@ Deila + + Vista sem PDF + + Tekst ekki að útbúa PDF Senda til tækis @@ -1081,9 +1065,11 @@ Afritað á klippispjald - Skráðu þig inn til að samstilla + Skráðu þig inn til að samstilla Skráðu þig inn til að samstilla + + Samstilltu og vistaðu gögn Senda í öll tæki @@ -1120,6 +1106,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Gerðu %1$s að sjálfgefnum vafra + + Prófaðu huliðsvafur + + Vafraðu án þess að vista vefkökur eða aðgerðaferil í %1$s + Safni eytt @@ -1209,8 +1201,6 @@ Hætta - - Þetta mun eyða öllum vafragögnum þínum. Tímabil sem á að hreinsa @@ -1243,34 +1233,20 @@ Hópi eytt - - Velkomin í %s! - Velkomin á betra internet Vafri hannaður fyrir fólk, ekki gróða. - - Samstilla Firefox á milli tækja Halda áfram þar sem frá var horfið - - Komdu með bókamerki, feril og lykilorð yfir í %1$s á þessu tæki. Samstilltu flipa og lykilorð á milli tækja til að skipta óaðfinnanlega um skjái. - - Skráðu þig Skrá inn Kveikt er á samstillingu - - Sívökul friðhelgi Sjálfgefin persónuvernd - - %1$s kemur sjálfkrafa í veg fyrir að fyrirtæki fylgi þér í laumi um vefinn. Er með allsherjar-vefkökuvörn sem kemur í veg fyrir að rekjarar geti notað vafrakökur til að rekja slóð þína á milli vefsvæða. @@ -1284,17 +1260,10 @@ Lokar fyrir fleiri rekjara svo síður hlaðast hraðar, en einhver virkni á síðunni gæti rofnað. Veldu staðsetningu verkfærastikunnar - - Settu verkfærastikuna innan seilingar. Haltu henni neðst eða færðu hana efst. Haltu því neðst eða færðu það efst. - - Persónuvernd þín Þú stjórnar gögnunum þínum - - Við hönnuðum %s til að gefa þér stjórn yfir því hverju þú deilir á netinu og því sem þú deilir með okkur. Firefox gefur þér stjórn yfir því hverju þú deilir á netinu og því sem þú deilir með okkur. @@ -1929,7 +1898,9 @@ Uppgötva meira - Keyrt með Pocket. + Keyrt með Pocket. + + Keyrt með %s. Hluti af Firefox-fjölskyldunni. %s @@ -1943,4 +1914,14 @@ Farðu í stillingar Firefox-tillögur + + + + fella saman + + þenja út + + opna tengil til að læra meira um þetta safn + + lesa greinina diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 50b975a50..5178b0b67 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -17,6 +17,12 @@ Cerca o scrivi un indirizzo + + Cerca nella cronologia + + Cerca nei segnalibri + + Cerca nelle schede Immetti i termini di ricerca @@ -42,8 +48,6 @@ - Segnalibri recenti - Aggiunti di recente Visualizza tutti i segnalibri salvati @@ -130,13 +134,6 @@ Pulsante per mostrare tutte le schede recenti - - La tua ricerca per “%1$s” - - - %d siti Mostra tutte le schede sincronizzate @@ -261,43 +258,23 @@ Impostazioni ricerca - - - Novità in %1$s - - Ora è più facile riprendere da dove avevi interrotto. - - Pagina iniziale di %1$s personalizzata - - Passa alle schede aperte, ai segnalibri e alla cronologia di navigazione. - - - Schede chiare e organizzate - - Riduci il caos generato da troppe schede aperte con un layout migliorato e chiusura automatica. - - Ricerche recenti - - - Rivedi le tue ultime ricerche effettuate dalla pagina iniziale e dalle schede. - - - La pagina iniziale personalizzata di Firefox rende più semplice riprendere da dove avevi interrotto. Puoi trovare le schede recenti, i segnalibri e i risultati delle ricerche. + + Questa volta cerca con: + + Questa volta cerca in: + + Scopri la tua pagina iniziale personalizzata. Le schede recenti, i segnalibri e i risultati di ricerca verranno visualizzati qui. - Benvenuti nell’Internet indipendente - Benvenuto in un Internet più personale Più colori. Ancora più protezione per la privacy. Stesso impegno nell’anteporre le persone ai profitti. - Passa dal computer al telefono, e viceversa - Passare da uno schermo all’altro è più facile che mai - Riprendi da dove avevi interrotto con le schede di altri dispositivi, ora disponibili direttamente dalla pagina iniziale. + Riprendi da dove eri rimasto con le schede di altri dispositivi, ora disponibili direttamente dalla pagina iniziale. Inizia @@ -306,7 +283,10 @@ Salta - La sincronizzazione delle tue schede è in corso. Riprendi da dove avevi interrotto sull’altro dispositivo. + La sincronizzazione delle tue schede è in corso. Riprendi da dove eri rimasto sull’altro dispositivo. + + + Chiudi @@ -359,6 +339,14 @@ Aggiungi scorciatoia navigazione anonima Modalità solo HTTPS + + + Riduzione banner per i cookie + + Riduci i banner per i cookie + + Firefox cerca automaticamente di rifiutare le richieste di cookie quando viene visualizzato un banner per i cookie. Se l’opzione per rifiutarli non è disponibile, Firefox potrebbe accettare tutti i cookie per chiudere il banner. + Tenta automaticamente la connessione ai siti utilizzando il protocollo di crittografia HTTPS per una maggiore sicurezza. @@ -398,8 +386,6 @@ Personalizza - Sincronizza segnalibri, cronologia e molto altro con il tuo account Firefox - Accedi per sincronizzare schede, segnalibri, password e altro ancora. Account Firefox @@ -470,8 +456,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitati di recente - Pocket + Pocket + + Storie che fanno riflettere + + Articoli selezionati da %s Storie sponsorizzate @@ -495,12 +485,6 @@ Impossibile cambiare lo sfondo Ulteriori informazioni - - Cambia lo sfondo toccando il logo di Firefox nella pagina iniziale - - - Logo di Firefox. Pulsante per cambiare lo sfondo %s classico @@ -601,9 +585,6 @@ Consenti a Mozilla di installare e condurre studi - - Attiva Sync - Sincronizza e salva i tuoi dati @@ -664,6 +645,17 @@ Chiudi + + Aprire %d schede? + + L’apertura di così tante schede potrebbe rallentare %s durante il caricamento delle pagine. Procedere comunque? + + Apri schede + + Annulla + %d sito @@ -694,10 +686,6 @@ Elenco Griglia - - Gruppi di ricerca - - Raggruppa siti correlati Chiudi schede @@ -824,9 +812,6 @@ %1$s (modalità Navigazione anonima) - - Altre schede - Immetti i termini di ricerca @@ -855,18 +840,6 @@ Nessuna cronologia disponibile. - - Sincronizzata da altri dispositivi - - Da altri dispositivi - - - Accedi per visualizzare la cronologia sincronizzata con altri dispositivi. - - Accedi - - Oppure crea un account Firefox per iniziare a sincronizzare]]> - Download eliminati @@ -918,6 +891,10 @@ Apri in una nuova scheda Apri in scheda anonima + + Apri tutti in nuove schede + + Apri tutti in schede anonime Elimina @@ -1107,6 +1084,10 @@ Condividi + + Salva come PDF + + Impossibile generare il PDF Invia a dispositivo @@ -1118,9 +1099,11 @@ Copiato negli appunti - Accedi per sincronizzare + Accedi per sincronizzare Accedi per sincronizzare + + Sincronizza e salva i dati Invia a tutti i dispositivi @@ -1132,7 +1115,7 @@ Per inviare una scheda, accedi all’account Firefox su almeno un altro dispositivo. - Tutto chiaro + OK Impossibile condividere con questa app @@ -1159,6 +1142,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Imposta %1$s come browser predefinito + + Prova la navigazione anonima + + Naviga senza salvare cookie o cronologia in %1$s + Raccolta eliminata @@ -1254,8 +1243,6 @@ Esci - - Questa azione eliminerà tutti i dati di navigazione. Intervallo di tempo da cancellare @@ -1289,34 +1276,21 @@ Gruppo eliminato - - Benvenuto in %s. Benvenuti in un Internet migliore Un browser realizzato per le persone, non per il profitto. - - Sincronizza Firefox tra vari dispositivi - Riprendi da dove ti eri interrotto - - Porta segnalibri, cronologia e password di %1$s su questo dispositivo. + Riprendi da dove eri rimasto Sincronizza le schede e le password tra i tuoi dispositivi per passare da uno schermo all’altro senza interruzioni. - - Registrati Accedi La sincronizzazione è attiva - - Privacy sempre attiva Progettato per la protezione della privacy - - %1$s blocca automaticamente le società che, di nascosto, cercano di seguire le tue attività sul Web. Ora con Protezione totale per i cookie, che impedisce l’utilizzo dei cookie per seguire le tue attività online attraverso diversi siti. @@ -1329,17 +1303,10 @@ Blocca più elementi traccianti. Le pagine verranno caricate più velocemente, ma alcune caratteristiche della pagina potrebbero non funzionare correttamente. Scegli la posizione della barra degli strumenti - - Metti la barra degli strumenti a portata di mano. Tienila in basso o spostala in alto. Tienila in basso o spostala in alto. - - La tua privacy I tuoi dati, la tua scelta - - %s è progettato per darti il pieno controllo sulle informazioni che condividi online e con noi. Firefox ti garantisce il pieno controllo sulle informazioni che condividi online e con noi. @@ -1519,7 +1486,7 @@ The first parameter is number of long clicks left to enable the menu --> Menu di debug: %1$d clic rimasto/i per attivare Menu di debug attivato - + Copia @@ -1527,10 +1494,10 @@ Incolla e vai Incolla - + URL copiato negli appunti - + Agg. a schermata principale @@ -1915,7 +1882,7 @@ Per aggiungere una nuova scorciatoia è necessario rimuoverne una esistente. Toccare il sito da eliminare tenendo premuto e selezionare rimuovi. - OK, tutto chiaro + OK Scorciatoie @@ -1981,7 +1948,9 @@ Scopri altre storie - Sviluppato con tecnologia Pocket + Sviluppato con tecnologia Pocket + + Con tecnologia %s. Parte della famiglia Firefox. %s @@ -1995,4 +1964,14 @@ Vai alle impostazioni Firefox Suggest + + + + comprimi + + espandi + + apri il link per ulteriori informazioni su questa raccolta + + leggere l’articolo diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index cdb3cf4c0..6b520fe7b 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -14,6 +14,12 @@ השבתת גלישה פרטית חיפוש או הכנסת כתובת + + חיפוש בהיסטוריה + + חיפוש בסימניות + + חיפוש לשוניות נא להקליד מונחים לחיפוש @@ -40,8 +46,6 @@ - סימניות אחרונות - נשמרו לאחרונה הצגת כל הסימניות השמורות @@ -130,13 +134,6 @@ כפתור להצגת כל הלשוניות האחרונות - - החיפוש שלך עבור ״%1$s״ - - - %d אתרים הצגת כל הלשוניות המסונכרנות @@ -257,39 +254,20 @@ הגדרות חיפוש - - - מה חדש ב־%1$s - - עכשיו קל יותר לחזור למקום שבו הפסקת. - - מסך בית מותאם אישית של %1$s - - ניתן לעבור ללשוניות הפתוחות שלך, לסימניות ולהיסטוריית הגלישה שלך. - - לשוניות נקיות ומאורגנות - - ניקוי עומס הלשוניות עם פריסה משופרת ואפשרות לסגירה אוטומטית של לשוניות. - - חיפושים אחרונים - - - ניתן לבקר שוב בחיפושים האחרונים שלך ממסך הבית והלשוניות שלך. - - - כעת קל יותר להמשיך מהמקום שבו הפסקת, במסך הבית של Firefox המותאם אישית שלך. ניתן למצוא את הלשוניות האחרונות, הסימניות ותוצאות החיפוש שלך. + + הפעם לחפש את: + + הפעם לחפש ב: + + הכירו את דף הבית המותאם אישית שלכם. לשוניות אחרונות, סימניות ותוצאות חיפוש יופיעו כאן. - ברוכים הבאים לאינטרנט עצמאי - ברוכים הבאים לאינטרנט אישי יותר יותר צבעים. פרטיות טובה יותר. אותה המחויבות לאנשים על פני רווחים. - לקפוץ מהטלפון למחשב הנייד ובחזרה - מעבר בין מסכים קל מאי פעם אפשר להמשיך מאיפה שעצרת עם לשוניות ממכשירים אחרים בעמוד הבית שלך. @@ -303,6 +281,9 @@ הלשוניות שלך מסתנכרנות! אפשר להמשיך מאיפה שהפסקת משאר המכשירים שלך. + + סגירה + פתיחת לשונית %1$s חדשה @@ -352,6 +333,7 @@ הוספת קיצור דרך לגלישה פרטית מצב HTTPS בלבד + מנסה להתחבר באופן אוטומטי לאתרים באמצעות פרוטוקול ההצפנה HTTPS לצורך אבטחה מוגברת. @@ -461,8 +443,12 @@ a section where users see a list of tabs that they have visited in the past few days --> נצפו לאחרונה - Pocket + Pocket + + סיפורים מעוררי מחשבה + + מאמרים המופעלים על־ידי %s סיפורים ממומנים @@ -482,12 +468,6 @@ לנסות שוב מידע נוסף - - החלפת הרקע על־ידי נגיעה בלוגו דף הבית של Firefox - - - הלוגו של Firefox - החלפת תמונת הרקע, כפתור ‏%s קלאסי @@ -634,6 +614,17 @@ סגירה + + לפתוח %d לשוניות? + + פתיחת כמות גדולה כזאת של לשוניות עשויה להאט את %s בזמן שהדפים נטענים. האם ברצונך להמשיך? + + פתיחת לשוניות + + ביטול + אתר אחד @@ -664,8 +655,6 @@ רשימה רשת - - קיבוץ אתרים קשורים סגירת לשוניות @@ -818,19 +807,6 @@ אין היסטוריה כאן - - סונכרן ממכשירים אחרים - - ממכשירים אחרים - - - יש להיכנס כדי לצפות בהיסטוריה המסונכרנת משאר מהמכשירים שלך. - - - כניסה - - או יצירת חשבון Firefox כדי להתחיל לסנכרן]]> - ההורדות הוסרו @@ -880,6 +856,10 @@ פתיחה בלשונית חדשה פתיחה בלשונית פרטית + + פתיחת הכל בלשוניות חדשות + + פתיחת הכל בלשוניות פרטיות מחיקה @@ -1059,6 +1039,10 @@ שיתוף + + שמירה כ־PDF + + לא ניתן ליצור PDF שליחה למכשיר @@ -1070,9 +1054,11 @@ הועתק ללוח - כניסה כדי לסנכרן + כניסה כדי לסנכרן התחברות אל Sync + + סנכרון ושמירת נתונים שליחה לכל המכשירים @@ -1109,6 +1095,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> הגדרת %1$s כדפדפן ברירת המחדל שלך + + נסו את הגלישה הפרטית + + גלישה ללא עוגיות או היסטוריה שמורים ב־%1$s + האוסף נמחק @@ -1232,33 +1224,20 @@ הקבוצה נמחקה - - ברוכים הבאים אל %s! ברוכים הבאים לאינטרנט טוב יותר דפדפן שנבנה לטובת בני אדם, לא למטרות רווח. - - סנכרון Firefox בין מכשירים להמשיך מאיפה שהפסקת - - משיכת הסימניות, ההיסטוריה והססמאות ל־%1$s במכשיר הזה. סנכרון לשוניות וססמאות בין מכשירים למעבר חלק בין מסכים. - - הרשמה כניסה הסנכרון פעיל - - פרטיות תמיד מופעלת הגנה על הפרטיות כברירת מחדל - - ‏%1$s מונע באופן אוטומטי מחברות לעקוב אחריך בסתר ברחבי הרשת. הגנת עוגיות מלאה מונעת מרכיבי מעקב להשתמש בעוגיות כדי לעקוב אחריך בין אתרים. @@ -1271,18 +1250,11 @@ חוסם יותר רכיבי מעקב כדי שדפים ייטענו מהר יותר, אך ייתכן שפונקציונליות בדפים מסויימים לא תעבוד. בחירת מיקום סרגל הכלים שלך - - לשים את סרגל הכלים בהישג יד. ניתן להשאיר אותו בתחתית, או להעביר אותו למעלה. אפשר להשאיר אותו למטה, או להזיז אותו למעלה. - - הפרטיות שלך הנתונים שלך בשליטתך - - עיצבנו את %s כדי להעניק לך שליטה במה שמעניין אותך לשתף ברשת ומה שמעניין אותך לשתף איתנו. ‏Firefox מעניק לך שליטה במה שמעניין אותך לשתף ברשת ומה שמעניין אותך לשתף איתנו. @@ -1919,7 +1891,9 @@ לגלות עוד - מופעל באמצעות Pocket + מופעל באמצעות Pocket + + מופעל על־ידי %s. חלק ממשפחת Firefox. %s @@ -1933,4 +1907,14 @@ מעבר להגדרות הצעות של Firefox + + + + לכווץ + + להרחיב + + לפתוח קישור כדי ללמוד עוד על אוסף זה + + לקרוא את המאמר diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 44f9f4108..4ee863e42 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -17,6 +17,12 @@ 検索語またはアドレスを入力 + + 履歴を検索 + + ブックマークを検索 + + タブを検索 検索語を入力 @@ -42,9 +48,6 @@ 選択 - - 最近追加したブックマーク - 最近保存 @@ -68,7 +71,7 @@ プライベートタブを開くショートカットをホーム画面に追加します。 - ショートカットを追加 + 追加する 追加しない @@ -135,13 +138,6 @@ 最近のタブをすべて表示するボタンです - - \"%1$s\" についての検索 - - - %d サイト 同期したタブをすべて見る @@ -265,39 +261,21 @@ 検索設定 - - - %1$s の新機能 - - 前回のページから再開するのが簡単になりました。 - - 個人に合わせた %1$s ホームページ - - 開いているタブ、ブックマーク、閲覧履歴にジャンプします。 - - きれいに整理されたタブ - - 改善されたレイアウトとタブを自動的に閉じる機能で散らかったタブを片付けます。 - - 最近の検索 - - ホームページとタブから最近の検索を確認できます。 - - - 個人に合わせた Firefox ホームページにより、前回のページから簡単に再開できるようになりました。最近のタブ、ブックマーク、検索結果を見つけられます。 + + 今回の検索: + + + 今回だけ使う検索エンジン: + パーソナライズされたホームページをご覧ください。最近使ったタブ、ブックマーク、検索結果がここに表示されます。 - - 誰のものでもない自由なインターネットへようこそ あなただけのインターネットへようこそ 多様なカラー、より優れたプライバシー保護、利益を超えて人々への平等なコミットメント。 - スマートフォンとラップトップの間を行ったり来たり - 画面の切り替えがこれまで以上に簡単に ホームページ上で、他の端末のタブの中断したところから再開できます。 @@ -310,6 +288,9 @@ タブが同期されます! 他の端末の中断したところから再開しましょう。 + + 閉じる + %1$s の新しいタブで開く @@ -360,6 +341,15 @@ プライベートブラウジングショートカットを追加する HTTPS-Only モード + + + Cookie バナーの削減 + + Cookie バナーを減らす + + + Firefox が自動的に Cookie バナーによる Cookie 要求を拒否しようとします。拒否オプションが利用できない場合、すべての Cookie を受け入れてバナーを閉じることがあります。 + セキュリティ強化のため、自動的に HTTPS 暗号化プロトコルを使用してサイトへの接続を試行します。 @@ -467,8 +457,12 @@ a section where users see a list of tabs that they have visited in the past few days --> 最近訪れたサイト - Pocket + Pocket + + 示唆に富むストーリー + + %s が提供する記事 広告ストーリー @@ -491,12 +485,6 @@ 壁紙を変更できませんでした 詳細情報 - - Firefox ホームページのロゴをタップして壁紙を変更する - - - Firefox ロゴ - 壁紙変更ボタンです %s の定番 @@ -655,6 +643,17 @@ 閉じる + + %d 個のタブを開きますか? + + この操作で多くのタブを開くと、ページの読み込み中に %s が遅くなる可能性があります。続行してもよろしいですか? + + タブを開く + + キャンセル + %d サイト @@ -684,10 +683,6 @@ リスト グリッド - - タブグループを検索 - - 関連サイトをグループ化します タブを閉じる期間 @@ -841,18 +836,6 @@ 履歴はありません - - 他の端末から同期 - - 他の端末から - - - 他の端末と同期した履歴を表示するにはログインしてください。 - - ログイン - - または Firefox アカウントを作成して同期を開始します]]> - ダウンロード履歴を削除しました @@ -903,6 +886,10 @@ 新しいタブで開く プライベートタブで開く + + すべてを新しいタブで開く + + すべてをプライベートタブで開く 削除 @@ -1084,6 +1071,10 @@ 共有 + + PDF として保存 + + PDF を生成できません 端末へ送信 @@ -1095,9 +1086,11 @@ クリップボードにコピーしました - ログインして同期 + ログインして同期 Sync にログイン + + 同期してデータを保存 すべての端末へ送信 @@ -1135,6 +1128,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s を既定のブラウザーに設定しましょう + + プライベートブラウジングを試す + + Cookie や履歴を %1$s に保存せずに閲覧します + コレクションを削除しました @@ -1260,33 +1259,20 @@ グループを削除しました - - %s へようこそ! より良いインターネットへようこそ 利益ではなく、ユーザーのために作られているブラウザー。 - - 端末間で Firefox を同期 やめたところから再開できます - - この端末の %1$s とブックマーク、履歴、パスワードを同期します。 端末間でタブとパスワードを同期して、シームレスに画面を切り替えられます。 - - アカウント登録 ログイン Sync が有効です - - プライバシー重視 初期設定でプライバシー保護 - - %1$s はウェブ上であなたを密かに追跡する組織を自動的に遮断します。 包括的 Cookie 保護機能が、Cookie を利用してサイト間であなたを追跡するトラッカーを遮断します。 @@ -1299,17 +1285,10 @@ より多くのトラッカーをブロックするとページの読み込みが速くなりますが、一部のページは正しく機能しなくなる可能性があります。 ツールバーの配置を選べます - - ツールバーを簡単に手の届く位置に置きましょう。画面下または上に移動できます。 画面下または上に移動できます。 - - あなたのプライバシー あなたのデータはあなたのもの - - %s は、あなたがオンラインで共有するものと、私たちと共有するものをコントロールできるように設計されています。 Firefox は、あなたがオンラインで共有するものと、私たちと共有するものをコントロールできます。 @@ -1488,7 +1467,7 @@ The first parameter is number of long clicks left to enable the menu --> デバッグメニュー: 有効にするには %1$d 回クリックしてください デバッグメニューが有効です - + コピー @@ -1496,10 +1475,10 @@ 貼り付けて移動 貼り付け - + URL をクリップボードにコピーしました - + ホーム画面に追加 @@ -1952,7 +1931,9 @@ より詳しく - Powered by Pocket. + Powered by Pocket. + + %s による提供です。 Firefox ファミリーの一員です。 %s @@ -1966,4 +1947,14 @@ 設定を開く Firefox Suggest + + + + 折りたたむ + + 展開する + + このコレクションの詳細についてはリンク先をご覧ください + + 記事を読む diff --git a/app/src/main/res/values-ka/strings.xml b/app/src/main/res/values-ka/strings.xml index 9578d476e..ec3e672ff 100644 --- a/app/src/main/res/values-ka/strings.xml +++ b/app/src/main/res/values-ka/strings.xml @@ -14,6 +14,12 @@ პირადი თვალიერების გამორთვა მოძებნეთ ან შეიყვანეთ მისამართი + + ძიების ისტორია + + სანიშნების ძიება + + ჩანართების ძიება შეიყვანეთ საძიებო ფრაზა @@ -39,8 +45,6 @@ - ბოლოს ჩანიშნული - ბოლოს შენახული ყველა ჩანიშნულის ჩვენება @@ -126,13 +130,6 @@ ყველა ბოლო ჩანართის ღილაკის ჩვენება - - მოძიებული „%1$s“ - - - %d საიტი ყველა დასინქრონებულის ნახვა @@ -252,40 +249,21 @@ ძიების პარამეტრები - - - რა სიახლეებითაა %1$s - - მარტივად განაგრძეთ იქიდან, სადაც შეჩერდით. - - მორგებული %1$s-გვერდი საწყისად - - გადადით გახსნილ ჩანართებზე, სანიშნებსა და მონახულებულ გვერდებზე. - - სუფთა, მოწესრიგებული ჩანართები - - - აირიდეთ ჩანართების არეულობა, დახვეწილი განლაგებითა და თვითდახურვით. - - ბოლოს მოძიებული - - კვლავ მოინახულეთ ბოლოს მოძიებულები, საწყისი გვერდიდან და ჩანართებიდან. - - - Firefox-ის მორგებული საწყისი გვერდით შეძლებთ, მარტივად განაგრძოთ იქიდან, სადაც შეჩერდით. იპოვეთ ბოლოს გახსნილი ჩანართები, სანიშნები და მოძიებული გვერდები. + + საძიებოდ გამოიყენეთ: + + საძიებოდ გამოიყენეთ: + + გაეცანით მორგებულ საწყის გვერდს. ბოლოდროინდელი ჩანართები, სანიშნები და მოძიებული გვერდები გამოჩნდება აქ. - - კეთილი იყოს თქვენი ფეხი დამოუკიდებელ ინტერნეტსივრცეში კეთილი იყოს თქვენი ფეხი მეტად პირად ინტერნეტსივრცეში მეტი ფერი. გაუმჯობესებული პირადულობა. ხალხის მოგებაზე წინ დაყენება მუდამ. - მოქნილად გადაერთეთ ტელეფონიდან ლეპტოპზე და უკან - ეკრანებს შორის გადართვა ჯერ არნახული სიმარტივით განაგრძეთ, სადაც გაჩერდით სხვა მოწყობილობიდან ჩანართების წამოღებით ახლა უკვე საწყის გვერდზე. @@ -298,6 +276,9 @@ თქვენი ჩანართები სინქრონდება! განაგრძეთ იქიდანვე, სადაც შეჩერდით სხვა მოწყობილობაზე. + + დახურვა + ახალი %1$s-ჩანართის გახსნა @@ -349,6 +330,14 @@ პირადი თვალიერების მალსახმობის დამატება მხოლოდ-HTTPS-რეჟიმი + + + ფუნთუშის მოთხოვნების შემცირება + + შეამცირეთ ფუნთუშის მოთხოვნები + + Firefox თავადვე შეეცდება უარყოს ფუნთუშის მოთხოვნები საიტზე ამომხტარ აბრებზე. თუ უარყოფა ვერ მოხერხდება, Firefox შეიძლება ყველა ფუნთუშის მიღებას დათანხმდეს ამომხტომი აბრის მოსაცილებლად. + თავადვე შეეცდება დაუკავშირდეს საიტებს დაშიფრული HTTPS-ოქმით, მეტი უსაფრთხოებისთვის. @@ -455,8 +444,12 @@ a section where users see a list of tabs that they have visited in the past few days --> ბოლოს ნანახი - Pocket + Pocket + + მეტად დამაფიქრებელი ამბები + + სტატიებს გთავაზობთ %s დაფინანსებული ამბები @@ -479,12 +472,6 @@ ფონის შეცვლა ვერ მოხერხდა ვრცლად - - შეცვალეთ ფონი Firefox-ის საწყისი გვერდის ნიშანზე შეხებით - - - Firefox-ლოგო – შეცვალეთ ფონი, ღილაკი ჩვეული %s @@ -643,6 +630,17 @@ დახურვა + + გაიხსნას %d ჩანართი? + + ბევრი ჩანართის გახსნამ შესაძლოა შეანელოს %s გვერდების ჩატვირთვისას. ნამდვილად გსურთ, განაგრძოთ? + + ჩანართების გახსნა + + გაუქმება + %d საიტი @@ -672,10 +670,6 @@ სია ბადისებრი - - ძიების ჯგუფები - - დაკავშირებული საიტების დაჯგუფება ჩანართების დახურვა @@ -826,18 +820,6 @@ ისტორია არ არის - - სხვა მოწყობილობებიდან დასინქრონებული - - სხვა მოწყობილობებიდან - - - შედით თქვენი სხვა მოწყობილობებიდან ისტორიის სანახავად. - - შესვლა - - ან შექმენით Firefox-ანგარიში სინქრონიზაციისთვის]]> - ჩამოტვირთვები მოცილებულია @@ -888,6 +870,10 @@ პირად ჩანართში გახსნა + + ყველას ახალ ჩანართებში გახსნა + + ყველას პირად ჩანართებში გახსნა წაშლა @@ -1065,6 +1051,10 @@ გაზიარება + + შენახვა PDF-სახით + + ვერ ხერხდება PDF-ის შექმნა მოწყობილობაზე გაგზავნა @@ -1076,9 +1066,11 @@ ასლი აღებულია - სინქრონიზაციაში შესვლა + სინქრონიზაციაში შესვლა დასინქრონებაში შესვლა + + დასინქრონება და შენახვა ყველა მოწყობილობაზე გაგზავნა @@ -1115,6 +1107,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> გახადეთ %1$s ნაგულისხმევი ბრაუზერი + + გამოცადეთ პირადი რეჟიმი + + გვერდების მონახულებისას %1$s არ შეინახავს ისტორიასა და ფუნთუშებს + კრებული წაიშალა @@ -1236,34 +1234,21 @@ ჯგუფი წაიშალა - - მოგესალმებათ %s! მოგესალმებით უკეთეს ინტერნეტში ბრაუზერი შექმნილი ხალხისთვის, და არა მოგებისთვის - - დაასინქრონეთ Firefox მოწყობილობებს შორის განაგრძეთ იქიდან, სადაც გაჩერდით. - - გადმოიტანს სანიშნებს, ისტორიასა და პაროლებს, ამ მოწყობილობის %1$s-ზე. დაასინქრონეთ ჩანართები და პაროლები მოწყობილობებს შორის შეუფერხებლად გადასვლისთვის. - - ანგარიშის შექმნა შესვლა სინქრონიზაცია ჩართულია - - ყოველთვის პირადული პირადულობის ნაგულისხმევი დაცვა - - %1$s ავტომატურად უზღუდავს კომპანიებს თქვენს მოქმედებებზე ფარულად თვალის მიდევნების საშუალებას ვებსივრცეში. ფუნთუშებისგან ყოველმხრივი დაცვით მეთვალყურეებს არ ექნებათ საშუალება, თვალი გადევნონ ვებსივრცეში ფუნთუშების გამოყენებით. @@ -1276,17 +1261,10 @@ ზღუდავს მეტ მეთვალყურეს, გვერდის ჩატვირთვა ასწრაფდება, თუმცა გამართულად შეიძლება ვერ იმუშაოს. აირჩიეთ ხელსაწყოთა ზოლის მდებარეობა - - განათავსეთ ხელსაწყოები მოხერხებულ ადგილას. დატოვეთ ქვემოთ ან გადაიტანეთ ზემოთ. დატოვეთ ქვემოთ ან გადაიტანეთ ზემოთ. - - თქვენი პირადულობა თქვენი მონაცემები თქვენს ხელშია - - %s შექმნილია ისე, რომ თავად წყვეტდეთ რას გააზიარებთ ინტერნეტში და რას გაგვიზიარებთ ჩვენ. %s საშუალებას იძლევა, რომ თავად წყვეტდეთ, რას გააზიარებთ ინტერნეტში და რას გაგვიზიარებთ ჩვენ. @@ -1929,7 +1907,9 @@ აღმოაჩინეთ მეტი - უზრუნველყოფს Pocket. + უზრუნველყოფს Pocket. + + უზრუნველყოფს %s. Firefox ოჯახის ნაწილი. %s @@ -1943,4 +1923,14 @@ პარამეტრებზე გადასვლა Firefox-შეთავაზება + + + + აკეცვა + + გაშლა + + გახსენით ბმული და იხილეთ ვრცლად ამ კრებულზე + + სტატიის წაკითხვა diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index b8316de02..437be09a2 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -15,6 +15,12 @@ Nadi neɣ sekcem tansa + + Nadi deg uzray + + Nadi ticraḍ n yisebtar + + Nadi deg waccaren Sekcem awalen n unadi @@ -43,8 +49,6 @@ - Ticraḍ n yisebtar n melmi kan - Yettwasekles melmi kan Sken akk ticraḍ n yisebtar yettwaskelsen @@ -133,13 +137,6 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Sken tqeffalt n meṛṛa accaren n melmi kan - - Anadi-inek•inem i \"%1$s\" - - - %d yismal Wali akk accaren yemtawan @@ -261,39 +258,20 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Nadi ismenyifen - - - D acu i d maynut deg %1$s - - Akka tura fessus ad tkemmleḍ ansi akken i tḥebseḍ. - - Asebter agejdan n %1$s yettwasagnen - - Ɛeddi ɣer waccaren yeldin, ticraḍ n yisebtar, d uzray n tunigin. - - Accaren zeddigen, yuddsen - - - Sfeḍ accaren ur tesriḍ ara s taneɣruft igerrzen akked waccaren n umdal awurman. - - Inadiyen imaynuten - - Ales rzu ɣer yinadiyen ineggura seg usebtar-inek•inem d waccaren. - - - Asebter-inek•inem n Firefox udmawan yettarra tura fessus ugar akemmel seg wanda akken i tḥebseḍ. Af accaren-ik•im n melmi kan, ticraḍ n yisebtar, d yigmaḍ n unadi. + + Tura nadi wagi: + + I unadi-a: + + Snirem asebtar-ik·im agejdan yettwasagnen. Accaren imaynuten, ticraḍ n yisebtar d yigmaḍ n unadi ad d-banen deg-s. - Ansuf ɣer internet ilelli - Ansuf ɣer internet udmawan ugar Ugar n yiniten. Tudert tabaḍnit igerrzen ugar. Tuṭṭfa deg tbaḍnit n yimdanen mačči d anadi ɣef tedrimt. - Ɛeddi seg tiliɣri ɣer uselkim, neɣ seg uselkim ɣer tiliɣri - Abeddel seg ugdil ɣer wayeḍ fessus ugar ɣef wayen iɛeddan Kemmel seg wanda i tḥebseḍ s useqdec n waccaren ɣef yibenkan-nniḍen ara d-ibanen akka tura ɣef usebter-ik·im agejdan. @@ -307,6 +285,9 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Accaren-ik·im mtawan! Kemmel seg wanda i tḥebseḍ ɣef yibenk-ik·im-nniḍen. + + Mdel + Ldi-t iccer amaynut %1$s @@ -357,6 +338,7 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Rnu anegzum i tunigin tusligin Askar HTTPS-Only + Ɛreḍ ad teqqneḍ s wudem awurman ɣer yismal s useqdec n uneggaf n uwgelhen HTTPS i tɣellist ɛlayen. @@ -465,8 +447,12 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara a section where users see a list of tabs that they have visited in the past few days --> Yemmẓer melmi kan - Pocket + Pocket + + Tiqsiḍin i ijebbden lwelha + + Imagraden yellan ddaw leɛnaya n %s Tiqṣidin yettwarefden @@ -491,12 +477,6 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Tegguma ad tbeddel tugna n ugilal Issin ugar - - Beddel tugna n ugilal s tira n ulugu n usebter agejdan n Firefox - - - Alogo Firefox - beddel agilal, taqeffalt Aklasik %s @@ -656,6 +636,17 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Mdel + + Ldi %d waccaren? + + Tawaledyawt n wannect-a n waccaren yessaẓay %s mi ara d-ttalin yisebtar. D tidet tebɣiḍ ad tkemmleḍ? + + Ldi accaren + + Sefsex + %d n usmel @@ -685,10 +676,6 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Tabdart Iẓiki - - Igrawen n unadi - - Ismal n yinagrawen i d-yittuɣalen lwaḥid Mdel iccaren @@ -843,19 +830,6 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Ulac amazray dagi - - Yemtawi seg yibenk-nniḍen - - Seg yibenkan-nniḍen - - - Qqen akken ad twaliḍ azray yemtawan seg yibenkan-ik-nniḍen. - - Qqen - - - Neɣ fren amiḍan Firefox i beddu n umtawi]]> - Isadaren ttwakksen @@ -906,6 +880,10 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Ldi-t deg yiccer amaynut Ldi deg iccer uslig + + Ldi kullec deg waccaren imaynuten + + Ldi kullec deg waccaren usligen Kkes @@ -1084,6 +1062,10 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Bḍu + + Kles d PDF + + D awezɣi ad yettusirew PDF Azen ɣer yibenk @@ -1095,9 +1077,11 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Ittwanɣel ɣeṛ tecfawt - Kcem akken ad tsemtawiḍ + Kcem akken ad tsemtawiḍ Qqen ɣer Sync + + Mtawi sakin sekles isefka Azen ɣer yibenkan meṛṛa @@ -1134,6 +1118,9 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara %1$s is a placeholder that will be replaced by the app name (Fenix). --> Err %1$s d iminig-ik amezwer + + Ɛreḍ tunigin tusligt + Tettwakkes tegrumma @@ -1256,29 +1243,22 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Agraw yettwakksen - - Ansuf ɣer %s! Ansuf ɣer internet ifazen - - Mtawi Firefox gar yibenkan + + D iminig i yettwafeṣṣlen i yimdanen, yerna baṭel. Kemmel seg wanida i tḥebseḍ - - Awi-d ticraḍ n yisebtar, amazray, d wawalen uffiren ɣer %1$s deg yibenk-a. - - Jerred + + Mtawi accaren d wawalen uffiren gar yibenkan-ik·im i wakken add tɛeddiḍ seg ugdil ɣer wayeḍ s wudem afrawan. Kcem Amtawi yermed - - Tabaḍnit tezga tettwaḍmen Ammesten n tudert tabaḍnit s wudem amezwer - - %1$s yessewḥal s wudem awurman tikebbaniyin ara ak-iḍefren deg web. + + Ammesten asemday mgal y inagan n tuqqna yessewḥal ineḍfaren ad sqedc inagan n tuqqna i wakken ad ak•akem-ḍefren deg web. Alugan (amezwer) @@ -1289,18 +1269,13 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Isewḥal ugar n ineḍfaren akken isebtar ad d-allin s wudem aurad, maca kra n tmahilin n usebter zemrent ad rẓent. Fren adig n ufeggag-ik·im n yifecka - - Eǧǧ afeggag n yifecka ɣef wafus. Eǧǧ-it ddaw neɣ err-it d asawen. Eǧǧ-it ukessar neɣ err-it d asawen - - Tabaḍnit inek/m Ad tiliḍ d aɛessas ɣef yisefka-k - - Nfeṣṣel %si w akken ad nerr gar ifassen-ik·im ayen i tbeṭṭuḍ srid aked wayen tbeṭṭuḍ yid-neɣ. + + Firefox ad yerr gar ifassen-ik·im ayen i tbeṭṭuḍ srid akked wayen tbeṭṭuḍ yid-neɣ. Ɣer tasertit-nneɣ n tbaḍnit @@ -1941,7 +1916,9 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Issin ugar - Sɣur Pocket. + Sɣur Pocket. + + Ddaw leɛnaya n %s. D aḥric seg twacult Firefox. %s @@ -1955,4 +1932,14 @@ Tiktiwin tigejdanin yuzzlen ur nṣeḥḥi ara Ddu ɣer yiɣewwaren Firefox Suggest + + + + fneẓ + + snefli + + Ldi aseɣwen i wakken ad tissineḍ ugar ɣef tefrant-a. + + ɣer amagrad diff --git a/app/src/main/res/values-kk/strings.xml b/app/src/main/res/values-kk/strings.xml index 744402d83..52653816a 100644 --- a/app/src/main/res/values-kk/strings.xml +++ b/app/src/main/res/values-kk/strings.xml @@ -15,6 +15,12 @@ Іздеу немесе адресті енгізу + + Тарихтан іздеу + + Бетбелгілерден іздеу + + Беттерден іздеу Іздеу жолын енгізіңіз @@ -39,8 +45,6 @@ - Жуырдағы бетбелгілер - Жуырда сақталған Барлық сақталған бетбелгілерді көрсету @@ -128,13 +132,6 @@ Барлық соңғы беттерді көрсету батырмасы - - \"%1$s\" бойынша іздеуіңіз - - - %d сайт Барлық синхрондалған беттерді қарау @@ -255,38 +252,20 @@ Іздеу баптаулары - - - %1$s ішінде не жаңалық - - Енді тоқтаған жерден жалғастыру оңайырақ. - - Жеке %1$s басты беті - - Ашық беттер, бетбелгілер және шолу тарихына өтіңіз. - - Таза, реттелген беттер - - Беттер енді жақсартылған орналастыру және автожабуды қолдану салдарынан көбірек реттелген болды. - - Жуырдағы іздеулер - - Үй беті және беттерден соңғы іздеулеріңізді қайта қараңыз. - - - Сіздің жекелендірілген Firefox үй беті енді тоқтаған жерден жалғастыруды жеңілдетеді. Соңғы беттерді, бетбелгілерді және іздеу нәтижелерін табыңыз. + + Бұл жолы іздеу: + + Бұл жолы келесі жерде іздеу: + + Жекелендірілген басты бетпен танысыңыз. Мұнда соңғы беттер, бетбелгілер және іздеу нәтижелері көрсетілетін болады. - Тәуелсіз интернетке қош келдіңіз - Жекелігі көбірек интернетке қош келдіңіз Қосымша түстер. Жақсырақ жекелік. Табыстан гөрі адамдарға бірдей міндеттеме. - Телефоннан ноутбукке және кері өтіңіз - Экрандарды ауыстыру бұрынғыдан оңайырақ Енді басты бетте орналасқан басқа құрылғылардың беттері арқылы тоқтаған жерден жалғастырыңыз. @@ -300,6 +279,9 @@ Сіздің беттеріңіз синхрондалуда! Осында басқа құрылғыда тоқтаған жерден жалғастырыңыз. + + Жабу + Жаңа %1$s бетін ашу @@ -349,6 +331,14 @@ Жеке шолу жарлығын қосу Тек-HTTPS режимі + + + Cookie баннерлерін азайту + + Cookie баннерлерін азайту + + Firefox cookie баннерлеріндегі cookie сұрауларын автоматты түрде қабылдамау әрекетін жасайды. Қабылдамау опциясы қол жетімді болмаса, Firefox баннерді жабу үшін барлық cookie файлдарын қабылдауы мүмкін. + Қауіпсіздікті арттыру үшін сайттарға HTTPS шифрлеу хаттамасын пайдаланып автоматты түрде қосылу әрекетін жасайды. @@ -454,8 +444,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Жуырда қаралған - Pocket + Pocket + + Ойландыратын әңгімелер + + %s ұсынған мақалалар Демеушілер мақалалары @@ -478,12 +472,6 @@ Тұсқағазды өзгерту мүмкін болмады Көбірек білу - - Firefox басты бетінің логотипін түрту арқылы тұсқағазды өзгертіңіз - - - Firefox логотипі - тұсқағазды, батырманы өзгерту Классикалық %s @@ -580,7 +568,7 @@ - Деректерді синхрондау және сақтау + Синхрондау және деректерді сақтау Қайта байланысу үшін кіру @@ -638,6 +626,17 @@ Жабу + + %d бетті ашу керек пе? + + Осыншама көп бетті ашу ол беттер жүктелгенше %s жұмысын баяулатуы мүмкін. Осыны растайсыз ба? + + Беттерді ашу + + Бас тарту + %d сайт @@ -667,14 +666,10 @@ Тізім Тор - - Іздеу топтары - - Байланысқан сайттарды біріктіру Беттерді жабу - Қолмен + Ешқашан Бір күннен кейін @@ -821,18 +816,6 @@ Осында тарих жоқ - - Басқа құрылғыдан синхрондалған - - Басқа құрылғылардан - - - Басқа құрылғыларыңыздан синхрондалған тарихты көру үшін жүйеге кіріңіз. - - Кіру - - Немесе синхрондауды бастау үшін Firefox тіркелгісін жасаңыз]]> - Жүктемелер өшірілді @@ -882,6 +865,10 @@ Жаңа бетте ашу Жекелік бетте ашу + + Барлығын жаңа беттерде ашу + + Барлығын жаңа жекелік беттерде ашу Өшіру @@ -1059,6 +1046,10 @@ Бөлісу + + PDF ретінде сақтау + + PDF жасау мүмкін емес Құрылғыға жіберу @@ -1070,9 +1061,11 @@ Алмасу буферіне көшірілді - Синхрондау ішіне кіру + Синхрондау ішіне кіру Синхрондау ішіне кіру + + Синхрондау және деректерді сақтау Барлық құрылғыларға жіберу @@ -1108,6 +1101,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s негізгі браузер қылу + + Жекелік шолуды қолданып көріңіз + + %1$s ішінде сақталған cookie файлдарсыз және тарихсыз шолыңыз + Жинақ өшірілді @@ -1230,34 +1229,21 @@ Топ өшірілді - - %s өніміне қош келдіңіз! Жақсырақ интернетке қош келдіңіз Табыс үшін емес, адамдар үшін жасалған браузер. - - Firefox-ты құрылғылар арасында синхрондау Жұмысты қалдырған жерінен жалғастырыңыз - - Осы құрылғыдағы %1$s ішіне бетбелгілер, шолу тарихын және парольдерді әкелу. Экранды оңай ауыстыру үшін беттер мен парольдерді құрылғылар арасында синхрондаңыз. - - Тіркелу Кіру Синхрондау іске қосулы - - Үздіксіз құпиялылық Үнсіз келісім бойынша жекелікті қорғау - - %1$s компанияларды интернетте сізді жасырын түрде бақылауын автоматты түрде тоқтатады. Трекерлерге cookie файлдарын пайдаланып, сізді сайттар арасында бақылауға жол бермеу үшін Толық қорғанысты ұсынады. @@ -1270,17 +1256,10 @@ Беттерді тезірек жүктеу үшін көбірек трекерлерді блоктайды, бірақ кейбір беттер функционалдылығы бұзылуы мүмкін. Құралдар панелінің орналасуын таңдау - - Құралдар панелін қолжетімді жерге орнату. Оны төменгі жағында ұстаңыз немесе оны жоғарыға қарай жылжытыңыз. Оны төменгі жағында ұстаңыз немесе жоғарғы жағына жылжытыңыз. - - Сіздің жекелігіңіз Өз деректеріңізді өзіңіз басқарасыз - - Біз %s өнімін сіз желіде және бізбен немен бөлісетіңізді басқаруды өз қолыңызға беретіндей етіп жасадық. Firefox сіз желіде және бізбен немен бөлісетіңізді басқаруды өз қолыңызға береді. @@ -1921,7 +1900,9 @@ Көбірек шолу - Pocket негізінде. + Pocket негізінде. + + %s негізінде. Firefox отбасының бөлігі. %s @@ -1935,4 +1916,14 @@ Баптауларға өту Firefox ұсынысы + + + + бүктеу + + жазық қылу + + осы жинақ туралы көбірек білу үшін сілтемені ашыңыз + + мақаланы оқу diff --git a/app/src/main/res/values-kmr/strings.xml b/app/src/main/res/values-kmr/strings.xml index f7b3f99d1..55b1f0a55 100644 --- a/app/src/main/res/values-kmr/strings.xml +++ b/app/src/main/res/values-kmr/strings.xml @@ -15,6 +15,12 @@ Gerîna veşartî bigire Lêgerîn an jî navnîşan + + Raboriya lêgerînê + + Di bijareyan de bigere + + Di hilpekînan de bigere Peyvên lêgerînê binivîse @@ -38,9 +44,6 @@ Hate bijartin - - Bijareyên dawiyê - Tomarbûnên dawî @@ -80,6 +83,9 @@ Bigire + + + Fonksiyona me ya ewlekariyê ya heta niha herî xurt, kodên şopandinê yên di navbera malperan de îzole dike. Li ser parastina xurekan a giştî agahî bistîne @@ -130,12 +136,6 @@ Bişkoka hemû hilpekînên kevn nîşan bide - - Lêgerîna te ya ji bo \"%1$s\" - - %d malper Hemû hilpekînên senkronîzekirî bibîne @@ -257,32 +257,20 @@ Eyarên lêgerînê - - - Tiştên nû yên %1$s`ê - - Niha hêsantir e ku vegerî ciyê lê mayî. - - Serûpela %1$s `ê ya şexsîkirî - - Here hilpekînên xwe yên vekirî, bijareyan û mêjûya lêgerînê. - - Hilpekînên serhevedayî - - - Bi pergala nû ya hilpekînan û hilpekînên xweber tên girtin tevliheviyê ji holê rakin. - - Lêgerînên dawiyê - - Vegere lêgerînên xwe yên dawiyê yên ji serûpel û hilpekînan. - - - Serûpela te ya Firefoxê ya şexsîkirî niha hêsantir dike ku tu li ciyê lê mayî dewam bikî. Hilpekîn, bijare û encamên dawiyê yên lêgerînên xwe bibîne. + + Lêgerîna niha: - - Tu bi xêr hatiyî înterneteke serbixwe + + + Serûpela xwe ya taybet nas bike. Tu yê li virê hilpekîn, bijare û encamên lêgerînên xwe yên dawiyê bibînî. Tu bi xêr hatiyî înterneteke kesanetir + + Rengên zêdetir. Ewlekariya çêtir. Ne ji bo pereyan, ji bo mirovahiyê. + + Derbasbûna ji cîhazekê bo cîhazeke din êdî hêsantir e + + Êdî hilpekînên te yên cîhazên din di serûpela te de ne. Dest pê bike @@ -290,6 +278,11 @@ Derbas bike + + Hilpekînên te tên senkronîzekirin! Di cîhazên din de li ciyê lê mayî dewam bike. + + Bigire + Hilpekînek nû ya %1$s `ê veke @@ -340,6 +333,7 @@ Kurterêya gerîna veşartî tevlî bike Moda Tenê-HTTPS + Ji bo ewlekariya zêdetir hewlê bide ku bi protokola şîfrekirî ya HTTPSê bi awayekî xweber têkeve malperan. @@ -445,8 +439,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Seredanên dawî - Pocket + Pocket + + Gotarên balkêş + + Gotar ji aliyê %sê ve tên dabînkirin Nûçeyên sponsorkirî @@ -469,15 +467,12 @@ Wêneyê dîwêr nehat guhertin Zêdetir bizane - - Ji bo guhertina wêneyê dîwêr pêlî logoya Firefoxê ya serûpelê bike - - Logoya Firefoxê - wêneyê dîwêr biguherîne, bişkok Klasîk %s + + Edîsyona Sînorkirî Koleksiyana dengên serbixwe ya nû. %s @@ -633,6 +628,14 @@ Bigire + + %d hilpekînan veke? + + Hilpekînên vekirî + + Betal bike + %d malper @@ -664,10 +667,6 @@ Grîd - - Komên lêgerînê - - Malperên têkildar bi hev re kom bikin Hilpekînan bigire @@ -818,18 +817,6 @@ Raborî tune - - Ji alavên din hatiye senkronîzekirin - - Ji alavên din - - - Têkevê da ku tu raboriya senkronîzekirî ya ji cîhazên xwe yên din bibînî. - - Têkeve - - Yan jî hesabekî Firefoxê biafirîne ku dest bi senkronîzekirinê bikî]]> - Daxistin hatin rakirin @@ -878,6 +865,10 @@ Di hilpekîna nû de veke Di hilpekîna veşartî de veke + + Gişî di hilpekînên nû de veke + + Gişî di hilpekînên veşartî de veke Jê bibe @@ -1055,6 +1046,10 @@ Parve bike + + Wekî PDF qeyd bike + + PDF nayê çêkirin Bişîne cîhazê @@ -1066,9 +1061,11 @@ Li panoyê hat kopîkirin - Ji bo senkronîzekirinê têkevê + Ji bo senkronîzekirinê têkevê Têkeve Sync’ê + + Senkronîze bike û daneyan qeyd bike Ji hemû cîhazan re bişîne @@ -1228,27 +1225,22 @@ Kom hat jêbirin - - Tu bi xêr hatî %s’ê! Tu bi xêr hatiyî înterneta baştir - - Firefoxê di navbera amûran de senkronîze bike - - Bijareyan, raboriyê û şîfreyan bîne nav %1$s`ê. - - Xwe tomar bike + + Gerokeke ji bo mirovan hatiye çêkirin, ne ji bo pereyan. + + Ji ciyê lê mayî dewam bike + + Ji bo derbasbûna bêproblem ya di navbera cîhazan de hilpekîn û şîfreyên xwe senkronîze bike. Têkeve Sync vekirî ye - - Her car -nepen Parastina nihêniyê temî vekirî ye - - %1$s bi awayekî xweber asteng dike ku şirket we li ser webê bi dizî bişopînin. + + Parastina çerezan ya bi temamî kodên şopandinê asteng dike ku nikaribin te li ser webê bişopînin. Standard (jixweber) @@ -1259,20 +1251,17 @@ Ji bo rûpel zûtir bên vekirin zêdetir şopîneran asteng dike lê dibe ku hin fonksiyonên rûpelan xira bibin. Ciyê darikê amûran hilbijêre - - Darikê amûran dayne ciyekê bi hêsanî bigihîjiyê. Dikarî wê li xwarê bihêlî yan jî bibî jorê. Li jêrê bihêle an jî bikişîne jorî. - - Nihêniya te Kontrola daneyên te di destê te de ye - - Me %s ji bo hindê çêkiriye ku derbarê tiştên tu li ser înternetê û tiştên bi me re parve dikî de kontrol di destê te de be. + + Firefox kontrola hindê dide te ka tu li ser înternetê bi kesên din û bi me re çi parve dikî. Agahdariya me ya nihêniyê bixwîne + + Tu amadeyî ku înterneteke nûwaze keşf bikî? Dest bi gerînê bike @@ -1360,6 +1349,8 @@ Hemû çerezên partiya sêyemîn (dibe ku hin malper xera bibin) Hemû çerez (dibe ku hin malper xera bibin) + + Çerezên nav-malperî îzole bike Naverokên ji bo şopandinê @@ -1382,8 +1373,12 @@ Taybetiya şopandina çalakiyên te yên gera li ser torên civakî bisînor dike. Çerezên şopandinê yên nav-malperî + + Çerezên nav-malperî Çerezên ku torên reklamê û şirketên analîtîkê ji bo şopandina gera di navbera malperên cuda de bi kar tînin asteng dike. + + Parastina çerezan a giştî, çerezan tenê ji bo malpera ku tu tê de yî îzole dike, bi xêra vê yekê torên reklaman ji bo şopandina te ya li ser malperan nikarin çerezan bi kar bînin. Kankerên krîpto @@ -1892,7 +1887,9 @@ Zêdetir keşf bike - Bi piştgiriya Pocketê. + Bi piştgiriya Pocketê. + + Bihêzkirin ji aliyê %sê. Beşeke ji malbata Firefoxê. %s @@ -1906,4 +1903,14 @@ Here eyaran Pêşniyara Firefoxê + + + + teng bike + + fireh bike + + ji bo derbarê vê koleksiyonê de bêtir bizanî, girêdankê veke + + gotarê bixwîne diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 7403aac93..8bc2db4c3 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -17,6 +17,12 @@ 검색어 또는 주소 입력 + + 기록 검색 + + 북마크 검색 + + 탭 검색 검색어 입력 @@ -44,8 +50,6 @@ - 최근 북마크 - 최근에 저장됨 저장된 북마크 모두 표시 @@ -135,13 +139,6 @@ 모든 최근 탭 표시 버튼 - - \"%1$s\"에 대한 검색 - - - %d개 사이트 동기화된 탭 모두 보기 @@ -265,38 +262,20 @@ 검색 설정 - - - %1$s의 새 기능 - - 이제 이전에 사용하던 부분을 쉽게 찾을 수 있습니다. - - 개인화된 %1$s 홈페이지 - - 열린 탭, 북마크 및 방문 기록으로 이동합니다. - - 깔끔하게 정리된 탭 - - 향상된 레이아웃과 자동 탭 닫기로 탭을 깔끔하게 정리하세요. - - 최근 검색 - - 홈페이지와 탭에서 최근 검색을 다시 방문하세요. - - - 이제 개인화된 Firefox 홈페이지에서 이전에 사용하던 부분을 쉽게 찾을 수 있습니다. 최근 탭, 북마크 및 검색 결과를 찾으세요. + + 이번만 검색: + + 이번만 검색: + + 개인화된 홈페이지를 만나보세요. 최근 탭, 북마크 및 검색 결과가 여기에 표시됩니다. - 독립 인터넷에 오신 것을 환영합니다 - 나만의 인터넷에 오신 것을 환영합니다 더 많은 색상. 더 나은 개인 정보 보호. 이익보다는 사람들에 대한 헌신. - 휴대전화에서 노트북으로 왔다가 다시 돌아가기 - 더 쉬워진 화면 전환 이제 홈페이지에서 다른 기기의 탭을 가져와서 중단한 부분부터 다시 시작하세요. @@ -310,6 +289,9 @@ 탭이 동기화 중입니다! 다른 기기에서 중단한 부분부터 다시 시작하세요. + + 닫기 + 새 %1$s 탭 열기 @@ -360,6 +342,14 @@ 사생활 보호 모드 바로 가기 추가 HTTPS 전용 모드 + + + 쿠키 배너 감소 + + 쿠키 배너 줄이기 + + Firefox는 자동으로 쿠키 배너에서 쿠키 요청을 거부하려고 시도합니다. 거부 옵션을 사용할 수 없는 경우, Firefox는 배너를 닫기 위해 모든 쿠키를 허용할 수 있습니다. + 보안 강화를 위해 HTTPS 암호화 프로토콜을 사용하여 사이트에 자동으로 연결을 시도합니다. @@ -399,8 +389,6 @@ 사용자 지정 - Firefox 계정으로 북마크, 기록 등을 동기화하세요 - 탭, 북마크, 비밀번호 등을 동기화하려면 로그인하세요. Firefox 계정 @@ -469,8 +457,12 @@ a section where users see a list of tabs that they have visited in the past few days --> 최근에 방문함 - 포켓 + 포켓 + + 생각하게 하는 이야기 + + %s 제공 글 스폰서 소식 @@ -494,12 +486,6 @@ 배경 화면을 변경할 수 없습니다 더 알아보기 - - Firefox 홈페이지 로고를 눌러 배경 화면 변경 - - - Firefox 로고 - 배경 화면 변경, 버튼 클래식 %s @@ -599,9 +585,6 @@ Mozilla가 연구를 설치하고 실행하도록 허용 - - Sync 켜기 - 데이터 동기화 및 저장 @@ -661,6 +644,17 @@ 닫기 + + 탭 %d개를 여시겠습니까? + + 이렇게 많은 탭을 열면 페이지가 로드되는 동안 %s가 느려질 수도 있습니다. 계속하시겠습니까? + + 탭 열기 + + 취소 + %d개 사이트 @@ -691,10 +685,6 @@ 목록 그리드 - - 그룹 검색 - - 관련된 사이트를 서로 그룹화 탭 닫기 @@ -821,9 +811,6 @@ %1$s (사생활 보호 모드) - - 기타 탭 - 검색어 입력 @@ -852,18 +839,6 @@ 기록 없음 - - 다른 기기에서 동기화됨 - - 다른 기기에서 - - - 다른 기기에서 동기화된 기록을 보려면 로그인 하세요. - - 로그인 - - 또는 동기화를 시작하려면 Firefox 계정을 만드세요]]> - 다운로드 삭제됨 @@ -915,6 +890,10 @@ 새 탭에서 열기 사생활 보호 탭에서 열기 + + 모두 새 탭에서 열기 + + 모두 사생활 보호 탭에서 열기 삭제 @@ -1108,6 +1087,10 @@ 공유 + + PDF로 저장 + + PDF를 생성할 수 없음 기기로 보내기 @@ -1119,9 +1102,11 @@ 클립보드에 복사됨 - Sync에 로그인 + Sync에 로그인 Sync에 로그인 + + 데이터 동기화 및 저장 모든 기기에 보내기 @@ -1160,6 +1145,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s를 기본 브라우저로 설정 + + 사생활 보호 모드 사용해보기 + + %1$s에 저장된 쿠키나 기록이 없는 탐색 + 모음집 삭제됨 @@ -1257,8 +1248,6 @@ 종료 - - 탐색 데이터가 모두 삭제됩니다. 삭제할 시간 범위 @@ -1292,34 +1281,21 @@ 그룹 삭제됨 - - %s에 오신걸 환영합니다! 더 나은 인터넷에 오신 것을 환영합니다 이익이 아닌 사람을 위해 만들어진 브라우저. - - 기기 간에 Firefox 동기화 중단한 부분부터 다시 시작하세요 - - 이 기기의 %1$s에 북마크, 기록 및 비밀번호를 가져오세요. 원활한 화면 전환을 위해 여러 기기에서 탭과 비밀번호를 동기화합니다. - - 가입하기 로그인 동기화 켜짐 - - 상시 개인 정보 보호 기본적으로 사생활을 보호합니다 - - %1$s는 회사가 웹에서 사용자를 몰래 따라 다니는 것을 자동으로 중지합니다. 전체 쿠키 보호 기능을 통해 추적기가 쿠키를 사용하여 사이트에서 사용자를 스토킹하는 것을 방지합니다. @@ -1332,17 +1308,10 @@ 더 많은 추적기를 차단하여 페이지가 더 빨리 로드되지만, 일부 페이지의 기능이 손상될 수 있습니다. 도구 모음 위치 선택 - - 도구 모음을 쉽게 접근할 수 있는 곳에 놓으세요. 하단에 두거나 상단으로 옮기세요. 아래쪽에 두거나 위쪽으로 이동하세요. - - 개인 정보 보호 사용자가 자신의 데이터를 제어 - - 우리는 %s가 무엇을 온라인에서 공유하고 우리와 공유할지 사용자가 제어할 수 있게 만들었습니다. Firefox를 사용하면 무엇을 온라인에서 공유하고 우리와 공유할지 사용자가 제어할 수 있습니다. @@ -1490,7 +1459,7 @@ 뒤로 %s의 새 기능 - + %s | OSS 라이브러리 @@ -1987,7 +1956,9 @@ 더 발견하기 - 포켓 제공 + 포켓 제공 + + %s 제공. Firefox 제품군의 일부입니다. %s @@ -2001,4 +1972,14 @@ 설정으로 이동 Firefox 제안 + + + + 접기 + + 펼치기 + + 이 모음집에 대해 더 알아보려면 링크를 여세요 + + 글 읽기 diff --git a/app/src/main/res/values-lo/strings.xml b/app/src/main/res/values-lo/strings.xml index ce8cd7f2a..6d37dfdbc 100644 --- a/app/src/main/res/values-lo/strings.xml +++ b/app/src/main/res/values-lo/strings.xml @@ -14,6 +14,12 @@ ປຶດນຳໃຊ້ການທ່ອງເວັບແບບສ່ວນຕົວ ຄົ້ນຫາ ຫລື ປ້ອນທີ່ຢູ່ໃສ່ + + ປະຫວັດການຊອກຫາ + + ຊອກຫາບຸກມາກ + + ຄົ້ນຫາແທັບ ປ້ອນຄຳທີ່ຕ້ອງການຄົ້ນຫາ @@ -38,9 +44,6 @@ ເລືອກແລ້ວ - - ບຸກມາກຫລ້າສຸດ - ບັນທຶກຫຼ້າສຸດ @@ -128,12 +131,6 @@ ສະແດງປຸ່ມແທັບຫລ້າສຸດທັງຫມົດ - - ການຄົ້ນຫາຂອງທ່ານສຳລັບ \"%1$s\" - - %d ເວັບໄຊທ ເບິງແທັບທີ່ sync ທັງຫມົດ @@ -255,40 +252,21 @@ ການຕັ້ງຄ່າການຄົ້ນຫາ + + ເວລານີ້ຄົ້ນຫາ: + + + ເວລານີ້ຄົ້ນຫາໃນ: + - - ສິ່ງໃໝ່ໆໃນ %1$s - - ທ່ານສາມາດກັບໄປເບິງຫນ້າເວັບທີ່ທ່ານເບິງຄ້າງໄວ້ໄດ້ງ່າຍຂື້ນແລ້ວ. - - - ປັບແຕ່ງໜ້າຫຼັກ %1$s - - ຂ້າມໄປຫາແທັບທີ່ເປີດຢູ່, ບຸກມມາກ ແລະ ປະຫວັດການທ່ອງເວັບຂອງທ່ານ. - - - ສະອາດ, ແຖບທີ່ມີການຈັດການ - - ລຶບລ້າງຄວາມວຸ້ນວາຍຂອງແຖບດ້ວຍໂຄງຮ່າງທີ່ປັບປຸງດີຂຶ້ນ ແລະແຖບປິດອັດຕະໂນມັດ. - - ການຄົ້ນຫາຫຼ້າສຸດ - - - ເຂົ້າໄປເບິງຄືນຈາກການຄົ້ນຫາຫຼ້າສຸດໄດ້ໃນຫນ້າທຳອິດຂອງທ່ານ. - - ໜ້າຫຼັກ Firefox ທີ່ປັບແຕ່ງເປັນແບບສ່ວນຕົວຂອງທ່ານຕອນນີ້ເຮັດໃຫ້ມັນງ່າຍຂຶ້ນໃນການເລືອກບ່ອນທີ່ທ່ານປະໄວ້. ຊອກຫາແຖບ, ບຸກມາກ ແລະຜົນການຄົ້ນຫາຫຼ້າສຸດຂອງທ່ານ. ພົບກັບໜ້າຫຼັກທີ່ເປັນສ່ວນຕົວຂອງທ່ານ. ແຖບຫຼ້າສຸດ, ບຸກມາກ, ແລະຜົນການຊອກຫາຈະປາກົດຢູ່ບ່ອນນີ້. - - ຍິນດີຕ້ອນຮັບສູ່ອິນເຕີເນັດທີບໍ່ມີຂອບຈຳກັດ ຍິນດີຕ້ອນຮັບສູ່ອິນເຕີເນັດທີມີຄວາມເປັນສ່ວນຕົວສູງ ສີເພີ່ມເຕີມ. ຄວາມເປັນສ່ວນຕົວທີ່ດີກວ່າ. ຄໍາຫມັ້ນສັນຍາດຽວກັນກັບປະຊາຊົນຫຼາຍກວ່າກໍາໄລ. - ເລື່ອນຈາກໂທລະສັບໄປຫາແລັບທັອບ ແລະຫຼັງ - ການສະຫຼັບໜ້າຈໍແມ່ນງ່າຍກວ່າທີ່ເຄີຍ ເລືອກເບິ່ງຕໍ່ຈາກທີທ່ານປະໄວ້ດ້ວຍແຖບຈາກອຸປະກອນອື່ນໆໃນຫນ້າທໍາອິດຂອງທ່ານ. @@ -302,6 +280,9 @@ ແຖບຂອງທ່ານກຳລັງຊິ້ງຢູ່! ເອົາບ່ອນທີ່ເຈົ້າຄ້າງໄວ້ໃນອຸປະກອນອື່ນຂອງເຈົ້າ. + + ປິດ + ເປີດແຖບ %1$s ໃໝ່ @@ -351,6 +332,14 @@ ເພີ່ມທາງລັດການທ່ອງເວັບແບບສ່ວນຕົວ ໂໝດ HTTPS ເທົ່ານັ້ນ + + + ການຫຼຸດປ້າຍໂຄສະນາຄຸກກີ + + ຫຼຸດປ້າຍໂຄສະນາຄຸກກີ + + Firefox ພະຍາຍາມປະຕິເສດການຮ້ອງຂໍຄຸກກີໃນປ້າຍໂຄສະນາຄຸກກີອັດຕະໂນມັດ. ຖ້າທາງເລືອກການປະຕິເສດບໍ່ສາມາດໃຊ້ໄດ້, Firefox ອາດຈະຍອມຮັບ cookies ທັງຫມົດເພື່ອປິດປ້າຍໂຄສະນາ. + ພະຍາຍາມເຊື່ອມຕໍ່ຫາເວັບໄຊໂດຍອັດຕະໂນມັດໂດຍໃຊ້ໂປຣໂຕຄໍການເຂົ້າລະຫັດ HTTPS ເພື່ອຄວາມປອດໄພທີ່ເພີ່ມຂຶ້ນ. @@ -459,8 +448,12 @@ a section where users see a list of tabs that they have visited in the past few days --> ຫາກໍ່ເຂົ້າໄປເບິງມື້ກີ້ນີ້ - Pocket + Pocket + + ເລື່ອງທີ່ກະຕຸ້ນຄວາມຄິດ + + ບົດຄວາມທີ່ຂັບເຄື່ອນໂດຍ %s ເລື່ອງລາວທີ່ໄດ້ຮັບການສະຫນັບສະຫນູນ @@ -485,12 +478,7 @@ ບໍ່ສາມາດປ່ຽນຮູບພື້ນຫຼັງໄດ້ ຮຽນຮູ້ເພີ່ມເຕີມ - - ປ່ຽນຮູບວໍເປເປີໂດຍການແຕະໃສ່ໂລໂກ້ຂອງໜ້າຫຼັກຂອງ Firefox - - ໂລໂກ້ Firefox - ປ່ຽນຮູບວໍເປເປີ, ປຸ່ມ ຄລາດສິກ %s @@ -653,6 +641,17 @@ ປິດ + + ເປີດ %d ແຖບບໍ? + + ການເປີດຫຼາຍແຖບນີ້ອາດຈະຊ້າລົງ %s ໃນຂະນະທີ່ຫນ້າເວັບກໍາລັງໂຫລດ. ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການສືບຕໍ່? + + ເປີດແທັບ + + ຍົກເລີກ + %d ເວັບໄຊທ @@ -682,10 +681,6 @@ ລາຍການ ເສັ້ນຕາຕະລາງ - - ກຸ່ມຄົ້ນຫາ - - ຈັດກຸ່ມເວັບໄຊທີກ່ຽວຂ້ອງກັນ ປິດແທັບ @@ -840,17 +835,6 @@ ບໍ່ມີປະຫວັດການໃຊ້ງານຢູ່ນີ້ - - ຊິງຄ໌ຈາກອຸປະກອນອື່ນ - - ຈາກອຸປະກອນອື່ນ - - ເຂົ້າສູ່ລະບົບເພື່ອເບິ່ງປະຫວັດການຊິງຄ໌ຈາກອຸປະກອນອື່ນຂອງທ່ານ. - - ເຂົ້າສູ່ລະບົບ - - ຫຼືສ້າງບັນຊີ Firefox ເພື່ອເລີ່ມຕົ້ນການຊິງຄ໌]]> - ລຶບການດາວໂຫລດແລ້ວ @@ -899,6 +883,10 @@ ເປີດໃນແທັບໃຫມ່ ເປີດໃນແທັບສ່ວນຕົວ + + ເປີດທັງໝົດໃນແຖບໃໝ່ + + ເປີດທັງໝົດໃນແຖບສ່ວນຕົວ ລຶບ @@ -1078,6 +1066,10 @@ ແບ່ງປັນ + + ບັກທຶກເປັນ PDF + + ບໍ່ສາມາດສ້າງ PDF ໄດ້ ສົ່ງໄປຫາອຸປະກອນ @@ -1089,9 +1081,11 @@ ສຳເນົາໃສ່ຄລິບບອດແລ້ວ - ເຂົ້າສູ່ລະບົບເພື່ອ Sync + ເຂົ້າສູ່ລະບົບເພື່ອ Sync ລົງຊື່ເຂົ້າໃຊ້ເພື່ອ Sync + + ຊິງຄ໌ແລະບັນທຶກຂໍ້ມູນ ສົ່ງໄປຫາທຸກອຸປະກອນ @@ -1130,6 +1124,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> ກຳນົດ %1$s ເປັນບຣາວເຊີຫລັກຂອງທ່ານ + + ລອງຊອກຫາແບບສ່ວນຕົວ + + ຊອກຫາດ້ວຍບໍ່ມີຄຸກກີ້ ຫຼືປະຫວັດທີ່ບັນທຶກໄວ້ໃນ %1$s + ລົບການສະສົມແລ້ວ @@ -1256,35 +1256,21 @@ ລຶບກຸ່ມແລ້ວ - - ຍິນດີຕ້ອນຮັບສູ່ %s! - ຍິນດີຕ້ອນຮັບສູ່ອິນເຕີເນັດທີ່ດີກວ່າ ອິນເຕີເນັດສຳລັບທຸກຄົນ, ບໍ່ແມ່ນເພືອຫວັງຜົນກຳໄລ - - Sync Firefox ລະຫວ່າງອຸປະກອນ ຮັບເອົາຈາກບ່ອນທີ່ທ່ານໄດ້ປະເອົາໄວ້. - - ເອົາບຸກມາກ, ປະຫວັດ, ແລະລະຫັດຜ່ານໄປຫາ %1$s ໃນອຸປະກອນນີ້. ຊິ້ງແຖບ ແລະລະຫັດຜ່ານໃນທົ່ວອຸປະກອນສຳລັບການສະຫຼັບໜ້າຈໍແບບບໍ່ມີຮອຍຕໍ່. - - ລົງ​ທະ​ບຽນ ເຂົ້າສູ່ລະບົບ Sync ເປີດຢູ່ - - ຄວາມເປັນສ່ວນຕົວເປີດຕະຫຼອດ ການປົກປ້ອງຄວາມເປັນສ່ວນຕົວຖືກກຳນົດເປັນຄ່າເລີ່ມຕົ້ນ - - %1$s ຈະຢຸດບໍລິສັດບໍ່ໃຫ້ຕິດຕາມທ່ານຢ່າງລັບໆໃນທົ່ວເວັບ. ມີການປົກປ້ອງຄຸກກີທັງໝົດເພື່ອຢຸດຜູ້ຕິດຕາມຈາກການໃຊ້ຄຸກກີເພື່ອຕິດຕາມທ່ານໃນທົ່ວເວັບໄຊ. @@ -1299,17 +1285,10 @@ ປິດກັ້ນຕົວຕິດຕາມຫຼາຍຂຶ້ນເພື່ອໃຫ້ຫນ້າໂຫລດໄວຂຶ້ນ, ແຕ່ບາງຫນ້າທີ່ຢູ່ໃນຫນ້າອາດຈະພັງ. ເລືອກການຈັດວາງແຖບເຄື່ອງມືຂອງທ່ານ - - ວາງແຖບເຄື່ອງມືໃຫ້ເຂົ້າເຖິງໄດ້ງ່າຍ. ຮັກສາມັນຢູ່ລຸ່ມ, ຫຼືຍ້າຍມັນໄປເທິງ. ຮັກສາມັນຢູ່ລຸ່ມ, ຫຼືຍ້າຍມັນໄປເທິງ. - - ຄວາມເປັນສ່ວນຕົວຂອງທ່ານ ທ່ານຄວບຄຸມຂໍ້ມູນຂອງທ່ານ - - ພວກເຮົາໄດ້ອອກແບບ %s ເພື່ອໃຫ້ທ່ານຄວບຄຸມສິ່ງທີ່ທ່ານແບ່ງປັນອອນລາຍ ແລະສິ່ງທີ່ທ່ານແບ່ງປັນກັບພວກເຮົາ. Firefox ໃຫ້ທ່ານຄວບຄຸມສິ່ງທີ່ທ່ານແບ່ງປັນອອນໄລນ໌ ແລະສິ່ງທີ່ທ່ານແບ່ງປັນກັບພວກເຮົາ. @@ -1958,7 +1937,9 @@ ຄົ້ນຫາເພີ່ມເຕີມ - ຂັບເຄື່ອນໂດຍ Pocket. + ຂັບເຄື່ອນໂດຍ Pocket. + + ຂັບເຄື່ອນໂດຍ %s. ສ່ວນຫນຶ່ງຂອງຄອບຄົວ Firefox. %s @@ -1971,4 +1952,14 @@ ໄປທີ່ການຕັ້ງຄ່າ Firefox ແນະນໍາ + + + + ຫຍໍ້ + + ຂະຫຍາຍອອກ + + ເປີດລິ້ງເພື່ອສຶກສາເພີ່ມເຕີມກ່ຽວກັບຄໍເລັກຊັນນີ້ + + ອ່ານບົດຄວາມ diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index d26d1f6e9..236861bed 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -14,6 +14,12 @@ Slå av privat nettlesing Søk eller skriv inn adresse + + Søke i historikk + + Søk i bokmerker + + Søk i faner Skriv inn søketekst @@ -40,8 +46,6 @@ - Nylige bokmerker - Nylig lagret Vis alle lagrede bokmerker @@ -132,13 +136,6 @@ Vis alle nylige faner-knappen - - Du søkte etter «%1$s» - - - %d nettsteder Se alle synkroniserte faner @@ -261,39 +258,20 @@ Søkeinnstillinger - - - Hva er nytt i %s - - Det er nå lettere å komme tilbake der du sluttet. - - Tilpasset %1$s-startside - - Gå til de åpne fanene, bokmerkene og nettleserhistorikken. - - Rene, organiserte faner - - Fjern rot i fanene med forbedret layout og faner som lukker seg automatisk. - - Nylige søk - - - Gå tilbake til de siste søkene dine fra startsiden og fanene. - - - Din personlige Firefox-startside gjør det nå lettere å fortsette der du sluttet. Finn de siste fanene, bokmerkene og søkeresultatene. + + Søk denne gangen med: + + Søk denne gangen i: + + Møt din personlige hjemmeside. Nylige faner, bokmerker og søkeresultater vises her. - Velkommen til et uavhengig internett - Velkommen til et mer personlig internett Flere farger. Bedre personvern. Samme forpliktelse til mennesker over fortjeneste. - Bytt fra telefon til bærbar PC og tilbake - Det er enklere enn noen gang å bytte skjerm Fortsett der du slapp med faner fra andre enheter nå på startsiden din. @@ -306,6 +284,9 @@ Fanene dine synkroniseres! Fortsett der du sluttet på den andre enheten. + + Lukk + Åpne en ny %1$s-fane @@ -355,6 +336,14 @@ Legg til snarvei for privat nettlesing Kun-HTTPS-modus + + + Redusering av infoskapselbanner + + Reduser infoskapselbannere + + Firefox prøver automatisk å avvise infokapselforespørsler på infoskapselbannere. Hvis et avvisningsalternativ ikke er tilgjengelig, kan Firefox godta alle infokapsler for å avvise banneret. + Forsøker automatisk å koble til nettsteder ved hjelp av HTTPS-krypteringsprotokollen for økt sikkerhet. @@ -394,8 +383,6 @@ Tilpass - Synkroniser bokmerker, historikk og mer med Firefox-kontoen din - Logg inn for å synkronisere faner, bokmerker, passord med mer. Firefox-konto @@ -464,8 +451,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nylig besøkt - Pocket + Pocket + + Tankevekkende artikler + + Artikler drevet av %s Sponsede historier @@ -488,12 +479,6 @@ Kunne ikke endre bakgrunnsbildet Les mer - - Endre bakgrunnsbilde ved å trykke på Firefox-logoen på startsiden - - - Firefox-logo - endre bakgrunn, knapp Klassisk %s @@ -591,8 +576,6 @@ Tillater Mozilla å installere og kjøre undersøkelser - - Slå på Sync Synkroniser og lagre dataene dine @@ -655,6 +638,17 @@ Lukk + + Åpne %d faner? + + Å åpne så mange faner kan redusere hastigheten på %s mens sidene lastes. Er du sikker på at du vil fortsette? + + Åpne faner + + Avbryt + %d nettsted @@ -684,10 +678,6 @@ Liste Rutenett - - Søk i grupper - - Grupper relaterte nettsteder sammen Lukk faner @@ -810,9 +800,6 @@ %1$s (privatmodus) - - Andre faner - Skriv inn søketekst @@ -841,18 +828,6 @@ Ingen historikk her - - Synkronisert fra andre enheter - - Fra andre enheter - - - Logg på for å se historikken synkronisert fra de andre enhetene dine. - - Logg inn - - Eller opprett en Firefox-konto for å begynne å synkronisere]]> - Nedlastinger fjernet @@ -902,6 +877,10 @@ Åpne i ny fane Åpne i privat fane + + Åpne alle i nye faner + + Åpne alle i private faner Slett @@ -1082,6 +1061,10 @@ Del + + Lagre som PDF + + Klarte ikke å generere PDF Send til enhet @@ -1093,9 +1076,11 @@ Kopiert til utklippstavle - Logg inn for å synkronisere + Logg inn for å synkronisere Logg inn på Sync + + Synkroniser og lagre data Send til alle enheter @@ -1131,6 +1116,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Bruk %1$s som din standard nettleser + + Prøv privat nettlesing + + Surf uten lagrede infokapsler eller historikk med %1$s + Samling slettet @@ -1221,9 +1212,6 @@ Avslutt - - Dette vil slette alle dine nettleserdata. - Tidsrom for sletting @@ -1256,35 +1244,21 @@ Gruppe slettet - - Velkommen til %s! - Velkommen til et bedre internett En nettleser bygget for mennesker, ikke profitt. - - Synkroniser Firefox mellom enheter Fortsett der du sluttet - - Ta med bokmerker, historikk og passord til %1$s på denne enheten. Synkroniser faner og passord på tvers av enheter for sømløs bytte av skjerm. - - Registrer deg Logg inn Synkroniseringen er på - - Alltid med personvern Personvernsbeskyttelse som standard - - %1$s stopper selskaper automatisk fra å spore aktivitetene dine på nettet i det skjulte. Total beskyttelse mot infokapsler stopper sporere fra å bruke infokapsler for å forfølge deg på tvers av nettsteder. @@ -1299,19 +1273,12 @@ Blokkerer flere sporings-mekanismer. Sider lastes inn raskere, men enkelte sider fungerer kanskje ikke. Velg plassering for verktøylinjen - - Plassere verktøylinjen innenfor rekkevidde. Ha den på bunn eller flytt den til toppen. Behold den på bunnen, eller flytt den til toppen. - - Ditt personvern Du kontrollerer dine data - - Vi har utviklet %s for å gi deg kontroll over det du deler på nettet og hva du deler med oss. Firefox gir deg kontroll over hva du deler på nettet og hva du deler med oss. @@ -1957,7 +1924,9 @@ Oppdag mer - Drevet av Pocket. + Drevet av Pocket. + + Drevet av %1$s. Del av Firefox-familien. %s @@ -1971,4 +1940,14 @@ Gå til innstillinger Firefox-forslag + + + + slå sammen + + fold ut + + åpne lenken for å lære mer om denne samlingen + + les artikkelen diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index e0891dc73..db86e2c29 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -60,7 +60,7 @@ @color/photonRed20 - @color/photonRed70 + @color/photonRed70 @color/photonViolet20 @@ -97,7 +97,7 @@ @color/photonLightGrey05 @color/photonRed20 - @color/photonRed70 + @color/photonRed70 @color/photonViolet20 @color/photonBlue20 @color/photonPink20 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 7a3dd7101..86e09217e 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -17,6 +17,12 @@ Voer zoekterm of adres in + + Geschiedenis doorzoeken + + Bladwijzers doorzoeken + + Tabbladen doorzoeken Voer zoektermen in @@ -43,8 +49,6 @@ - Recente bladwijzers - Onlangs opgeslagen Alle opgeslagen bladwijzers tonen @@ -60,9 +64,9 @@ The first parameter is the name of the app defined in app_name (for example: Fenix) --> %1$s wist uw zoek- en browsergeschiedenis zodra u de toepassing afsluit of alle privétabbladen sluit. Hoewel dit u niet anoniem maakt voor websites of uw internetprovider, maakt dit het makkelijker om wat u online doet privé te houden voor anderen die dit apparaat gebruiken. - + Veelgehoorde mythes over privénavigatie - + @@ -135,13 +139,6 @@ Knop Alle recente tabbladen tonen - - Uw zoekopdracht naar ‘%1$s’ - - - %d websites Alle gesynchroniseerde tabbladen bekijken @@ -265,39 +262,20 @@ Zoekinstellingen - - - Wat is er nieuw in %1$s - - Het is nu eenvoudiger om verder te gaan waar u was gebleven. - - Gepersonaliseerde %1$s-startpagina - - Spring naar uw open tabbladen, bladwijzers en navigatiegeschiedenis. - - Nette, geordende tabbladen - - Verwijder tabbladrommel met een verbeterde opmaak en automatisch sluitende tabbladen. - - Recente zoekopdrachten - - - Bekijk uw laatste zoekopdrachten opnieuw vanaf uw startpagina en tabbladen. - - - Uw gepersonaliseerde Firefox-startpagina maakt het nu eenvoudiger om verder te gaan waar u was gebleven. Vind uw recente tabbladen, bladwijzers en zoekresultaten. + + Deze keer zoeken met: + + + Deze keer zoeken in: + Maak kennis met uw gepersonaliseerde startpagina. Recente tabbladen, bladwijzers en zoekresultaten worden hier weergegeven. - Welkom bij een onafhankelijk internet - Welkom bij een meer persoonlijk internet Meer kleuren. Betere privacy. Dezelfde toewijding aan mensen boven winst. - Spring van telefoon naar laptop en terug - Van scherm wisselen is eenvoudiger dan ooit Ga verder waar u was gebleven met tabbladen van andere apparaten nu op uw startpagina. @@ -311,6 +289,9 @@ Uw tabbladen worden gesynchroniseerd! Ga verder waar u was gebleven op uw andere apparaat. + + Sluiten + Een nieuw %1$s-tabblad openen @@ -360,6 +341,14 @@ Snelkoppeling naar privénavigatie toevoegen Alleen-HTTPS-modus + + + Reductie van cookiebanners + + Cookiebanners reduceren + + Firefox probeert automatisch cookie-aanvragen op cookiebanners te weigeren. Als er geen weigeringsoptie beschikbaar is, accepteert Firefox mogelijk alle cookies om de banner te sluiten. + Probeert voor een betere beveiliging automatisch middels het HTTPS-versleutelingsprotocol verbinding te maken met websites. @@ -399,8 +388,6 @@ Aanpassen - Synchroniseer bladwijzers, geschiedenis en meer met uw Firefox-account - Meld u aan om uw tabbladen, bladwijzers, wachtwoorden en meer te synchroniseren. Firefox-account @@ -469,8 +456,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Onlangs bezocht - Pocket + Pocket + + Verhalen die tot nadenken stemmen + + Artikelen mogelijk gemaakt door %s Gesponsorde verhalen @@ -494,12 +485,6 @@ Kan achtergrond niet wijzigen Meer info - - Uw achtergrond wijzigen door op het Firefox-startpaginalogo te tikken - - - Firefox-logo – de achtergrond, de knop wijzigen Klassieke %s @@ -596,8 +581,6 @@ Stelt Mozilla in staat om onderzoeken te installeren en uit te voeren - - Sync inschakelen Uw gegevens synchroniseren en opslaan @@ -659,6 +642,17 @@ Sluiten + + %d tabbladen openen? + + Als u zoveel tabbladen opent, kan dit %s vertragen tijdens het laden van de pagina’s. Weet u zeker dat u wilt doorgaan? + + Tabbladen openen + + Annuleren + %d website @@ -689,10 +683,6 @@ Lijst Raster - - Groepen zoeken - - Gerelateerde websites groeperen Tabbladen sluiten @@ -818,9 +808,6 @@ %1$s (privémodus) - - Overige tabbladen - Voer zoektermen in @@ -848,18 +835,6 @@ Geen geschiedenis hier - - Gesynchroniseerd vanaf andere apparaten - - Vanaf andere apparaten - - - Meld u aan om van uw andere apparaten gesynchroniseerde geschiedenis te bekijken. - - Aanmelden - - Of maak een Firefox-account om te beginnen met synchroniseren]]> - Downloads verwijderd @@ -909,6 +884,10 @@ Openen in nieuw tabblad Openen in privétabblad + + Alles in nieuwe tabbladen openen + + Alles in privétabbladen openen Verwijderen @@ -1086,6 +1065,10 @@ Delen + + Opslaan als PDF + + Kan PDF niet aanmaken Verzenden naar apparaat @@ -1097,9 +1080,11 @@ Naar klembord gekopieerd - Aanmelden om te synchroniseren + Aanmelden om te synchroniseren Aanmelden bij Sync + + Synchroniseren en gegevens opslaan Verzenden naar alle apparaten @@ -1138,6 +1123,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s uw standaardbrowser maken + + Probeer privénavigatie + + Surf zonder opgeslagen cookies of geschiedenis in %1$s + Collectie verwijderd @@ -1227,8 +1218,6 @@ Afsluiten - - Hierdoor worden al uw navigatiegegevens verwijderd. Te verwijderen tijdsperiode @@ -1262,33 +1251,20 @@ Groep verwijderd - - Welkom bij %s! Welkom bij een beter internet Een browser gebouwd voor mensen, niet voor winst. - - Synchroniseer Firefox tussen apparaten Ga verder waar u was gebleven - - Breng bladwijzers, geschiedenis en wachtwoorden naar %1$s op dit apparaat. Synchroniseer tabbladen en wachtwoorden op verschillende apparaten voor naadloos schakelen tussen schermen. - - Registreren Aanmelden Synchronisatie is ingeschakeld - - Privacy die altijd aan staat Standaard privacybescherming - - %1$s zorgt er automatisch voor dat bedrijven u niet stiekem volgen op internet. Met Totale cookiebescherming om te voorkomen dat trackers cookies gebruiken om u stiekem op het internet te volgen. @@ -1301,17 +1277,10 @@ Blokkeert meer trackers, zodat pagina’s sneller worden geladen, maar sommige functionaliteit op een pagina werkt mogelijk niet. Kies uw werkbalkplaatsing - - Plaats de werkbalk binnen handbereik. Houd hem onderaan of verplaats hem naar boven. Houd hem onderaan, of verplaats hem naar boven. - - Uw privacy U beheert uw gegevens - - We hebben %s ontworpen om u controle te geven over wat u online deelt en wat u met ons deelt. Firefox geeft u controle over wat u online deelt en wat u met ons deelt. @@ -1499,10 +1468,10 @@ Plakken & Gaan Plakken - + URL naar klembord gekopieerd - + Toevoegen aan startscherm @@ -1948,7 +1917,9 @@ Meer ontdekken - Mogelijk gemaakt door Pocket. + Mogelijk gemaakt door Pocket. + + Mogelijk gemaakt door %s. Onderdeel van de Firefox-familie. %s @@ -1962,4 +1933,14 @@ Naar Instellingen Firefox Suggesties + + + + samenvouwen + + uitvouwen + + koppeling openen voor meer info over deze collectie + + het artikel te lezen diff --git a/app/src/main/res/values-nn-rNO/strings.xml b/app/src/main/res/values-nn-rNO/strings.xml index 4201cbf6c..50b362350 100644 --- a/app/src/main/res/values-nn-rNO/strings.xml +++ b/app/src/main/res/values-nn-rNO/strings.xml @@ -17,6 +17,12 @@ Søk eller skriv inn ei adresse + + Søkjehistorikk + + Søk i bokmerke + + Søk i faner Skriv inn søkjetekst @@ -43,8 +49,6 @@ - Nylege bokmerke - Nyleg lagra Vis alle lagra bokmerke @@ -81,6 +85,13 @@ Ignorer + + + Vår kraftigaste personvernfunksjon til no isolerer sporarar på tvers av nettstadar. + + + Les meir om totalt vern mot infokapslar + Kameratilgang er nødvendig. Gå til Android-innstillingar, trykk på løyve, og trykk på tillat. @@ -127,13 +138,6 @@ Vis alle nylege faner-knappen - - Du søkte etter «%1$s» - - - %d nettstadar Vis alle synkroniserte faner @@ -254,33 +258,20 @@ Søkjeinnstillingar - - - Kva er nytt i %1$s - - Det er no enklare å fortsetje der du slutta. - - - Tilpassa %1$s-startside - - Gå til dei opne fanene, bokmerka og nettlesarhistorikken. - - Reine, organiserte faner - - Fjern rot i fanene med forbetra layout og faner som automatisk lèt seg att. - - Nylege søk - - - Gå tilbake til dei siste søka dine frå startsida og fanene. - - - Den personlege Firefox-startsida di gjer det no lettare å fortsetje der du slutta. Finn dei siste fanene, bokmerka og søkjeresultata. + + Søk denne gongen med: + + + Møt den personlege heimesida di. Nylege faner, bokmerke og søkjeresultat vert viste her. - Velkomen til eit uavhengig internett + Velkomen til eit meir personleg internett + + Fleire fargar. Betre personvern. Same forplikting til menneske over forteneste. - Byt frå telefonen til datamaskina og tilbake + Det er enklare enn nokon gong g å byte skjerm + + Hald fram der du slapp med faner frå andre einingar - no på startsida di. Kom i gang @@ -289,6 +280,11 @@ Hopp over + + Fanene dine synkroniserer no! Hald fram der du slutta på den andre eininga. + + Lat att + Opne ei ny %1$s-fane @@ -339,6 +335,7 @@ Legg til snarveg for privat nettlesing Berre HTTPS-modus + Prøver automatisk å kople til nettstadar ved hjelp av HTTPS-krypteringsprotokollen for auka sikkerheit. @@ -446,8 +443,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nyleg besøkte - Pocket + Pocket + + Tankevekkjande artiklar + + Artiklar levert av %s Sponsa historier @@ -463,21 +464,23 @@ Vis + + Klarte ikkje å laste ned bakgrunnsbildet Prøv igjen + + Klarte ikkje å endre bakgrunnsbildet Les meir - - Endre bakgrunnsbilde ved å trykkje på Firefox-logoen på startsida - - - Firefox-logo - knapp for å endre bakgrunnsbilde Klassisk %s Avgrensa utgåve + + Den nye kolleksjonen Uavhengige røyster. %s + + Den nye kolleksjonen uavhengige røyster. Prøv ein fargeklatt @@ -627,6 +630,17 @@ Lat att + + Opne %d faner? + + Å opne så mange faner kan seinke %s medan sidene vert lasta. Er du sikker på at du vil halde fram? + + Opne faner + + Avbryt + %d nettstad @@ -658,10 +672,6 @@ Liste Rutenett - - Søkjegrupper - - Grupper relaterte nettstadar saman Lat att faner @@ -814,18 +824,6 @@ Ingen historikk her - - Synkronisert frå andre einingar - - Frå andre einingar - - - Logg inn for å sjå historikken synkronisert frå dei andre einingane dine. - - Logga in - - Eller opprett ein Firefox-konto for å starte synkronisering]]> - Nedlastingar fjerna @@ -875,6 +873,10 @@ Opne i ny fane Opne i privat fane + + Opne alle i nye faner + + Opne alle i private faner Slett @@ -1054,6 +1056,10 @@ Del + + Lagre som PDF + + Klarte ikkje å generere PDF Send til eining @@ -1065,9 +1071,11 @@ Kopier til utklippstavla - Logg inn for å synkronisere + Logg inn for å synkronisere Logg inn på Sync + + Synkroniser og lagre data Send til alle einingar @@ -1227,30 +1235,24 @@ Gruppe sletta - - Velkomen til %s! - - - Synkroniser Firefox mellom einingar + + Velkomen til eit betre internett + + Ein nettlesar bygd for personar, ikkje profitt. Hald fram der du slutta - - Ta med bokmerke, historikk og passord til %1$s på denne eininga. - - Registrer deg + + Synkroniser faner og passord på tvers av einingar for saumlaus byte av skjerm. Logg inn Synkronisering er på - - Alltid med personvern Personvernsikring som standard - - %1$s stoppar selskap automatisk frå å spore aktivitetane dine på nettet i det skjulte. + + Totalt vern mot infokapslar stoppar sporarar frå å bruke infokapslar til å forfølgje deg på tvers av nettstadar. Standard (standard) @@ -1261,16 +1263,17 @@ Blokkerer fleire sporings-mekanismar. Sider vert leste inn raskare, men enkelte sider fungerer kanskje ikkje. Vel plassering for verktøylinja - - Plassere verktøylinja innanfor rekkjevidde. Ha henne i botn eller topp. - - Ditt personvern - - Vi har utvikla %s for å gi deg kontroll over det du deler på nettet og kva du deler med oss. + + Behald i botnen, eller flytt til toppen. + + Du kontrollerer dine data + + Firefox gir deg kontroll over kva du deler på nettet og kva du deler med oss. Les personvernmerknaden vår + + Klar til å oppdage eit fantastisk internett? Start nettlesinga @@ -1358,6 +1361,8 @@ Alle tredjeparts-infokapslar (kan lage feil på nettstadar) Alle infokapslar (vil føre til feil på nettstadar) + + Isoler infokapslar på tvers av nettstadar Sporingsinnhald @@ -1384,6 +1389,8 @@ Infokapslar på tvers av nettstadar Blokkerer informasjonskapslar som annonsenettverk og analyseselskap brukar for å samanstille aktiviteten din på nettet på tvers av nettstadar. + + Totalt vern mot infokapslar isolerer infokapslar til nettstaden du er på, så sporarar som annonsenettverk ikkje kan bruke dei til å følgje deg mellom nettstadar. Kryptoutvinnarar @@ -1906,7 +1913,9 @@ Oppdag meir - Levert av Pocket. + Levert av Pocket. + + Driven av %s. Del av Firefox-familien. %s @@ -1920,4 +1929,14 @@ Gå til innstillingar Firefox-forslag + + + + slå saman + + fald ut + + opne lenka for å lære meir om denne samlinga + + les artikkelen diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml index d09d866a2..9f7e409a9 100644 --- a/app/src/main/res/values-oc/strings.xml +++ b/app/src/main/res/values-oc/strings.xml @@ -15,6 +15,12 @@ Recèrca o adreça + + Cercar dins l’istoric + + Cercar dins los marcapaginas + + Cercar pels onglets Picatz un tèrme de recèrca @@ -39,9 +45,6 @@ Seleccionat - - Marcats recentament - Salvats recentament @@ -130,13 +133,6 @@ Afichar lo boton dels onglets recents - - Vòstre recèrca per \« %1$s \ » - - - %d sites Veire totes los onglets sincronizats @@ -258,39 +254,20 @@ Paramètres de recèrca - - - Qué de nòu dins %1$s - - Ara es mai facil de contunhar d’ont aviatz arrestat. - - Acuèlh personalizat de %1$s - - Accedissètz a vòstres onglets dobèrts, vòstres marcapaginas e vòstre istoric de navegacion. - - Onglets clars e organizats - - Eliminatz lo bazar amb un agençament melhorat e d’onglets que se tampan solets. - - Recèrcas recentas - - - Revisitatz vòstras darrièras recèrcas a partir de la pagina d’acuèlh e vòstres onglets. - - - L’acuèlh personalizat de Firefox permet ara de tornar mai facilament ont èretz. Trapatz vòstres onglets, marcapaginas e recèrcas recentas. + + Aqueste còp cercar : + + + Aqueste còp cercar amb : + Fasètz coneissença amb vòstra pagina d’acuèlh personalizada. Onglets recents, marcapaginas e resultats de recèrca apreissaràn aicí. - La benvenguda a Internet independent - Benvengut dins un Internet mai personal Mai de colors. Melhora confidencialitat. Meteis engatjament per las personas abans lo profièch. - Basculatz del mobil a l’ordenador e invèrsament - Bascular d’ecran es mai facil que jamai Tornatz ont èretz amb los onglets d’autres aparelhs que figuran ara per la pagina d’acuèlh. @@ -304,6 +281,9 @@ Vòstre onglets son sincronizatz ! Tornatz ont èretz sus vòstre autre aparelh. + + Tampar + Dobrir dins un onglet %1$s novèl @@ -354,6 +334,14 @@ Ajustar un acorchi per la navegacion privada Mòde HTTPS solament + + + Reduccion de las bandièras de cookies + + Reduire las bandièras de cookies + + Firefox ensaja automaticament de regetar las demandas de cookies de las bandièras de cookies. Se l’opcion de refús es pas disponibla, Firefox accèpta totes las cookies per tampar la bandièra. + Ensaja automaticament de se connectar als sites amb lo chiframent HTTPS per una seguretat melhorada. @@ -462,8 +450,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitats fa res - Pocket + Pocket + + Articles suggerits + + Articles provesits per %s Istòrias pairinejadas @@ -487,12 +479,6 @@ Cambiament impossible del papièr pintrat Ne saber mai - - Cambiar lo fons d’ecran en tocant lo logotipe de Firefox de la pagina iniciala - - - Logotipe Firefox - cambiar lo fons d’ecran, boton %s classic @@ -654,6 +640,17 @@ Tampar + + Dobrir %d onglets ? + + Dobrir tan d’onglets pòt alentir %s pendent que las paginas se cargaràn. Volètz vertadièrament contunhar ? + + Dobrir los onglets + + Anullar + %d site @@ -683,10 +680,6 @@ Lista Grasilha - - Cercar en grops - - Agropar los sites ligats Tampar los onglets @@ -841,18 +834,6 @@ Cap d’istoric - - Sincronizat a partir d’autres periferics - - A partir d’autres periferics - - - Connectatz-vos per consultar l’istoric sincronizat a partir de vòstres autres aparelhs. - - Se connectar - - O crear un compte Firefox per lançar la sincronizacion]]> - Telecargament suprimits @@ -904,6 +885,10 @@ Dobrir dins un onglet novèl Dobrir en navigacion privada + + Tot dobrir dins d’onglets novèls + + Tot dobrir dins l’onglets privats Suprimir @@ -1085,6 +1070,10 @@ Partejar + + Enregistrar en PDF + + Generacion PDF impossibla Enviar al periferic @@ -1096,9 +1085,11 @@ Copiat dins lo quichapapièrs - Se connectar per sincronizar + Se connectar per sincronizar Se connectar a Sync + + Sincronizar e enregistrar las donadas Enviar a totes los periferics @@ -1135,6 +1126,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Far que %1$s siá lo navegador per defaut + + Ensajatz la navegacion privada + + + Navegatz sens cap de cookies o d’istoric dins %1$s + Colleccion suprimida @@ -1182,7 +1180,7 @@ URL copiada - Aquò es un exemple de tèxt. Aquí es una demotracion de coma apareisserà lo tèxt quand aumentatz o redusissètz la talha amb aqueste paramètre. + Aquò es un exemple de tèxt. Aquí es una demostracion de coma apareisserà lo tèxt quand aumentatz o redusissètz la talha amb aqueste paramètre. Va venir lo tèxt dels sites mai grand o mai pichon @@ -1260,33 +1258,20 @@ Grop suprimit - - La benvenguda a %s ! Benvengut dins un Internet melhor Un navegador concebut per las gents, pas per far de profièches. - - Sincronizar Firefox entre vòstres aparelhs Tornatz ont èretz - - Importatz vòstres marcapaginas, vòstre istoric e vòstres senhals dins %1$s sus aqueste aparelh. Sincronizacion d’onglets e de senhals demest aparelhs per passar d’un ecran a l’autre sens relambi. - - Se connectar Connexion Sincro. activada - - Confidencialitat totjorn renfortida Proteccion de la vida privada per defaut - - %1$s empacha automaticament las entrepresas de vos pistar secrètament pel web. Embarcant una proteccion totala contra los cookies per empachar los traçadors d’utilizar de cookies per vos pistar de site en site. @@ -1299,17 +1284,10 @@ Bloca mai de traçadors, accelèra la cargament de las paginas mas d’unas pòdon quitar de foncionar. Causissètz ont conhar la barra d’aisinas - - Plaçatz la barra d’aisinas a portada de man. Daissatz-la enbàs o ennaut. Gardatz-la enbàs o desplaçatz-la ennaut. - - Vòstra vida privada Contrarotlatz vòstras donadas - - Concebèrem %s per vos donar lo contraròtle de çò que partejatz en linha e çò que partejatz amb nosautres. Firefox vos dòna lo contraròtle de çò que partejatz en linha e çò que partejatz amb nosautres. @@ -1961,7 +1939,9 @@ Ne descobrir mai - Propulsat per Pocket. + Propulsat per Pocket. + + Fonciona gràcia a %s. Membre de la familha Firefox. %s @@ -1975,4 +1955,14 @@ Anar als paramètres Firefox suggerís + + + + plegar + + desplegar + + dobrir lo ligam per ne saber mai tocant aquesta colleccion + + legir l’article diff --git a/app/src/main/res/values-pa-rIN/strings.xml b/app/src/main/res/values-pa-rIN/strings.xml index 618dc3c4f..6a58d212e 100644 --- a/app/src/main/res/values-pa-rIN/strings.xml +++ b/app/src/main/res/values-pa-rIN/strings.xml @@ -16,6 +16,12 @@ ਨਿੱਜੀ ਬਰਾਊਜ਼ ਕਰਨਾ ਅਸਮਰੱਥ ਕਰੋ ਖੋਜੋ ਜਾਂ ਸਿਰਨਾਵਾਂ ਦਿਓ + + ਅਤੀਤ ਖੋਜੋ + + ਬੁੱਕਮਾਰਕ ਖੋਜੋ + + ਟੈਬਾਂ ਖੋਜੋ ਖੋਜ ਸ਼ਬਦ ਭਰੋ @@ -42,8 +48,6 @@ - ਸੱਜਰੇ ਬੁੱਕਮਾਰਕ - ਤਾਜ਼ਾ ਸੰਭਾਲੇ ਸਾਰੇ ਸੰਭਾਲੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਵੇਖੋ @@ -98,7 +102,7 @@ ਖ਼ਾਰਜ ਕਰੋ - ਖੋਲ੍ਹੀਆਂ ਟੈਬਾਂ ਨੂੰ ਆਪਣੇ-ਆਪ ਬੰਦ ਕਰਨਾ ਨਿਯਤ ਕਰੋ, ਜੋ ਕਿ ਪਿਛਲੇ ਦਿਨ, ਹਫ਼ਤੇ ਜਾਂ ਮਹੀਨੇ ਵਿੱਚ + ਖੋਲ੍ਹੀਆਂ ਟੈਬਾਂ ਨੂੰ ਆਪਣੇ-ਆਪ ਬੰਦ ਕਰਨਾ ਨਿਯਤ ਕਰੋ, ਜੋ ਕਿ ਪਿਛਲੇ ਦਿਨ, ਹਫ਼ਤੇ ਜਾਂ ਮਹੀਨੇ ਵਿੱਚ ਵੇਖੀਆਂ ਗਈਆਂ। ਚੋਣਾਂ ਵੇਖੋ @@ -135,13 +139,6 @@ ਸਾਰੀਆਂ ਸੱਜਰੀਆਂ ਟੈਬਾਂ ਬਟਨ ਨੂੰ ਵੇਖਾਓ - - \"%1$s\" ਲਈ ਤੁਹਾਡੀ ਖੋਜ - - - %d ਸਾਈਟਾਂ ਸਾਰੀਆਂ ਸਿੰਕ ਕੀਤੀਆਂ ਟੈਬਾਂ ਵੇਖੋ। @@ -265,38 +262,20 @@ ਖੋਜ ਸੈਟਿੰਗਾਂ - - - %1$s ਵਿੱਚ ਨਵਾਂ ਕੀ ਹੈ - - ਜਿੱਥੇ ਤੁਸੀਂ ਛੱਡ ਕੇ ਗਈ ਸੀ, ਉਥੋਂ ਹੀ ਮੁੜ ਸ਼ੁਰੂ ਕਰਨਾ ਸੌਖਾ ਹੈ। - - ਆਪਣੇ ਮੁਤਾਬਕ ਢਾਲਿਆ %1$s ਦਾ ਮੁੱਖ-ਸਫ਼ਾ - - ਆਪਣੀਆਂ ਖੋਲ੍ਹੀਆ ਟੈਬਾਂ, ਬੁੱਕਮਾਰਕਾਂ ਅਤੇ ਬਰਾਊਜ਼ ਕਰਨ ਦੇ ਅਤੀਤ ਉੱਤੇ ਜਾਓ। - - ਸਾਫ਼, ਸਜਾਈਆਂ ਟੈਬਾਂ - - ਸੁਧਾਰੇ ਖਾਕੇ ਤੇ ਆਪਣੇ-ਬੰਦ ਹੋਣ ਵਾਲੀਆਂ ਟੈਬਾਂ ਨਾਲ ਟੈਬਾਂ ਦੇ ਖਿਲਾਰੇ ਨੂੰ ਸਾਫ਼ ਕਰੋ। - - ਸੱਜਰੀਆਂ ਖੋਜਾਂ - - ਆਪਣੇ ਮੁੱਖ-ਸਫ਼ੇ ਅਤੇ ਟੈਬਾਂ ਤੋਂ ਆਪਣੀਆਂ ਸੱਜਰੀਆਂ ਖੋਜਾਂ ਨੂੰ ਮੁੜ-ਖੋਲ੍ਹੋ। - - - ਤੁਹਾਡੇ ਆਪਣੇ ਬਣਾਏ Firefox ਮੁੱਖ-ਸਫ਼ੇ ਨੇ ਹੁਣ ਜਿੱਥੇ ਤੁਸੀਂ ਛੱਡ ਕੇ ਗਏ ਸੀ, ਉਥੋਂ ਹੀ ਸ਼ੁਰੂ ਕਰਨਾ ਸੌਖਾ ਬਣਾ ਦਿੱਤਾ ਹੈ। ਆਪਣੀਆਂ ਸੱਜਰੀਆਂ ਟੈਬਾਂ, ਬੁੱਕਮਾਰਕ ਅਤੇ ਖੋਜ ਨਤੀਜੇ ਲੱਭੋ। + + ਇਹ ਸਮਾਂ ਖੋਜ: + + ਇਸ ਵਾਰ ਇਸ ਵਿੱਚ ਖੋਜੋ: + + ਤੁਹਾਡੇ ਆਪਣੇ ਬਣਾਏ ਮੁੱਖ-ਸਫ਼ੇ ਨੂੰ ਸਮਝੋ। ਸੱਜਰੀਆਂ ਟੈਬਾਂ, ਬੁੱਕਮਾਰਕ ਅਤੇ ਖੋਜ ਨਤੀਜੇ ਇੱਥੇ ਦਿਖਾਈ ਦੇਣਗੇ। - ਆਜ਼ਾਦ ਇੰਟਰਨੈੱਟ ਲਈ ਜੀ ਆਇਆਂ ਨੂੰ - ਵੱਧ ਨਿੱਜੀ ਇੰਟਰਨੈੱਟ ਲਈ ਜੀ ਆਇਆਂ ਨੂੰ ਵੱਧ ਰੰਗ। ਵੱਧ ਪਰਦੇਦਾਰੀ। ਫਾਇਦੇ ਨਾਲੋਂ ਲੋਕਾਂ ਨੂੰ ਪਹਿਲ ਦੇਣ ਦਾ ਉਹੀ ਵਾਅਦਾ। - ਫ਼ੋਨ ਤੋਂ ਲੈਪਟਾਪ ਉੱਤੇ ਜਾਓ ਤੇ ਵਾਪਸ ਆਓ - ਸਕਰੀਨਾਂ ਵਿਚਾਲੇ ਬਦਲਣਾ ਪਹਿਲਾਂ ਤੋਂ ਵੱਧ ਸੌਖਾਲਾ ਹੋਇਆ ਹੋਰ ਡਿਵਾਈਸਾਂ ਤੋਂ ਜਿੱਥੇ ਤੁਸੀਂ ਟੈਬਾਂ ਨੂੰ ਛੱਡਿਆ ਹੈ, ਉਥੋਂ ਹੀ ਹੁਣ ਆਪਣੀ ਮੁੱਖ ਸਕਰੀਨ ਤੋਂ ਲਵੋ। @@ -310,6 +289,9 @@ ਤੁਹਾਡੀਆਂ ਟੈਬਾਂ ਸਿੰਕ ਹੋ ਰਹੀਆਂ ਹਨ! ਆਪਣੇ ਹੋਰ ਡਿਵਾਈਸ ਉੱਤੇ ਜਿੱਥੇ ਤੁਸੀਂ ਛੱਡੋ, ਉਥੋਂ ਹੀ ਤੁਸੀਂ ਹੀ ਸ਼ੁਰੂ ਕਰੋ। + + ਬੰਦ ਕਰੋ + ਨਵੀਂ %1$s ਟੈਬ ਖੋਲ੍ਹੋ @@ -359,6 +341,15 @@ ਨਿੱਜੀ ਬਰਾਊਜ਼ਿੰਗ ਸ਼ਾਰਟਕੱਟ ਜੋੜੋ ਸਿਰਫ਼-HTTPS ਢੰਗ + + + ਕੂਕੀਜ਼ ਬੈਨਰ ਘਟਾਉਣਾ + + ਕੂਕੀਜ਼ ਬੈਨਰ ਘਟਾਓ + + + Firefox ਆਪਣੇ-ਆਪ ਕੂਕੀਜ਼ ਬੈਨਰ ਲਈ ਕੂਕੀਜ਼ ਬੇਨਤੀਆਂ ਨੂੰ ਇਨਕਾਰ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ ਕਰਦਾ ਹੈ। ਜੇ ਇਨਕਾਰ ਕਰਨ ਦੀ ਚੋਣ ਨਹੀਂ ਮੌਜੂਦ ਹੁੰਦੀ ਤਾਂ Firefox ਬੈਨਰ ਨੂੰ ਖਾਰਜ ਕਰਨ ਵਾਸਤੇ ਸਾਰੇ ਕੂਕੀਜ਼ ਨੂੰ ਮਨਜ਼ੂਰ ਵੀ ਕਰ ਸਕਦਾ ਹੈ। + ਵਾਧਾ ਕੀਤੀ ਸੁਰੱਖਿਆ ਲਈ HTTPS ਇੰਕ੍ਰਿਪਸ਼ਨ ਪਰੋਟੋਕਾਲ ਵਰਤ ਕੇ ਸਾਈਟਾਂ ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਦੀ ਆਪਣੇ-ਆਪ ਕੋਸ਼ਿਸ਼ ਕਰੋ। @@ -468,8 +459,12 @@ a section where users see a list of tabs that they have visited in the past few days --> ਤਾਜ਼ਾ ਖੋਲ੍ਹੇ ਗਏ - Pocket + Pocket + + ਸੋਚਣ ਲਈ ਮਜ਼ਬੂਰ ਕਰਨ ਵਾਲੇ ਲੇਖ + + %s ਵਲੋਂ ਤਿਆਰ ਕੀਤੇ ਲੇਖ ਸਪਾਂਸਰ ਕੀਤੀਆਂ ਕਹਾਣੀਆਂ @@ -492,12 +487,6 @@ ਵਾਲਪੇਪਰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਿਆ ਹੋਰ ਜਾਣੋ - - Firefox ਮੁੱਖ-ਸਫ਼ੇ ਲੋਗੋ ਨੂੰ ਛੂਹ ਕੇ ਵਾਲਪੇਪਰ ਬਦਲੋ - - - Firefox ਲੋਗੋ - ਵਾਲਪੇਪਰ ,ਬਟਨ ਬਦਲੋ ਕਲਾਸਿਕ %s @@ -659,6 +648,18 @@ ਬੰਦ ਕਰੋ + + %d ਟੈਬਾਂ ਖੋਲ੍ਹਣੀਆਂ ਹਨ? + + + ਐਨੀਆਂ ਸਾਰੀਆਂ ਟੈਬਾਂ ਖੋਲ੍ਹਣ ਨਾਲ %s ਸਫ਼ੇ ਲੋਡ ਹੋਣ ਦੌਰਾਨ ਹੌਲੀ ਹੋ ਸਕਦਾ ਹੈ। ਕੀ ਤੁਸੀਂ ਖੋਲ੍ਹਣੀਆਂ ਚਾਹੁੰਦੇ ਹੋ? + + ਟੈਬਾਂ ਖੋਲ੍ਹੋ + + ਰੱਦ ਕਰੋ + %d ਸਾਈਟ @@ -689,10 +690,6 @@ ਸੂਚੀ ਗਰਿੱਡ - - ਗਰੁੱਪ ਲੱਭੋ - - ਮਿਲਦੀਆਂ ਸਾਈਟਾਂ ਨੂੰ ਇਕੱਠੀਆਂ ਕਰਕੇ ਗਰੁੱਪ ਬਣਾਓ ਟੈਬਾਂ ਨੂੰ ਬੰਦ ਕਰੋ @@ -844,18 +841,6 @@ ਇ਼ੱਥੇ ਕੋਈ ਅਤੀਤ ਨਹੀਂ ਹੈ - - ਹੋਰ ਡਿਵਾਈਸਾਂ ਤੋਂ ਸਿੰਕ ਕੀਤੇ - - ਹੋਰ ਡਿਵਾਈਸਾਂ ਤੋਂ - - - ਆਪਣੇ ਹੋਰ ਡਿਵਾਈਸਾਂ ਤੋਂ ਸਿੰਕ ਕੀਤੀ ਅਤੀਤ ਵੇਖਣ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ। - - ਸਾਇਨ ਇਨ - - ਜਾਂ ਸਿੰਕ ਕਰਨ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ Firefox ਖਾਤਾ ਬਣਾਓ]]> - ਡਾਊਨਲੋਡ ਹਟਾਏ ਗਏ @@ -905,6 +890,10 @@ ਨਵੀਂ ਟੈਬ ‘ਚ ਖੋਲ੍ਹੋ ਨਿੱਜੀ ਟੈਬ ‘ਚ ਖੋਲ੍ਹੋ + + ਸਭ ਨੂੰ ਨਵੀਆਂ ਟੈਬਾਂ ਵਿੱਚ ਖੋਲ੍ਹੋ + + ਸਭ ਨੂੰ ਨਿੱਜੀ ਟੈਬਾਂ ਵਿੱਚ ਖੋਲ੍ਹੋ ਹਟਾਓ @@ -1083,6 +1072,10 @@ ਸਾਂਝਾ ਕਰੋ + + PDF ਵਜੋਂ ਸੰਭਾਲੋ + + PDF ਬਣਾਉਣ ਲਈ ਅਸਮਰੱਥ ਡਿਵਾਈਸ ‘ਤੇ ਭੇਜੋ @@ -1094,9 +1087,11 @@ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕੀਤਾ - ਸਿੰਕ ਕਰਨ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ + ਸਿੰਕ ਕਰਨ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ ਸਿੰਕ ਕਰਨ ਲਈ ਸਾਈਨ ਇਨ ਕਰੋ + + ਡਾਟਾ ਸਿੰਕ ਕਰੋ ਤੇ ਸੰਭਾਲੋ ਸਾਰੇ ਡਿਵਾਈਸਾਂ ‘ਤੇ ਭੇਜੋ @@ -1133,6 +1128,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s ਨੂੰ ਆਪਣਾ ਮੂਲ ਬਰਾਊਜ਼ਰ ਬਣਾਓ + + ਨਿੱਜੀ ਬਰਾਊਜ਼ ਕਰਨ ਨੂੰ ਅਜ਼ਮਾਓ + + %1$s ਵਿੱਚ ਬਿਨਾਂ ਕਿਸੇ ਸੰਭਾਲੇ ਕੂਕੀ ਜਾਂ ਅਤੀਤ ਦੇ ਬਰਾਊਜ਼ ਕਰੋ + ਭੰਡਾਰ ਹਟਾਇਆ @@ -1259,34 +1260,21 @@ ਗਰੁੱਪ ਹਟਾਇਆ - - %s ਵਲੋਂ ਜੀ ਆਇਆਂ ਨੂੰ! ਬੇਹਤਰ ਇੰਟਰਨੈੱਟ ਲਈ ਜੀ ਆਇਆਂ ਨੂੰ ਲੋਕਾਂ ਲਈ, ਨਾ ਕਿ ਫਾਇਦੇ ਲਈ ਬਣਾਇਆ ਬਰਾਊਜ਼ਰ। - - ਡਿਵਾਈਸਾਂ ਵਿਚਾਲੇ Firefox ਸਿੰਕ ਕਰੋ ਜਿੱਥੇ ਤੁਸੀਂ ਛੱਡਿਆ ਸੀ, ਉੱਥੋਂ ਸ਼ੁਰੂ ਕਰੋ - - ਇਸ ਡਿਵਾਈਸ ਉੱਤੇ %1$s ਵਿੱਚ ਬੁੱਕਮਾਰਕ, ਅਤੀਤ ਅਤੇ ਪਾਸਵਰਡ ਲਿਆਓ। ਸਹਿਜ ਨਾਲ ਸਕਰੀਨਾਂ ਬਦਲਣ ਵਾਸਤੇ ਵੱਖ-ਵੱਖ ਡਿਵਾਈਸਾਂ ਵਿਚਾਲੇ ਟੈਬਾਂ ਤੇ ਪਾਸਵਰਡਾਂ ਨੂੰ ਸਿੰਕ ਕਰੋ। - - ਸਾਈਨ ਅੱਪ ਕਰੋ ਸਾਇਨ ਇਨ ਸਿੰਕ ਚਾਲੂ ਹੈ - - ਪਰਦੇਦਾਰੀ ਹਮੇਸ਼ਾਂ ਚਾਲੂ ਮੂਲ ਰੂਪ ਵਿੱਚ ਪਰਦੇਦਾਰੀ ਸੁਰੱਖਿਆ - - ਤੁਹਾਡੇ ਵਲੋਂ ਵੈਬ ਵਰਤਣ ਦੇ ਦੌਰਾਨ ਕੰਪਨੀਆਂ ਨੂੰ ਚੋਰੀ-ਛੁਪੇ ਤੁਹਾਡਾ ਪਿੱਛਾ ਕਰਨ ਤੋਂ %1$s ਆਪਣੇ-ਆਪ ਰੋਕਦਾ ਹੈ। ਪੇਸ਼ ਕੀਤੀ ਪੂਰੀ ਕੂਕੀਜ਼ ਸੁਰੱਖਿਆ ਨਾਲ ਤੁਹਾਡੇ ਵਲੋਂ ਖੋਲ੍ਹੀਆਂ ਸਾਈਟਾਂ ਵਿਚਾਲੇ ਟਰੈਕਰਾਂ ਨੂੰ ਕੂਕੀਜ਼ ਵਰਤਣ ਤੋਂ ਰੋਕੋ। @@ -1299,18 +1287,10 @@ ਹੋਰ ਟਰੈਕਰਾਂ ਉੱਤੇ ਪਾਬੰਦੀ ਲਾਉਂਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਸਫ਼ੇ ਤੇਜ਼ੀ ਨਾਲ ਲੋਡ ਹੁੰਦੇ ਹਨ, ਪਰ ਕੁਝ ਸਫ਼ੇ ਸ਼ਾਇਦ ਠੀਕ ਤਰ੍ਹਾਂ ਕੰਮ ਨਾ ਕਰਨ। ਆਪਣੇ ਟੂਲਬਾਰ ਦੀ ਥਾਂ ਚੁਣੋ - - ਸੌਖੀ ਪਹੁੰਚ ਲਈ ਟੂਲਬਾਰ ਨੂੰ ਰੱਖੋ। ਹੇਠਾਂ ਰੱਖੋ ਜਾਂ ਇਸ ਨੂੰ ਉੱਤੇ ਰੱਖੋ। ਇਸ ਨੂੰ ਹੇਠਾਂ ਰੱਕੋ ਜਾਂ ਉੱਤੇ ਲੈ ਜਾਓ। - - ਤੁਹਾਡੀ ਪਰਦੇਦਾਰੀ ਆਪਣੇ ਡਾਟਾ ਨੂੰ ਕੰਟਰੋਲ ਕਰੋ - - ਅਸੀਂ %s ਨੂੰ ਇੰਝ ਬਣਾਇਆ ਹੈ ਕਿ ਤੁਹਾਡੇ ਕੋਲ ਪੂਰਾ ਕੰਟਰੋਲ ਹੋਵੇ ਕਿ ਤੁਸੀਂ -ਆਨਲਾਈਨ ਕੀ ਸਾਂਝਾ ਕਰਦੇ ਹੋ ਅਤੇ ਸਾਡੇ ਨਾਲ ਕੀ ਸਾਂਝਾ ਕਰਦੇ ਹੋ। Firefox ਤੁਹਾਡੇ ਹੱਥ ਕੰਟਰੋਲ ਦਿੰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਆਨਲਾਈਨ ਕੀ ਸਾਂਝਾ ਕਰਨਾ ਹੈ ਅਤੇ ਕੀ ਸਾਡੇ ਨਾਲ ਸਾਂਝਾ ਕਰਨਾ ਹੈ। @@ -1497,7 +1477,7 @@ ਚੇਪੋ ਤੇ ਜਾਓ ਚੇਪੋ - + URL ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕੀਤਾ @@ -1513,7 +1493,7 @@ ਸ਼ਾਰਟਕੱਟ ਨਾਂ - ਤੁਸੀਂ ਇਸ ਵੈੱਬਸਾਈਟ ਨੂੰ ਫ਼ੌਰੀ ਤੌਰ ਉੱਤੇ ਵਰਤਣ ਤੇ ਐਪ ਵਾਂਗ ਤੇਜ਼ ਬਰਾਊਜ਼ ਕਰਨ ਲਈ ਸੌਖੀ ਤਰ੍ਹਾਂ + ਤੁਸੀਂ ਇਸ ਵੈੱਬਸਾਈਟ ਨੂੰ ਫ਼ੌਰੀ ਤੌਰ ਉੱਤੇ ਵਰਤਣ ਤੇ ਐਪ ਵਾਂਗ ਤੇਜ਼ ਬਰਾਊਜ਼ ਕਰਨ ਲਈ ਸੌਖੀ ਤਰ੍ਹਾਂ ਮੁੱਖ ਸਕਰੀਨ ਉੱਤੇ ਸੌਖੀ ਤਰ੍ਹਾਂ ਜੋੜ ਸਕਦੇ ਹੋ। @@ -1945,7 +1925,9 @@ ਹੋਰ ਲੱਭੋ - Pocket ਵਲੋਂ ਇਖ਼ਤਿਆਰ + Pocket ਵਲੋਂ ਇਖ਼ਤਿਆਰ + + %s ਦੀ ਸਹਾਇਤਾ ਨਾਲ Firefox ਪਰਿਵਾਰ ਦਾ ਹਿੱਸਾ। %s @@ -1959,4 +1941,14 @@ ਸੈਟਿੰਗਾਂ ਉੱਤੇ ਜਾਓ Firefox ਸੁਝਾਅ + + + + ਸਮੇਟੋ + + ਫੈਲਾਓ + + ਇਹ ਭੰਡਾਰ ਬਾਰੇ ਹੋਰ ਸਿੱਖਣ ਲਈ ਲਿੰਕ ਖੋਲ੍ਹੋ + + ਲੇਖ ਨੂੰ ਪੜ੍ਹੋ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 594b5b6cd..f9825f392 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -15,6 +15,12 @@ Wyjdź z trybu prywatnego Wpisz adres lub szukaj + + Szukaj w historii + + Szukaj w zakładkach + + Szukaj w kartach Szukaj @@ -41,8 +47,6 @@ - Ostatnio dodane zakładki - Ostatnio zachowane Wyświetl wszystkie dodane zakładki @@ -130,13 +134,6 @@ Przycisk wyświetlania wszystkich ostatnich kart - - Wyszukiwanie „%1$s” - - - Witryny: %d Wszystkie karty z innych urządzeń @@ -260,38 +257,17 @@ Ustawienia wyszukiwania - - - Co nowego w przeglądarce %1$s - - Teraz łatwiej jest kontynuować od miejsca, w którym skończono. - - Spersonalizowana strona startowa przeglądarki %1$s - - Szybko przejdź do otwartych kart, zakładek i historii przeglądania. - - Przejrzyste, uporządkowane karty - - Pozbądź się bałaganu w kartach dzięki ulepszonemu układowi i automatycznemu zamykaniu kart. - - Ostatnie wyszukiwania - - Wróć do swoich ostatnich wyszukiwań na stronie startowej i w kartach. - - - Spersonalizowana strona startowa Firefoksa ułatwia teraz kontynuowanie od miejsca, w którym skończono. Znajdź swoje ostatnie karty, zakładki i wyniki wyszukiwania. + + Tym razem szukaj: + Poznaj swoją spersonalizowaną stronę startową. Tutaj będą wyświetlane ostatnie karty, zakładki i wyniki wyszukiwania. - Witamy w niezależnym Internecie - Witamy w bardziej spersonalizowanym Internecie Więcej kolorów. Większa prywatność. Stawianie ludzi ponad zyski — bez zmian. - Przełączaj się z telefonu na laptopa i z powrotem - Przechodzenie między urządzeniami jest łatwiejsze niż kiedykolwiek Kontynuuj w tym samym miejscu, korzystając z kart z innych urządzeń, które teraz są na stronie startowej. @@ -304,6 +280,9 @@ Twoje karty są synchronizowane! Kontynuuj w tym samym miejscu, co na drugim urządzeniu. + + Zamknij + Otwórz nową kartę w przeglądarce %1$s @@ -461,8 +440,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Ostatnio odwiedzone - Pocket + Pocket + + Artykuły skłaniające do myślenia + + Artykuły dostarczane przez %s Sponsorowane artykuły @@ -485,12 +468,6 @@ Nie udało się zmienić tapety Więcej informacji - - Zmień tapetę, stukając logo na stronie startowej Firefoksa - - - Logo Firefoksa — zmień tapetę, przycisk Klasyczny %s @@ -648,6 +625,17 @@ Zamknij + + Otworzyć wiele kart (%d)? + + Otwarcie tak wielu kart jednocześnie może spowodować spowolnienie pracy przeglądarki %s na czas wczytywania stron. Czy na pewno kontynuować? + + Otwórz karty + + Anuluj + Witryny: %d @@ -678,10 +666,6 @@ Lista Siatka - - Grupy wyszukiwań - - Grupuje powiązane witryny Zamykaj karty @@ -834,18 +818,6 @@ Nie ma jeszcze historii - - Z innych urządzeń - - Z innych urządzeń - - - Zaloguj się, aby wyświetlić historię zsynchronizowaną z innych urządzeń. - - Zaloguj się - - Lub utwórz konto Firefoksa, aby rozpocząć synchronizację]]> - Wyczyszczono listę @@ -895,6 +867,10 @@ Otwórz w nowej karcie Otwórz w prywatnej karcie + + Otwórz wszystkie w nowych kartach + + Otwórz wszystkie w prywatnych kartach Usuń @@ -1072,6 +1048,10 @@ Udostępnij + + Zapisz jako PDF + + Utworzenie pliku PDF się nie powiodło Wyślij na urządzenie @@ -1083,9 +1063,11 @@ Skopiowano do schowka - Zaloguj się do synchronizacji + Zaloguj się do synchronizacji Zaloguj się do synchronizacji + + Synchronizuj i zachowuj dane Wyślij na wszystkie urządzenia @@ -1247,33 +1229,20 @@ Usunięto grupę - - Witamy w przeglądarce %s! Witamy w lepszym Internecie Przeglądarka tworzona dla ludzi, nie dla zysku. - - Synchronizuj Firefoksa między urządzeniami Kontynuuj przeglądanie - - Przenieś zakładki, historię i hasła do przeglądarki %1$s na tym urządzeniu. Synchronizuj karty i hasła między urządzeniami, aby błyskawicznie przechodzić z ekranu na ekran. - - Utwórz konto Zaloguj się Synchronizacja jest włączona - - Zawsze włączona prywatność Ochrona prywatności bez konfiguracji - - %1$s automatycznie uniemożliwia firmom potajemne śledzenie Cię w Internecie. Zawiera całkowitą ochronę ciasteczek, która uniemożliwia elementom śledzącym używanie ciasteczek do śledzenia Cię między witrynami. @@ -1286,17 +1255,10 @@ Blokuje więcej elementów śledzących, dzięki czemu strony wczytują się szybciej, ale część ich funkcji może nie działać. Wybierz położenie paska narzędzi - - Miej pasek narzędzi zawsze pod ręką. Zostaw go na dole lub przenieś na górę. Zostaw go na dole lub przenieś na górę. - - Twoja prywatność Ty kontrolujesz swoje dane - - %s został zaprojektowany tak, aby dać Ci kontrolę nad tym, co udostępniasz w sieci i czym dzielisz się z nami. Firefox daje Ci kontrolę nad tym, co udostępniasz w sieci i czym dzielisz się z nami. @@ -1484,10 +1446,10 @@ Wklej i przejdź Wklej - + Skopiowano adres do schowka - + Dodaj do ekranu głównego @@ -1932,7 +1894,9 @@ Odkryj więcej - Dostarczane przez Pocket. + Dostarczane przez Pocket. + + Dostarczane przez %s. Część rodziny Firefoksa. %s @@ -1946,4 +1910,14 @@ Przejdź do ustawień Podpowiedzi Firefoksa + + + + zwinąć + + rozwinąć + + otworzyć odnośnik z informacjami o tej kolekcji + + przeczytać artykuł diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 7aaca4538..331f0ba3a 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -14,6 +14,12 @@ Desativar navegação privativa Pesquise ou digite um endereço + + Pesquisar no histórico + + Pesquisar nos favoritos + + Pesquisar nas abas Digite termos de pesquisa @@ -39,8 +45,6 @@ - Favoritos recentes - Salvo recentemente Mostrar todos os favoritos salvos @@ -130,13 +134,6 @@ Botão de exibir todas as abas recentes - - Sua pesquisa de \"%1$s\" - - - %d sites Ver todas as abas sincronizadas @@ -259,40 +256,20 @@ Configurações da pesquisa - - - Novidades no %1$s - - Agora é mais fácil continuar de onde você parou. - - Tela inicial personalizada do %1$s - - Vá direto para suas abas abertas, favoritos e histórico de navegação. - - - Abas limpas e organizadas - - - Layout aprimorado e fechamento automático de abas para remover o excesso de abas. - - Pesquisas recentes - - Revisite suas pesquisas recentes feitas na tela inicial e em abas. - - - A tela inicial personalizada do Firefox agora facilita continuar de onde você parou. Encontre suas abas, favoritos e resultados de pesquisa recentes. + + Desta vez pesquisar: + + Desta vez, pesquisar em: + + Conheça sua tela inicial personalizada. Abas recentes, favoritos e resultados de pesquisa aparecem aqui. - Boas-vindas a uma internet independente - Boas-vindas a uma internet mais pessoal Mais cores. Melhor privacidade. Mesmo compromisso com pessoas acima de lucros. - Alterne entre celular e notebook - Mudar de tela está mais fácil do que nunca Continue agora de onde parou, com abas de outros dispositivos na sua tela inicial. @@ -306,6 +283,9 @@ Suas abas estão sendo sincronizadas! Continue de onde parou em outro dispositivo. + + Fechar + Abrir nova aba no %1$s @@ -350,13 +330,21 @@ Permitir captura de tela na navegação privativa - Se permitido, as abas privativas também ficam visíveis quando vários aplicativos estão abertos + Se permitido, abas privativas também permanecem visíveis ao mudar para outros aplicativos Adicionar atalho para navegação privativa Modo somente HTTPS + + + Redução de avisos de cookies + + Reduzir avisos de cookies + + O Firefox tenta rejeitar automaticamente solicitações de cookies em avisos de cookies. Se não estiver disponível uma opção de rejeição, o Firefox pode aceitar todos os cookies para descartar o aviso. + - Tenta se conectar com sites usando automaticamente o protocolo de criptografia HTTPS para maior segurança. + Tentar se conectar com sites usando automaticamente o protocolo de criptografia HTTPS para maior segurança. Ativado @@ -461,8 +449,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visitado recentemente - Pocket + Pocket + + Histórias que instigam o pensamento + + Artigos sugeridos pelo %s Histórias patrocinadas @@ -487,21 +479,15 @@ Não foi possível mudar o fundo de tela Saiba mais - - Mudar o fundo de tela tocando no logotipo do Firefox na tela inicial - - - Logotipo do Firefox - mudar fundo de tela, botão %s clássico Edição limitada - A nova coleção de vozes independentes. %s + Nova coleção de vozes independentes. %s - A nova coleção de vozes independentes. + Nova coleção de vozes independentes. Experimente um toque de cores @@ -648,6 +634,17 @@ Fechar + + Abrir %d abas? + + Abrir tantas abas pode deixar o %s lento enquanto as páginas são carregadas. Tem certeza que quer continuar? + + Abrir abas + + Cancelar + %d site @@ -677,10 +674,6 @@ Lista Grade - - Grupos de pesquisa - - Agrupar sites relacionados Fechar abas @@ -833,18 +826,6 @@ Nenhum histórico aqui - - Sincronizado de outros dispositivos - - De outros dispositivos - - - Entre para ver o histórico sincronizado de seus outros dispositivos. - - Entrar - - Ou crie uma conta Firefox para começar a sincronizar]]> - Downloads removidos @@ -894,6 +875,10 @@ Abrir em nova aba Abrir em aba privativa + + Abrir tudo em novas abas + + Abrir tudo em abas privativas Excluir @@ -1072,6 +1057,10 @@ Compartilhar + + Salvar como PDF + + Não foi possível gerar PDF Enviar para dispositivo @@ -1083,9 +1072,11 @@ Copiado para área de transferência - Entrar para sincronizar + Entrar para sincronizar Entrar no Sync + + Sincronizar e salvar dados Enviar para todos os dispositivos @@ -1122,6 +1113,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Defina o %1$s como navegador padrão + + Experimente a navegação privativa + + Navegue sem salvar cookies nem histórico no %1$s + Coleção excluída @@ -1209,7 +1206,7 @@ Limpar dados de navegação ao sair - Excluir automaticamente os dados de navegação selecionados abaixo ao selecionar \"Sair\" no menu principal + Excluir automaticamente os dados de navegação selecionados abaixo ao tocar em \"Sair\" no menu principal Sair @@ -1245,33 +1242,20 @@ Grupo excluído - - Boas-vindas ao %s! Boas-vindas a uma internet melhor Um navegador feito para as pessoas, não para o lucro. - - Sincronize o Firefox entre dispositivos Continue de onde você parou - - Traga favoritos, histórico e senhas para o %1$s neste dispositivo. Sincronize abas e senhas entre dispositivos para mudar facilmente de uma tela para outra. - - Criar uma conta Entrar A sincronização está ativada - - Privacidade sempre ativa Proteção de privacidade por padrão - - O %1$s impede automaticamente que empresas sigam você secretamente pela web. Apresentamos a proteção total contra cookies para impedir que rastreadores usem cookies para te perseguir de um site para outro. @@ -1284,17 +1268,10 @@ Bloqueia mais rastreadores, assim as páginas carregam mais rápido, mas pode atrapalhar algumas funcionalidades de páginas. Escolha a posição da barra de ferramentas - - Facilite o alcance à barra de ferramentas. Mantenha embaixo, ou mova para cima. Mantenha na parte de baixo, ou mova para o alto. - - Sua privacidade Você controla seus dados - - Projetamos o %s para te dar controle sobre o que você compartilha online e o que você compartilha conosco. O Firefox te dá o controle sobre o que você compartilha online e o que compartilha conosco. @@ -1340,7 +1317,7 @@ Usar email - Crie uma para sincronizar o Firefox entre dispositivos.]]> + Crie para sincronizar o Firefox entre dispositivos.]]> O %s deixará de sincronizar com sua conta, mas não excluirá seus dados de navegação neste dispositivo. @@ -1938,7 +1915,9 @@ Descubra mais - Proporcionado pelo Pocket. + Proporcionado pelo Pocket. + + Com tecnologia %s. Parte da família Firefox. %s @@ -1952,4 +1931,14 @@ Ir para configurações Sugestões Firefox + + + + recolher + + expandir + + abrir link para saber mais sobre esta coleção + + ler o artigo diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index b23e7f3e8..ff9e6a3fe 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -15,6 +15,12 @@ Desativar navegação privada Pesquise ou insira o endereço + + Pesquisar histórico + + Pesquisar marcadores + + Pesquisar separadores Introduza os termos de pesquisa @@ -41,8 +47,6 @@ - Marcadores recentes - Recentemente guardados Mostrar todos os marcadores guardados @@ -131,13 +135,6 @@ Mostrar botão todos os separadores recentes - - A sua pesquisa por \"%1$s\" - - - %d sites Ver todos os separadores sincronizados @@ -259,38 +256,20 @@ Definições de pesquisa - - - Novidades do %s - - Agora é mais simples continuar de onde parou. - - Página inicial personalizada do %1$s - - Aceda aos seus separadores abertos, marcadores e histórico de navegação. - - Separadores limpos e organizados - - Elimine a confusão de separadores com um esquema melhorado e encerramento automático de separadores. - - Pesquisas recentes - - Revisite as suas pesquisas mais recentes na sua página inicial e separadores. - - - A sua página inicial personalizada do Firefox faz com que agora seja mais simples continuar de onde parou. Encontre os seus separadores, marcadores e resultados de pesquisa recentes. + + Pesquisa neste momento: + + Desta vez pesquisar em: + + Conheça a sua página inicial personalizada. Aqui vão ser apresentados separadores recentes, marcadores e resultados de pesquisas. - Bem-vindo/a a uma Internet independente - Bem-vindo a uma internet mais pessoal Mais cores. Melhor privacidade. O mesmo compromisso com as pessoas, acima dos lucros. - Alternar do telemóvel para o portátil e vice-versa - Alterar entre ecrãs é mais fácil do que nunca Continue de onde parou com os separadores de outros dispositivos agora na sua página inicial. @@ -304,6 +283,9 @@ Os seus separadores estão a ser sincronizados! Continue de onde parou no seu outro dispositivo. + + Fechar + Abrir um novo separador do %1$s @@ -353,6 +335,14 @@ Adicionar um atalho de navegação privada Modo apenas HTTPS + + + Redução de Faixas de Cookies + + Reduzir faixas de cookies + + O Firefox tenta rejeitar automaticamente pedidos de cookies em faixas de cookies. Se uma opção de rejeição não estiver disponível, o Firefox poderá aceitar todos os cookies para esconder a faixa. + Automaticamente tenta conectar-se a sites utilizando o protocolo de encriptação HTTPS para uma melhor segurança. @@ -459,8 +449,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visualizados recentemente - Pocket + Pocket + + Histórias que fazem pensar + + Artigos suportados pelo %s Histórias patrocinadas @@ -483,12 +477,6 @@ Não foi possível alterar o fundo Saber mais - - Altere o fundo ao tocar no logótipo da página principal do Firefox - - - Logótipo do Firefox - altere o fundo, botão %s clássico @@ -648,6 +636,17 @@ Fechar + + Abrir %d separadores? + + Abrir tantos separadores poderá desacelerar o %s enquanto as páginas estiverem a carregar. Tem a certeza de que quer continuar? + + Abrir separadores + + Cancelar + %d site @@ -677,10 +676,6 @@ Lista Grelha - - Pesquisar grupos - - Agrupar sites relacionados Fechar separadores @@ -830,18 +825,6 @@ Sem histórico - - Sincronizado de outros dispositivos - - De outros dispositivos - - - Inicie sessão para ver o histórico sincronizado dos seus outros dispositivos. - - Iniciar sessão - - Ou crie uma conta Firefox para iniciar a sincronização]]> - Transferências removidas @@ -892,6 +875,10 @@ Abrir num separador novo Abrir num separador privado novo + + Abrir todos em novos separadores + + Abrir todos em separadores privados Eliminar @@ -1069,6 +1056,10 @@ Partilhar + + Guardar como PDF + + Não foi possível gerar o PDF Enviar para o dispositivo @@ -1080,9 +1071,11 @@ Copiado para a área de transferência - Iniciar sessão para sincronizar + Iniciar sessão para sincronizar Iniciar sessão para sincronizar + + Sincronizar e guardar os dados Enviar para todos os dispositivos @@ -1118,6 +1111,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Escolher o %1$s como o seu navegador predefinido + + Experimente a navegação privada + + Navegue sem guardar cookies nem histórico no %1$s + Coleção eliminada @@ -1240,35 +1239,21 @@ Grupo eliminado - - Bem-vindo ao %s! - Bem-vindo a uma internet melhor Um navegador feito para as pessoas e não para os lucros. - - Sincronizar o Firefox entre dispositivos Continue de onde ficou - - Traga os marcadores, histórico e palavras-passe para o %1$s neste dispositivo. Sincronize separadores e palavras-passe entre dispositivos para uma troca transparente entre ecrãs. - - Registar Iniciar sessão A sincronização está ativada - - Privacidade sempre ativa Proteção de privacidade por predefinição - - O %1$s impede automaticamente que as empresas o sigam secretamente pela Internet. A apresentar a Proteção total de cookies para parar os rastreadores de utilizar cookies que o/a perseguem na Internet. @@ -1281,17 +1266,10 @@ Bloqueia mais rastreadores para que as páginas carreguem mais rapidamente, mas algumas funcionalidades das páginas podem ser perdidas. Escolha o posicionamento da barra de ferramentas - - Facilite o acesso à barra de ferramentas. Mantenha a mesma na parte inferior ou mova-a para cima. Manter na parte inferior ou mover para o topo. - - A sua privacidade Você controla os seus dados - - Nós desenhámos o %s para lhe dar mais controlo sobre o que partilha online e o que partilha connosco. O Firefox dá-lhe mais controlo sobre o que partilha na Internet e o que partilha connosco. @@ -1510,7 +1488,7 @@ Nunca guardar - Auto-preenchimento em %1$s + Autopreenchimento do %1$s Preencher e guardar nomes de utilizador e palavras-passe em site ao utilizar o %1$s. @@ -1933,7 +1911,9 @@ Descobrir mais - Com tecnologia do Pocket. + Com tecnologia do Pocket. + + Suportado por %s. Membro da família Firefox. %s @@ -1947,4 +1927,14 @@ Ir para as definições Sugestões Firefox + + + + colapsar + + expandir + + abrir ligação para saber mais sobre esta coleção + + ler o artigo diff --git a/app/src/main/res/values-rm/strings.xml b/app/src/main/res/values-rm/strings.xml index b5233ea85..b4909d135 100644 --- a/app/src/main/res/values-rm/strings.xml +++ b/app/src/main/res/values-rm/strings.xml @@ -14,6 +14,12 @@ Deactivar il modus privat Tschertgar u endatar in\'adressa + + Tschertgar en la cronologia + + Tschertgar en ils segnapaginas + + Tschertgar en ils tabs Endatar ils terms da tschertga @@ -39,8 +45,6 @@ - Tschernì dacurt sco segnapagina - Memorisà dacurt Mussar tut ils segnapaginas memorisads @@ -127,13 +131,6 @@ Buttun per mussar tut ils tabs averts dacurt - - Tia tschertga da «%1$s» - - - %d websites Mussar tut ils tabs sincronisads @@ -254,39 +251,20 @@ Parameters da tschertga - - - Las novaziuns en %1$s - - Ussa èsi pli simpel da cuntinuar là nua che ti has chalà. - - Pagina da partenza da %1$s persunalisada - - Siglir tar tes tabs averts, tes segnapaginas e tia cronologia da navigaziun. - - Tabs organisads e survesaivels - - - Reducescha il caos cun in layout optimà e cun tabs che sa serran automaticamain. - - Tschertgà dacurt - - Turna als resultats da tias ultimas tschertgas – directamain da la pagina da partenza e dals tabs. - - - Cun tia pagina da partenza da Firefox persunalisada èsi ussa pli simpel da cuntinuar là nua che ti has chalà. Ti chattas tes ultims tabs, segnapaginas e resultats da tschertga. + + Tschertgar questa giada: + + Questa giada tschertgar cun/en: + + Emprenda d\'enconuscher tia pagina da partenza persunalisada. Tabs recents, segnapaginas e resultats da tschertga vegnan a cumparair qua. - Bainvegni en in internet independent - Bainvegni en in internet pli persunal Novas colurs. Dapli protecziun da datas. Ma il medem engaschi per las persunas, betg per il profit. - Mida dal telefonin al laptop ed enavos - La midada dad in visur a l\'auter è ussa pli simpla che mai Cuntinuescha là nua che ti has smess cun ils tabs dad auters apparats che figureschan ussa sin tia pagina da partenza. @@ -299,6 +277,9 @@ Tes tabs vegnan sincronisads! Cuntinuescha là nua che ti has smess sin tes auter apparat. + + Serrar + Avrir in nov tab da %1$s @@ -348,6 +329,14 @@ Agiuntar ina scursanida al modus privat Modus mo HTTPS + + + Reducziun da bandieras da cookies + + Reducir las bandieras da cookies + + Firefox emprova da refusar automaticamain dumondas da cookies sin bandieras da cookies. Sche l\'opziun da refusar na stat betg a disposiziun, accepta Firefox eventualmain tut ils cookies per serrar la bandiera. + Empruvar da connectar automaticamain cun websites cun agid dal protocol da criptadi HTTPS per dapli segirezza. @@ -454,8 +443,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Visità dacurt - Pocket + Pocket + + Istorgias che dattan da pensar + + Artitgels da %s Artitgels sponsurads @@ -478,12 +471,6 @@ Impussibel da midar il maletg dal fund davos Ulteriuras infurmaziuns - - Mida il maletg dal fund davos cun tutgar il logo da Firefox sin la pagina da partenza - - - Logo da Firefox – midar il maletg dal fund davos, buttun %s classic @@ -640,6 +627,17 @@ Serrar + + Avrir %d tabs? + + Cun avrir tants tabs vegn %s eventualmain ralentà durant che las paginas vegnan chargiadas. Vuls ti propi cuntinuar? + + Avrir ils tabs + + Interrumper + %d website @@ -669,10 +667,6 @@ Glista Griglia - - Gruppas da tschertgar - - Gruppar websites che tutgan ensemen Serrar ils tabs @@ -821,18 +815,6 @@ Nagina cronologia - - Sincronisà dad auters apparats - - Dad auters apparats - - - T\'annunzia per vesair la cronologia sincronisada da tes auters apparats. - - S\'annunziar - - U creescha in conto da Firefox per cumenzar a sincronisar]]> - Allontanà las telechargiadas @@ -882,6 +864,10 @@ Avrir en in nov tab Avrir en in tab privat + + Avrir tuts en novs tabs + + Avrir tuts en tabs privats Stizzar @@ -1058,6 +1044,10 @@ Cundivider + + Memorisar sco PDF + + Impussibel da generar il PDF Trametter a l\'apparat @@ -1069,9 +1059,11 @@ Copià en l\'archiv provisoric - S\'annunziar per sincronisar + S\'annunziar per sincronisar S\'annunziar tar Sync + + Sincronisar e memorisar las datas Trametter a tut ils apparats @@ -1110,6 +1102,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Fa da %1$s tes navigatur da standard + + Emprova il modus privat + + Navighescha senza memorisar ni cookies ni la cronologia en %1$s + Stizzà la collecziun @@ -1234,34 +1232,21 @@ Stizzà la gruppa - - Bainvegni en %s! Bainvegni en in meglier internet In navigatur creà per persunas, betg per daners. - - Sincronisescha Firefox sin differents apparats Cuntinuescha là nua che ti has chalà - - Importescha segnapaginas, la cronologia e pleds-clav en %1$s sin quest apparat. Sincronisescha tabs e pleds-clav tranter tes apparats per midar senza interrupziun dad in visur a l\'auter. - - Sa registrar S\'annunziar Sync è activà - - Protecziun da datas franco fabrica Protecziun da la sfera privata sco standard - - %1$s impedescha automaticamain che interpresas ta persequiteschian a la zuppada en il web. Ussa cun la protecziun totala cunter cookies per impedir ch\'ils fastizaders dovrian ils cookies per ta persequitar sur pliras websites. @@ -1275,17 +1260,10 @@ Blochescha ulteriurs fastizaders, uschia che paginas chargian pli svelt, ma tschertas paginas na funcziunan eventualmain betg pli endretg. Tscherna la posiziun da la trav d\'utensils - - Plazzescha la trav d\'utensils uschia ch\'ella è cuntanschibla a moda optimala. La mantegna giusut u la plazzescha sisum. Lascha ella giusut u la sposta ensi. - - Tia sfera privata Ti controlleschas tias datas - - Nus avain creà %s per che ti possias controllar tge che ti cundividas en l\'internet e tge che ti cundividas cun nus. Firefox ta pussibilitescha da controllar tge che ti cundividas en l\'internet e tge che ti cundividas cun nus. @@ -1931,7 +1909,9 @@ Scuvrir dapli - Cun tecnologia da Pocket. + Cun tecnologia da Pocket. + + Cun agid da %s. Part da la paletta da products Firefox. %s @@ -1945,4 +1925,14 @@ Ir als parameters Firefox propona + + + + reducir + + extender + + avrir la colliaziun per vegnir a savair dapli davart questa collecziun + + leger l\'artitgel diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index b96bad7ac..76310ecfb 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -17,6 +17,12 @@ Введите запрос или адрес + + Поиск в журнале + + Поиск в закладках + + Поиск во вкладках Введите поисковые запросы @@ -28,23 +34,21 @@ Выбрано: %1$d - Создать новую коллекцию + Создать новый сборник Название - Выберите коллекцию + Выберите сборник Выйти из режима множественного выбора - Сохранить выбранные вкладки в коллекцию + Сохранить выбранные вкладки в сборник Выбрано - Недавние закладки - Недавно добавленные Показать все сохраненные закладки @@ -135,13 +139,6 @@ Кнопка показа всех недавних вкладок - - Ваш поиск \"%1$s\" - - - Сайтов: %d Все облачные вкладки @@ -198,7 +195,7 @@ Найти на странице - В коллекцию + В сборник Поделиться - Cканировать + Считать Поисковая система @@ -267,39 +264,20 @@ Настройки поиска - - - Что нового в %1$s - - Теперь легче продолжить с того места, где вы остановились. - - Настраиваемая домашняя страница %1$s - - Переходите к открытым вкладкам, закладкам и истории просмотра. - - Лучшая организация вкладок - - - Вкладки стали более организованы с использованием улучшенного размещения и автоматического закрытия. - - Недавние поиски - - Вернитесь к последним поисковым запросам с домашней страницы и вкладок. - - - На настроенной вами домашней странице Firefox теперь легче продолжить с того места, где вы остановились. Найдите свои недавние вкладки, закладки и результаты поиска. + + В этот раз искать: + + В этот раз искать в: + + Познакомьтесь с настраиваемой домашней страницей. Здесь будут отображаться последние вкладки, закладки и результаты поиска. - Добро пожаловать в независимый интернет - Добро пожаловать в более личный Интернет Больше красок. Лучшая приватность. Обязательство перед людьми, а не погоня за прибылью. - Переходите с телефона на ноутбук и обратно - Переключение экранов стало проще, чем когда-либо Продолжайте с того места, где вы остановились, с вкладками с других устройств, которые теперь находятся на вашей домашней странице. @@ -313,6 +291,9 @@ Ваши вкладки синхронизируются! Продолжайте с того места, на котором остановились на другом устройстве. + + Закрыть + Открыть новую вкладку %1$s @@ -350,19 +331,28 @@ Приватность и защита - Разрешения для сайтов + Разрешения сайтов Приватный просмотр Открывать ссылки в приватной вкладке - Разрешить скриншоты при приватном просмотре + Разрешить снимки экрана при приватном просмотре В случае, если разрешено, приватные вкладки будут видны при просмотре нескольких приложений Добавить ярлык приватного просмотра Режим «Только HTTPS» + + + Снижение числа уведомлений о куках + + + Снижать число уведомлений о куках + + Firefox автоматически пытается отклонить запросы на установку кук при показе уведомлений о них. Если вариант отклонения недоступен, Firefox может принять все куки, чтобы скрыть уведомление. + Автоматически пытаться подключиться к сайтам через протокол шифрования HTTPS для повышения безопасности. @@ -378,9 +368,9 @@ Защищённый сайт недоступен - Скорее всего, веб-сайт просто не поддерживает HTTPS. + Скорее всего, сайт не поддерживает HTTPS. - Однако возможно вмешательство злоумышленников. Если вы продолжите переход на веб-сайт, вам не следует вводить на нём какие-либо конфиденциальные данные. Если вы продолжите, режим «Только HTTPS» для этого сайта будет временно отключён. + Однако возможно вмешательство злоумышленников. Если вы продолжите переход на сайт, вам не следует вводить на нём какие-либо личные данные. Если вы продолжите, режим «Только HTTPS» для этого сайта будет временно отключён. Специальные возможности @@ -426,7 +416,7 @@ Предложения из буфера обмена - Поиск по истории сёрфинга + Поиск по истории просмотра сети Поиск закладок @@ -435,7 +425,7 @@ Настройки Аккаунта - Автодополнение URL + Автозаполнение сетевых адресов Открывать ссылки в приложениях @@ -449,17 +439,17 @@ - Собственная коллекция дополнений + Собственный сборник дополнений OK Отмена - Имя коллекции + Имя сборника - Владелец коллекции (ID пользователя) + Владелец сборника (идентификатор пользователя) - Коллекция дополнений была изменена. Закрываем приложение, чтобы применить изменения… + Сборник дополнений был изменён. Закрываем приложение, чтобы применить изменения… @@ -470,8 +460,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Недавно посещённые - Pocket + Pocket + + Истории, наводящие на размышления + + Статьи от %s Статьи спонсоров @@ -494,11 +488,6 @@ Не удалось сменить обои Подробнее - - Меняйте обои, коснувшись логотипа домашней страницы Firefox - - Логотип Firefox - сменить обои, кнопка Классический %s @@ -531,7 +520,7 @@ Закладки - Логины + Пароли Открытые вкладки @@ -590,7 +579,7 @@ Маркетинговые данные - Делиться базовыми данными об использовании с Adjust, нашим мобильным маркетинговым вендором + Делиться основными данными об использовании с Adjust, нашим мобильным маркетинговым поставщиком Исследования @@ -598,7 +587,7 @@ - Синхронизация и сохранение данных + Синхронизация Войти, чтобы подключиться снова @@ -606,7 +595,7 @@ - firefox.com/pair]]> + firefox.com/pair]]> @@ -656,6 +645,17 @@ Закрыть + + Открыть %d вкладок? + + Открытие такого количества вкладок может замедлить работу %s на время, требуемое для загрузки этих страниц. Вы действительно хотите это сделать? + + Открыть вкладки + + Отмена + %d сайт @@ -686,10 +686,6 @@ Списком Сеткой - - Поисковые группы - - Группировать связанные сайты Закрывать вкладки @@ -770,7 +766,7 @@ Настройки Аккаунта - Параметры вкладок + Настройки вкладок Закрыть все вкладки @@ -792,17 +788,17 @@ Меню открытых вкладок - Сохранить вкладки в коллекцию + Сохранить вкладки в сборник - Удалить коллекцию + Удалить сборник - Переименовать коллекцию + Переименовать сборник Открыть вкладки - Имя коллекции + Имя сборника Переименовать @@ -841,18 +837,6 @@ История отсутствует - - Синхронизировано с других устройств - - С других устройств - - - Войдите, чтобы увидеть историю с других ваших устройств. - - Войти - - Или создайте учётную запись Firefox, чтобы начать синхронизацию]]> - Загрузки удалены @@ -904,6 +888,10 @@ Открыть в новой вкладке Открыть в приватной вкладке + + Открыть все в новых вкладках + + Открыть все в приватных вкладках Удалить @@ -918,7 +906,7 @@ Войдите, чтобы увидеть свои синхронизируемые закладки - URL + Адрес страницы ПАПКА @@ -930,7 +918,7 @@ Должна иметь заголовок - Некорректный URL + Недействительный сетевой адрес Здесь нет закладок Межсайтовые куки - Защищённое DRM содержимое + Защищённое авторским правом содержимое Всегда спрашивать @@ -1002,21 +990,21 @@ Отключена - Разрешить аудио и видео + Разрешить звук и видео - Разрешить аудио и видео + Разрешить звук и видео - Блокировать аудио и видео только при использовании мобильных данных + Блокировать звук и видео только при использовании мобильных данных - Аудио и видео будут проигрываться при использовании Wi-Fi + Звуки и видео будут проигрываться при использовании Wi-Fi - Блокировать только аудио + Блокировать только звуки - Блокировать только аудио + Блокировать только звуки - Блокировать аудио и видео + Блокировать звуки и видео - Блокировать аудио и видео + Блокировать звуки и видео Включено @@ -1029,9 +1017,9 @@ - Коллекции + Сборники - Меню коллекции + Меню сборника Собирайте то, что важно для вас.\nОбъединяйте похожие запросы, сайты и вкладки для быстрого доступа в будущем. @@ -1039,13 +1027,13 @@ Выберите вкладки - Выберите коллекцию + Выберите сборник - Имя коллекции + Имя сборника - Создать новую коллекцию + Создать новый сборник Выбрать все @@ -1066,7 +1054,7 @@ Вкладки сохранены! - Коллекция сохранена! + Сборник сохранён! Вкладка сохранена! @@ -1085,7 +1073,7 @@ Отмена - Коллекция %d + Сборник %d @@ -1093,6 +1081,10 @@ Поделиться + + Сохранить как PDF + + Не удалось сгенерировать PDF Отправить на устройство @@ -1104,9 +1096,11 @@ Скопировано в буфер обмена - Войти в синхронизацию + Войти в синхронизацию Войти в синхронизацию + + Синхронизация и сохранение данных Отправить на все устройства @@ -1144,12 +1138,18 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Сделайте %1$s вашим браузером по умолчанию + + Попробуйте приватный просмотр + + Просмотр без сохранённых кук или истории в %1$s + - Коллекция удалена + Сборник удалён - Коллекция переименована + Сборник переименован Вкладка закрыта @@ -1176,13 +1176,13 @@ ЗАПРЕТИТЬ - Веб-адрес недействителен. + Сетевой адрес недействителен. OK Вы уверены, что хотите удалить %1$s? - Удалив эту вкладку, вы удалите всю коллекцию. Вы можете создавать новые коллекции в любое время. + Удалив эту вкладку, вы удалите весь сборник. Вы можете создавать новые сборники в любое время. Удалить %1$s? @@ -1191,7 +1191,7 @@ Вход в полноэкранный режим - URL скопирован + Ссылка скопирована @@ -1204,16 +1204,16 @@ Автоматический размер шрифта - Размер шрифта будет соответствовать настройкам Android. Отключите этот параметр, чтобы управлять размером шрифта здесь. + Размер шрифта будет соответствовать настройкам Android. Отключите эту настройку, чтобы управлять размером шрифта здесь. - Удаление данных веб-сёрфинга + Удаление данных просмотра сети Открытые вкладки Вкладок: %d - История веб-сёрфинга и данные сайтов + История просмотра сети и данные сайтов Адресов: %d @@ -1230,17 +1230,17 @@ Загрузки - Удалить данные веб-сёрфинга + Удалить данные просмотра сети - Удалять данные веб-сёрфинга при выходе + Удалять данные просмотра сети при выходе - Автоматически удаляет данные веб-сёрфинга, когда вы выбираете \"Выйти\" в главном меню + Автоматически удаляет данные просмотра сети, когда вы выбираете \"Выйти\" в главном меню Выйти - Диапазон времени для удаления + Промежуток времени для удаления Удаляет историю (включая историю с других устройств), куки и другие данные просмотра. @@ -1251,16 +1251,16 @@ Всё - %s удалит выбранные данные веб-сёрфинга. + %s удалит выбранные данные просмотра сети. Отмена Удалить - Данные веб-сёрфинга удалены + Данные просмотра сети удалены - Удаляем данные веб-сёрфинга… + Удаляем данные просмотра сети… Удалить все сайты в «%s» @@ -1272,66 +1272,46 @@ Группа удалена - - Добро пожаловать в %s! Добро пожаловать в лучший Интернет Браузер, созданный для людей, а не для прибыли. - - Синхронизация Firefox между устройствами Начните с того места, на котором остановились - - Перенесите закладки, историю и пароли в %1$s на этом устройстве. Синхронизируйте вкладки и пароли между устройствами для бесшовного перехода между экранами. - - Зарегистрироваться Войти Началась синхронизация - - Постоянная приватность Защита приватности по умолчанию - - %1$s автоматически блокирует тайную слежку компаний за вами в Интернете. Представляем полную защиту от кук, не позволяющую трекерам использовать куки для отслеживания вас на разных сайтах. - Стандартная (по умолчанию) + Обычная (по умолчанию) - Обеспечивает наилучший баланс приватности и производительности. Страницы будут загружаться нормально. + Золотая середина: приватность и производительность. Страницы будут загружаться приемлемо. Строгая - Блокирует больше трекеров, так что страницы загружаются быстрее, но некоторые страницы могут работать некорректно. + Блокирует больше трекеров, так что страницы загружаются быстрее, но некоторые страницы могут работать неправильно. Выберите размещение панели инструментов - - Обеспечьте удобный доступ к панели инструментов. Оставьте её внизу или переместите вверх. Оставьте её внизу или переместите наверх. - - Ваша приватность - Вы контролируете свои данные - - Мы создали %s, чтобы предоставить вам контроль над тем, чем вы делитесь — как в Интернете, так и с нами. + Вы управляете своими данными - Firefox даёт вам контроль над тем, чем вы делитесь — как в Интернете, так и с нами. + Firefox даёт вам управлять тем, чем вы делитесь — как в сети, так и с нами. Уведомление о конфиденциальности Готовы открыть для себя удивительный Интернет? - Начать веб-сёрфинг + Начать просмотр сети @@ -1341,7 +1321,7 @@ Автоматическая - Адаптируется к настройкам вашего устройства + Использует настройки вашего устройства Тёмная тема @@ -1356,11 +1336,11 @@ ПОВТОРИТЬ - Сканирование QR-кода + Считывание штрих-кода https://firefox.com/pair]]> - Сканировать QR-код + Считать штрих-код Войти с помощью камеры @@ -1382,17 +1362,17 @@ Улучшенная защита от отслеживания - Сёрфите по Интернету без слежки + Используйте Интернет без слежки Храните свои данные при себе. %s защитит вас от многих наиболее известных трекеров, которые следят за вашим поведением в Интернете. Узнать больше - Стандартная (по умолчанию) + Обычная (по умолчанию) - Обеспечивает наилучший баланс приватности и производительности. Страницы будут загружаться нормально. + Золотая середина: приватность и производительность. Страницы будут загружаться нормально. - Что блокируется стандартной защитой от отслеживания + Что блокируется обычной защитой от отслеживания Строгая @@ -1400,7 +1380,7 @@ Что блокируется строгой защитой от отслеживания - Персональная + Собственная Выберите, какие трекеры и скрипты необходимо блокировать. @@ -1413,9 +1393,9 @@ Куки с непосещённых сайтов - Все сторонние куки (может нарушить работу веб-сайтов) + Все сторонние куки (может нарушить работу сайтов) - Все куки (нарушит работу веб-сайтов) + Все куки (нарушит работу сайтов) Изолировать межсайтовые куки @@ -1435,15 +1415,15 @@ Разрешены - Трекеры социальных сетей + Трекеры соцсетей - Ограничивает возможности социальных сетей по отслеживанию вашей активности в Интернете. + Ограничивает возможности соцсетей по отслеживанию ваших действий в Интернете. Межсайтовые отслеживающие куки Межсайтовые куки - Блокирует куки, которые рекламные сети и анализирующие компании используют, чтобы объединять ваши данные сёрфинга со многих сайтов. + Блокирует куки, которые рекламные сети и анализирующие компании используют, чтобы объединять ваши данные просмотра сети со многих сайтов. Полная защита от кук изолирует действие кук сайтом, на котором вы находитесь, чтобы трекеры, такие как рекламные сети, не могли использовать их для слежки за вами на разных сайтах. @@ -1453,17 +1433,17 @@ Сборщики цифровых отпечатков - Останавливает сбор однозначно идентифицируемых данных о вашем устройстве, которые могут быть использованы в целях отслеживания. + Останавливает сбор однозначно определяемых данных о вашем устройстве, которые могут быть использованы в целях отслеживания. Отслеживающее содержимое - Блокирует загрузку внешней рекламы, видео и другого содержимого, если они содержат отслеживающий код. Может повлиять на работу некоторых веб-сайтов. + Блокирует загрузку внешней рекламы, видео и другого содержимого, если они содержат отслеживающий код. Может повлиять на работу некоторых сайтов. Защита для этого сайта включена Защита для этого сайта отключена - Улучшенная защита от отслеживания отключена для следующих веб-сайтов + Улучшенная защита от отслеживания отключена для следующих сайтов Перейти назад @@ -1476,7 +1456,7 @@ Трекеры перенаправлений - Удаляет куки, установленные в ходе перенаправлений на известные веб-сайты с отслеживанием. + Удаляет куки, установленные в ходе перенаправлений на известные отслеживающие сайты. @@ -1493,13 +1473,13 @@ Узнайте о своих правах - Информация о лицензии + Сведения о лицензии Используемые библиотеки - Кликов до включения меню отладки: %1$d + Нажатий до включения меню отладки: %1$d Меню отладки включено @@ -1509,10 +1489,10 @@ Вставить и перейти Вставить - + - URL скопирован в буфер обмена - + Ссылка скопирована в буфер обмена + Добавить на домашний экран @@ -1520,17 +1500,17 @@ Добавить - Вернуться к веб-сайту + Вернуться к сайту Название ярлыка - Вы можете легко добавить этот веб-сайт на домашний экран вашего устройства, чтобы иметь к нему мгновенный доступ и сёрфить быстрее со скоростью нативного приложения. + Вы можете легко добавить этот сайт на домашний экран вашего устройства, чтобы иметь к нему мгновенный доступ. - Логины и пароли + Пароли - Сохранение логинов и паролей + Сохранение паролей Предлагать сохранить @@ -1552,9 +1532,9 @@ Синхронизировать логины между устройствами - Сохранённые логины + Сохранённые пароли - Логины, которые вы сохраняете или синхронизируете в %s, появятся тут. + Пароли, которые вы сохраняете или синхронизируете в %s, появятся тут. Узнайте больше о синхронизации. @@ -1578,7 +1558,7 @@ Имя пользователя скопировано в буфер обмена - Копировать пароль + Скопировать пароль Очистить пароль @@ -1594,11 +1574,11 @@ Скрыть пароль - Разблокируйте, чтобы просмотреть сохранённые логины + Разблокируйте, чтобы просмотреть сохранённые пароли Защитите свои логины и пароли - Настройте графический ключ, PIN-код или пароль для блокировки устройства, чтобы защитить сохранённые логины и пароли, если кто-либо ещё получит доступ к вашему устройству. + Настройте графический ключ, Пин-код или пароль для блокировки устройства, чтобы защитить сохранённые пароли, если кто-либо ещё получит доступ к вашему устройству. Позже @@ -1644,7 +1624,7 @@ Сохранять и автоматически заполнять адреса - Включая такую информацию, как номера, адреса эл. почты и доставок + Включая такие сведения, как номера, адреса эл. почты и доставок Добавить карту @@ -1678,7 +1658,7 @@ Сохранённые карты - Пожалуйста, введите корректный номер карты + Пожалуйста, введите правильный номер карты Пожалуйста, заполните это поле @@ -1687,7 +1667,7 @@ Защитите свои банковские карты - Настройте графический ключ, PIN-код или пароль для блокировки устройства, чтобы защитить сохранённые банковские карты, если кто-либо ещё получит доступ к вашему устройству. + Настройте графический ключ, Пин-код или пароль для блокировки устройства, чтобы защитить сохранённые банковские карты, если кто-либо ещё получит доступ к вашему устройству. Настроить сейчас @@ -1765,7 +1745,7 @@ Замените строку запроса на “%s”. Пример:\nhttps://www.google.com/search?q=%s - Информация о персональной поисковой системе + Сведения о выбранной поисковой системе Введите имя поисковой системы @@ -1819,9 +1799,9 @@ Удалить - Редактировать + Править - Вы уверены, что хотите удалить этот логин? + Вы уверены, что хотите удалить этот пароль? Удалить @@ -1837,7 +1817,7 @@ Сохранить изменения в логине. - Редактирование + Правка Добавить новый логин @@ -1852,14 +1832,14 @@ Говорите - Логин с таким именем пользователя уже существует + Пароль с таким именем пользователя уже существует https://www.example.com - Веб-адрес должен содержать "https://" or "http://" + Сетевой адрес должен содержать "https://" or "http://" - Введите корректное имя сервера + Введите правильное имя сервера @@ -1885,11 +1865,11 @@ - Достигнут лимит ярлыков + Достигнут предел ярлыков - Чтобы добавить ярлык, удалите другой ярлык. Нажмите и удерживайте карточку с сайтом, а затем нажмите «Удалить». + Чтобы добавить ярлык, удалите другой ярлык. Нажмите и удерживайте значок сайта, а затем нажмите «Удалить». - OK, понятно + Понятно Ярлыки @@ -1933,7 +1913,7 @@ Автозакрытие включено - Настройте автоматическое открытие ссылок с веб-сайтов, из электронных писем и сообщений в Firefox. + Настройте автоматическое открытие ссылок с сайтов, из электронных писем и сообщений в Firefox. Убрать @@ -1955,7 +1935,9 @@ Узнайте больше - С использованием Pocket. + С использованием Pocket. + + При поддержке %s. Является частью семейства Firefox. %s @@ -1969,4 +1951,14 @@ Перейти в настройки Firefox Suggest + + + + свернуть + + развернуть + + откройте ссылку, чтобы узнать больше об этом сборнике + + прочитать статью diff --git a/app/src/main/res/values-sat/strings.xml b/app/src/main/res/values-sat/strings.xml index 1805074e2..70bab3fcd 100644 --- a/app/src/main/res/values-sat/strings.xml +++ b/app/src/main/res/values-sat/strings.xml @@ -14,6 +14,12 @@ ᱯᱨᱟᱭᱣᱮᱴ ᱵᱽᱨᱟᱣᱡᱤᱝ ᱵᱟᱝ ᱦᱩᱭ ᱦᱚᱪᱚᱜ ᱢᱮ ᱥᱮᱸᱫᱽᱨᱟ ᱟᱨ ᱵᱟᱝ ᱴᱷᱤᱠᱬᱟᱹ ᱟᱫᱮᱨ ᱢᱮ + + ᱱᱟᱜᱟᱢ ᱠᱚ ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ + + ᱵᱩᱠᱢᱟᱨᱠ ᱠᱚ ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ + + ᱴᱮᱵᱽ ᱠᱚ ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ ᱥᱮᱸᱫᱽᱨᱟ ᱚᱞ ᱠᱚ ᱟᱫᱮᱨ ᱢᱮ @@ -36,9 +42,6 @@ ᱵᱟᱪᱷᱟᱣᱮᱱᱟ - - ᱱᱤᱛᱚᱜᱼᱟᱜ ᱵᱩᱠᱢᱟᱨᱠ ᱠᱚ - ᱱᱤᱛ ᱥᱟᱺᱪᱟᱣᱟᱜ @@ -78,6 +81,12 @@ ᱵᱚᱸᱫ + + + ᱟᱞᱮᱭᱟᱜ ᱡᱷᱚᱛᱚ ᱠᱷᱚᱱ ᱫᱟᱲᱮ ᱱᱤᱥᱚᱱ ᱯᱷᱤᱪᱚᱨ ᱫᱚ ᱯᱟᱧᱡᱟ ᱵᱟᱨ ᱯᱟᱦᱴᱟ ᱫᱟᱱᱟᱲ ᱠᱚ ᱵᱟᱫ ᱠᱚᱣᱟᱭ ᱾ + + ᱢᱩᱴ ᱯᱟᱧᱡᱟ ᱨᱩᱠᱷᱤᱭᱟᱹ ᱵᱟᱵᱚᱛ ᱰᱷᱮᱨ ᱵᱟᱲᱟᱭ ᱢᱮ + ᱠᱚᱢᱨᱟ ᱵᱮᱵᱷᱟᱨ ᱫᱚᱨᱠᱟᱨ ᱾ ᱮᱸᱰᱨᱚᱭᱮᱰ ᱥᱟᱡᱟᱣ ᱛᱮ ᱪᱟᱹᱞᱟᱜ ᱢᱮ, ᱪᱷᱟᱹᱲ ᱨᱮ ᱚᱛᱟᱭ ᱢᱮ , ᱟᱨ ᱮᱞᱞᱟᱣ ᱨᱮ ᱚᱛᱟᱭ ᱢᱮ ᱾ @@ -125,13 +134,6 @@ ᱱᱤᱛᱚᱜᱟᱜ ᱴᱮᱵᱽ ᱵᱩᱛᱟᱹᱢ ᱠᱚ ᱡᱷᱚᱛᱚ ᱫᱮᱠᱷᱟᱣ ᱢᱮ - - \"%1$s\" ᱞᱟᱹᱜᱤᱜ ᱟᱢᱟᱜ ᱥᱮᱸᱫᱽᱨᱟ - - - %d ᱥᱟᱭᱤᱴ ᱠᱚ ᱤᱧᱟᱜ ᱡᱷᱚᱛᱚ ᱟᱹᱭᱩᱨ ᱢᱤᱫ ᱠᱟᱱ ᱴᱮᱵᱽ ᱠᱚ ᱫᱮᱠᱷᱟᱣ ᱢᱮ @@ -254,33 +256,35 @@ ᱥᱮᱸᱫᱽᱨᱟ ᱥᱟᱡᱟᱣ ᱠᱚ - - - %1$s ᱨᱮ ᱪᱮᱫ ᱱᱟᱶᱟ ᱢᱮᱱᱟ-ᱟ - - ᱱᱤᱛᱚᱜ ᱫᱚ ᱡᱟᱦᱟᱸ ᱨᱮ ᱢᱟᱲᱟᱝ ᱛᱟᱦᱮᱸ ᱠᱟᱱᱟᱢ ᱱᱚᱰᱮ ᱠᱷᱚᱱ ᱥᱟᱵ ᱫᱟᱲᱮᱭᱟᱜᱼᱟᱢ᱾ - - ᱱᱤᱡᱮ ᱛᱮ ᱛᱮᱭᱟᱨ %1$s ᱚᱲᱟᱜ ᱥᱟᱦᱴᱟ - - ᱠᱷᱩᱞᱟᱹ ᱠᱟᱱ ᱴᱮᱵᱽ, ᱵᱩᱠᱢᱟᱨᱠ ᱠᱚ, ᱟᱨ ᱦᱤᱛᱟᱹᱞ ᱵᱽᱨᱟᱣᱩᱡᱽ ᱛᱮ ᱪᱟᱞᱟᱜ ᱢᱮ᱾ - - ᱥᱟᱯᱷᱟ, ᱴᱮᱵᱽ ᱠᱚ ᱵᱮᱵᱚᱥᱛᱷᱟᱭ ᱢᱮ - - ᱴᱮᱵᱽ ᱵᱷᱤᱲ ᱠᱚ ᱥᱩᱫᱷᱨᱟᱹᱣ ᱠᱟᱱ ᱞᱮᱭᱟᱩᱴ ᱟᱨ ᱟᱡ ᱛᱮ ᱵᱚᱸᱫᱚᱜ ᱠᱟᱱ ᱴᱮᱵᱽ ᱠᱚ ᱢᱮᱴᱟᱣᱟᱭ᱾ - - ᱱᱤᱛᱚᱜᱟᱜ ᱥᱮᱸᱫᱽᱨᱟ ᱠᱚ - - - ᱟᱢᱟᱜ ᱚᱲᱟᱜ ᱥᱟᱦᱴᱟ ᱟᱨ ᱴᱮᱵᱽ ᱠᱷᱚᱱ ᱱᱤᱛᱚᱜᱟᱜ ᱥᱮᱸᱫᱽᱨᱟ ᱛᱮ ᱫᱩᱦᱲᱟᱹ ᱪᱟᱞᱟᱜ ᱞᱟᱹᱜᱤᱫ ᱾ - - - ᱟᱢᱟᱜ ᱢᱚᱱᱮᱛᱮᱭᱟᱜ Firefox ᱚᱲᱟᱜᱥᱟᱦᱴᱟ ᱫᱚ ᱱᱤᱛᱚᱜ ᱡᱟᱦᱟᱸ ᱨᱮ ᱟᱲᱟᱜ ᱠᱟᱜᱼᱟᱢ ᱚᱱᱰᱮ ᱜᱮ ᱤᱫᱤ ᱢᱮᱭᱟᱭ ᱾ ᱟᱢᱟᱜ ᱱᱤᱛᱚᱜᱟᱜ ᱴᱮᱵᱽ ᱠᱚ, ᱵᱩᱠᱢᱟᱨᱠ ᱠᱚ ᱟᱨ ᱥᱮᱸᱫᱽᱨᱟ ᱠᱚ ᱯᱟᱱᱛᱮ ᱛᱟᱢ ᱾ + + ᱱᱤᱭᱟᱹ ᱚᱠᱛᱚ ᱥᱮᱸᱫᱽᱨᱟ : + + + ᱱᱤᱛᱚᱜ ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ : + + + ᱟᱢᱟᱜ ᱠᱩᱥᱤ ᱚᱲᱟᱜ ᱥᱟᱦᱴᱟ ᱧᱮᱞ ᱛᱟᱢ ᱾ ᱱᱤᱛᱚᱜᱟᱜ ᱴᱮᱵᱽ ᱠᱚ, ᱵᱩᱩᱠᱢᱟᱨᱠ ᱠᱚ ᱟᱨ ᱥᱮᱱᱫᱽᱨᱟ ᱛᱮᱞᱟ ᱫᱚ ᱱᱚᱰᱮ ᱫᱮᱠᱷᱟᱣᱜᱼᱟ ᱾ + + ᱱᱤᱡᱚᱨᱟᱜ ᱞᱮᱠᱷᱟ ᱤᱱᱴᱚᱨᱱᱮᱴ ᱨᱮ ᱟᱢᱟᱜ ᱥᱟᱹᱜᱩᱱ ᱫᱟᱨᱟᱢ + + ᱰᱷᱮᱨ ᱨᱚᱝ ᱠᱚ ᱾ ᱵᱮᱥ ᱱᱤᱥᱚᱱ ᱾ ᱞᱟᱵᱷ ᱨᱮ ᱚᱱᱟ ᱥᱚᱯᱚᱛᱷ ᱜᱮ ᱡᱷᱚᱛᱚ ᱦᱚᱲ ᱾ + + ᱯᱚᱨᱫᱟ ᱵᱚᱫᱚᱞ ᱫᱚ ᱱᱤᱛᱚᱜ ᱟᱹᱰᱤ ᱤᱫᱤᱜ ᱠᱟᱱᱟ + + ᱚᱲᱟᱜ ᱥᱟᱦᱴᱟ ᱨᱮ ᱱᱤᱛᱚᱜ ᱡᱟᱦᱟᱸ ᱠᱷᱚᱱ ᱮᱢ ᱟᱲᱟᱜ ᱞᱮᱜᱼᱟ ᱮᱴᱟᱜ ᱥᱟᱫᱷᱚᱱ ᱨᱮᱭᱟᱜ ᱴᱮᱵᱽ ᱠᱷᱚᱱ ᱯᱟᱧᱡᱟ ᱫᱟᱲᱮᱭᱟᱜᱼᱟᱢ ᱾ + + ᱫᱮᱞᱟ ᱮᱛᱦᱚᱵ ᱞᱮᱜᱮ ᱵᱚᱱ ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ ᱟᱲᱟᱜ + + ᱟᱢᱟᱜ ᱴᱮᱵᱽ ᱫᱚ ᱟᱹᱭᱩᱨ ᱢᱤᱫᱚᱜ ᱠᱟᱱᱟ! ᱮᱴᱟᱜ ᱥᱟᱫᱷᱚᱱ ᱨᱮᱭᱟᱜ ᱴᱮᱵᱽ ᱠᱷᱚᱱ ᱯᱟᱧᱡᱟ ᱫᱟᱲᱮᱭᱟᱜᱼᱟᱢ ᱾ + + ᱵᱚᱸᱫᱚᱭ ᱢᱮ + ᱱᱟᱶᱟ ᱴᱮᱵᱽ %1$s ᱡᱷᱤᱡᱽ ᱢᱮ @@ -329,6 +333,14 @@ ᱱᱤᱡᱮᱨᱟᱜ ᱵᱽᱨᱟᱣᱩᱡᱤᱝ ᱠᱷᱟᱴᱚᱢᱟᱪᱷᱟ ᱥᱮᱞᱮᱫᱽ ᱢᱮ ᱠᱷᱟᱹᱞᱤᱼHTTPS ᱢᱳᱰ + + + ᱠᱩᱠᱤ ᱵᱮᱱᱚᱨ ᱠᱷᱟᱴᱚ + + ᱠᱩᱠᱤ ᱵᱮᱱᱚᱨ ᱠᱷᱟᱴᱚᱭ ᱢᱮ + + ᱠᱩᱠᱤ ᱵᱮᱱᱚᱨ ᱨᱮ Firefox ᱫᱚ ᱟᱡ ᱛᱮᱜᱮ ᱠᱩᱠᱤ ᱱᱮᱦᱚᱨ ᱠᱚ ᱵᱟᱫ ᱜᱤᱰᱤ ᱠᱟᱜᱼᱟᱭ ᱾ ᱡᱩᱫᱤ ᱵᱟᱫ ᱜᱤᱫᱤ ᱚᱯᱥᱚᱱ ᱨᱮ ᱵᱟᱹᱱᱩᱜ ᱠᱷᱟᱱ, Firefox ᱫᱚ ᱵᱮᱱᱚᱨ ᱢᱮᱴᱟᱣ ᱞᱟᱹᱜᱤᱫ ᱡᱷᱚᱛᱚ ᱠᱩᱠᱤ ᱦᱮᱥᱤᱭᱟᱹᱨ ᱩᱛᱟᱹᱨ ᱟᱭ ᱾ + ᱵᱮᱰᱷᱟᱣ ᱠᱟᱱᱟ ᱨᱩᱠᱷᱤᱭᱟᱹ ᱞᱟᱹᱜᱤᱫ ᱛᱮ HTTPS ᱫᱟᱱᱟᱝ ᱵᱮᱵᱷᱟᱨ ᱛᱮ ᱥᱟᱭᱤᱴ ᱠᱚ ᱥᱟᱞᱟᱜ ᱟᱡ ᱛᱮ ᱡᱩᱲᱟᱹᱣ ᱵᱤᱲᱟᱹᱣ ᱾ @@ -368,8 +380,6 @@ ᱠᱩᱥᱤᱭᱟᱜ ᱛᱮᱭᱟᱨ - ᱵᱩᱠᱢᱟᱨᱠ, ᱱᱟᱜᱟᱢ ᱟᱨ ᱵᱟᱹᱲᱛᱤ ᱠᱚ ᱟᱢᱟᱜ Firefox ᱠᱷᱟᱛᱟ ᱥᱟᱶᱛᱮ ᱥᱭᱝᱠ ᱢᱮ - ᱟᱢᱟᱜ ᱴᱮᱵᱽ ᱠᱚ, ᱵᱩᱠᱢᱟᱨᱠ ᱠᱚ, ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱠᱚ ᱟᱨ ᱵᱟᱹᱲᱛᱤ ᱠᱚ ᱛᱚᱞ ᱡᱚᱠᱷᱟᱭ ᱞᱟᱹᱜᱤᱫ ᱥᱩᱦᱤ ᱮᱢ ᱢᱮ ᱾ Firefox ᱠᱷᱟᱛᱟ @@ -436,8 +446,12 @@ a section where users see a list of tabs that they have visited in the past few days --> ᱱᱤᱛᱚᱜᱟᱜ ᱦᱤᱨᱤᱭᱟᱜ - ᱯᱚᱠᱮᱴ + ᱯᱚᱠᱮᱴ + + ᱢᱚᱱᱮᱼᱜᱷᱟᱱᱴᱟ ᱠᱟᱹᱦᱱᱤᱠᱚ + + %s ᱫᱟᱨᱟᱭ ᱛᱮ ᱫᱟᱲᱮ ᱮᱢ ᱠᱟᱱ ᱚᱱᱚᱞᱠᱚ ᱜᱟᱲᱚ ᱠᱟᱱ ᱠᱟᱹᱦᱱᱤ ᱠᱚ @@ -454,12 +468,29 @@ ᱧᱮᱞ - - Firefox ᱚᱲᱟᱜ ᱥᱟᱦᱴᱟ ᱞᱚᱜᱚ ᱨᱮ ᱴᱤᱯᱟᱹᱣ ᱠᱟᱛᱮ ᱞᱟᱴᱷᱟ ᱪᱤᱛᱟᱹᱨ ᱵᱚᱫᱚᱞ ᱢᱮ - - - Firefox ᱪᱤᱱᱦᱟᱹᱯ - ᱠᱟᱸᱛᱷᱥᱟᱦᱴᱟ, ᱵᱩᱛᱟᱹᱢ ᱵᱚᱫᱚᱞ ᱢᱮ + + ᱠᱟᱱᱛᱷᱪᱤᱛᱟᱹᱨ ᱰᱟᱩᱱᱞᱳᱰ ᱵᱟᱭ ᱜᱟᱱ ᱞᱮᱱᱟ + + ᱫᱩᱦᱲᱟᱹ ᱠᱩᱨᱩᱢᱩᱴᱩᱭ ᱢᱮ + + ᱠᱟᱱᱛᱷᱪᱤᱛᱟᱹᱨ ᱵᱚᱫᱚᱞ ᱵᱟᱭ ᱜᱟᱱ ᱞᱮᱱᱟ + + ᱰᱷᱮᱨ ᱥᱮᱬᱟᱭ ᱢᱮ + + + ᱠᱞᱟᱥᱤᱠ %s + + ᱥᱤᱢᱤᱛ ᱮᱰᱤᱥᱚᱱ + + ᱱᱟᱶᱟ ᱥᱟᱫᱤᱱ ᱨᱚᱲ ᱛᱩᱢᱟᱹᱞ ᱾%s + + ᱱᱟᱶᱟ ᱥᱟᱫᱤᱱ ᱨᱚᱲ ᱛᱩᱢᱟᱹᱞ ᱾ + + ᱨᱚᱝ ᱨᱮᱭᱟᱜ ᱟᱨᱮᱡ ᱧᱮᱞ ᱵᱤᱲᱟᱹᱣ ᱢᱮ + + ᱟᱢᱟᱜ ᱠᱩᱥᱤᱭᱟᱜ ᱠᱟᱱᱛᱷᱪᱤᱛᱟᱹᱨ ᱵᱟᱪᱷᱟᱣ ᱢᱮ ᱾ + + ᱰᱷᱮᱨ ᱠᱟᱱᱛᱷᱪᱤᱛᱟᱹᱨ ᱠᱚ ᱥᱮᱸᱫᱽᱨᱟᱭ ᱢᱮ @@ -542,8 +573,6 @@ Mozilla ᱥᱚᱫᱽᱷ ᱞᱚ ᱟᱹᱛᱩᱨ ᱟᱨ ᱫᱟᱹᱲ ᱪᱷᱚ ᱞᱟᱹᱤᱫᱽ ᱢᱮᱛᱟᱭ ᱢᱮ - - ᱥᱭᱝᱠ ᱪᱟᱹᱞᱩᱭ ᱢᱮ ᱥᱭᱝᱠᱢᱮ ᱟᱨ ᱟᱢᱟᱜ ᱰᱟᱴᱟ ᱥᱟᱺᱪᱟᱣ ᱛᱟᱢ @@ -605,6 +634,18 @@ ᱵᱚᱸᱫᱚᱭ ᱢᱮ + + %d ᱴᱮᱵᱽᱠᱚ ᱠᱷᱩᱞᱟᱹᱭᱟᱢ ᱥᱮ ? + + + ᱥᱟᱦᱴᱟᱠᱚ ᱞᱟᱫᱮ ᱡᱷᱚᱛᱜ ᱟᱹᱰᱤᱜᱟᱱ ᱴᱮᱵᱽ ᱠᱚ ᱠᱷᱩᱞᱟᱹ ᱞᱮᱠᱷᱟᱱ %s ᱵᱟᱹᱭᱚᱜᱼᱟ ᱾ ᱟᱡ ᱥᱟᱹᱨᱤᱛᱮ ᱞᱟᱦᱟ ᱥᱮᱱᱟᱢ ᱠᱟᱱᱟ ᱥᱮ ? + + ᱴᱮᱵᱽ ᱠᱚ ᱡᱷᱤᱡᱽ ᱢᱮ + + ᱵᱟᱹᱰᱨᱟᱹ + %d ᱥᱟᱭᱤᱴ @@ -635,10 +676,6 @@ ᱞᱤᱥᱴᱤ ᱡᱟᱸᱜᱞᱟ - - ᱥᱮᱸᱫᱽᱨᱟ ᱫᱳᱞ ᱠᱚ - - ᱡᱩᱲᱟᱹᱣ ᱠᱟᱱ ᱥᱟᱭᱤᱴ ᱠᱚ ᱫᱳᱞ ᱠᱟᱜ ᱢᱮ ᱴᱮᱵᱽ ᱠᱚ ᱵᱚᱸᱫᱚᱭ ᱢᱮ @@ -763,9 +800,6 @@ %1$s (ᱯᱨᱭᱣᱮᱴ ᱢᱳᱰ) - - ᱵᱷᱮᱜᱟᱨ ᱴᱮᱵᱽ ᱠᱚ - ᱥᱮᱸᱫᱽᱨᱟ ᱚᱞ ᱠᱚ ᱟᱫᱮᱨ ᱢᱮ @@ -793,19 +827,6 @@ ᱱᱚᱰᱮ ᱱᱟᱜᱟᱢ ᱵᱚᱱᱩᱜ-ᱟ - - ᱮᱴᱟᱜ ᱥᱟᱫᱷᱚᱱ ᱠᱷᱚᱱ ᱟᱹᱭᱩᱨ ᱢᱤᱫ ᱠᱟᱱᱟ - - ᱮᱴᱟᱜ ᱥᱟᱫᱷᱚᱱ ᱠᱷᱚᱱ - - - ᱮᱴᱟᱜ ᱥᱟᱫᱷᱚᱱ ᱠᱷᱚᱱ ᱦᱤᱛᱟᱹᱞ ᱧᱮᱞ ᱞᱟᱹᱜᱤᱫ ᱥᱩᱦᱤ ᱮᱢ ᱢᱮ ᱾ - - ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ - - - ᱟᱨᱵᱟᱝᱠᱷᱟᱱ ᱟᱹᱭᱩᱨ ᱢᱤᱫ ᱞᱟᱹᱜᱤᱫ ᱢᱤᱫᱴᱟᱹᱝ Firefox ᱠᱷᱟᱛᱟ ᱛᱮᱭᱟᱨ ᱢᱮ]]> - ᱰᱟᱩᱱᱞᱚᱰᱠᱚ ᱚᱪᱚᱜᱮᱱᱟ @@ -856,6 +877,10 @@ ᱱᱟᱶᱟ ᱴᱮᱵᱽ ᱨᱮ ᱡᱷᱤᱡᱽ ᱢᱮ ᱱᱤᱡᱮᱨᱟᱜ ᱴᱮᱵᱽ ᱨᱮ ᱡᱷᱤᱡᱽ ᱢᱮ + + ᱱᱟᱶᱟ ᱴᱮᱵᱽ ᱨᱮ ᱡᱷᱚᱛᱚ ᱡᱷᱤᱡᱽ ᱢᱮ + + ᱱᱤᱡᱮᱨᱟᱜ ᱴᱮᱵ ᱨᱮ ᱡᱷᱚᱛᱚ ᱡᱷᱤᱡᱽ ᱢᱮ ᱢᱮᱴᱟᱣ ᱢᱮ @@ -1033,6 +1058,10 @@ "Share" button. Opens the share menu when pressed. --> ᱦᱟᱹᱴᱤᱧ ᱢᱮ + + PDF ᱞᱮᱠᱷᱟ ᱥᱟᱺᱪᱟᱣ ᱢᱮ + + PDF ᱛᱮᱭᱟᱨ ᱵᱟᱭ ᱜᱟᱱ ᱞᱮᱱᱟ ᱥᱟᱫᱷᱚᱱ ᱨᱮ ᱠᱩᱞ ᱢᱮ @@ -1044,9 +1073,11 @@ ᱨᱮᱴᱚᱯ ᱵᱳᱨᱰ ᱨᱮ ᱱᱚᱠᱚᱞᱮᱱᱟ - ᱥᱭᱝᱠ ᱞᱟᱹᱜᱤᱫ ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ ᱢᱮ + ᱥᱭᱝᱠ ᱞᱟᱹᱜᱤᱫ ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ ᱢᱮ ᱥᱭᱝᱠ ᱞᱟᱹᱜᱤᱫ ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ ᱢᱮ + + ᱥᱭᱝᱠ ᱟᱨ ᱰᱟᱴᱟ ᱥᱟᱺᱪᱟᱣ ᱡᱚᱛᱚ ᱥᱟᱫᱷᱚᱱ ᱛᱮ ᱵᱷᱮᱡᱟᱭᱢᱮ @@ -1084,6 +1115,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s ᱫᱚ ᱟᱢᱟᱜ ᱢᱩᱞ ᱯᱷᱮᱲᱟᱛ ᱵᱽᱨᱟᱩᱡᱚᱨ ᱥᱮᱴ ᱢᱮ + + ᱱᱤᱡᱚᱨᱟᱜ ᱵᱽᱨᱟᱣᱡᱤᱝ ᱠᱩᱨᱩᱢᱩᱴᱩ ᱞᱮᱢ + + + %1$s ᱨᱮ ᱵᱟᱝ ᱥᱟᱧᱪᱟᱣ ᱠᱟᱱ ᱠᱩᱠᱤ ᱟᱨᱵᱟᱝ ᱦᱤᱛᱟᱹᱞ ᱠᱚ ᱵᱽᱨᱟᱣᱩᱡᱽ ᱢᱮ + ᱛᱩᱢᱟᱹᱞ ᱢᱮᱴᱟᱣᱮᱱᱟ @@ -1174,8 +1212,6 @@ ᱟᱲᱟᱹᱜ ᱢᱮ - - ᱱᱚᱶᱟ ᱫᱚ ᱟᱢᱟᱜ ᱥᱟᱱᱟᱢ ᱵᱽᱨᱟᱣᱩᱡᱤᱝ ᱰᱟᱴᱟ ᱢᱮᱴᱟᱣ ᱛᱟᱢᱟᱭ ᱾ ᱢᱮᱴᱟᱣ ᱞᱟᱹᱜᱤᱫ ᱚᱠᱛᱚ ᱨᱮᱭᱟᱜ ᱨᱮᱧᱡᱽ @@ -1208,21 +1244,22 @@ ᱫᱳᱞ ᱢᱮᱴᱟᱣ ᱦᱩᱭ - - %s ᱨᱮ ᱥᱟᱹᱜᱩᱱ ᱫᱟᱨᱟᱢ! - - ᱥᱟᱫᱷᱚᱱ ᱵᱷᱤᱛᱨᱤ ᱨᱮ Firefox ᱥᱭᱝᱠ ᱢᱮ - - %1$s ᱨᱮ ᱵᱩᱠᱢᱟᱨᱠᱥ, ᱦᱤᱛᱟᱹᱞ, ᱟᱨ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫᱽ ᱨᱮ ᱟᱹᱜᱩ ᱪᱷᱚᱭ ᱢᱮ ᱾ - - ᱥᱩᱦᱤ ᱮᱡ ᱪᱷᱚ + + ᱢᱤᱫᱴᱟᱹᱝ ᱵᱮᱥ ᱤᱱᱴᱚᱨᱱᱮᱴ ᱨᱮ ᱟᱢᱟᱜ ᱥᱟᱹᱜᱩᱱ ᱫᱟᱨᱟᱢ + + ᱦᱚᱲ ᱠᱚ ᱞᱟᱹᱜᱤᱫ, ᱵᱤᱱ ᱞᱟᱵᱷ ᱨᱮᱭᱟᱜ ᱢᱤᱫᱴᱟᱹᱝ ᱵᱽᱨᱟᱣᱡᱚᱨ ᱾ + + ᱪᱟᱞᱟᱜ ᱢᱮ ᱡᱟᱦᱟᱸ ᱨᱮ ᱢᱟᱲᱟᱝ ᱛᱟᱦᱮᱸ ᱠᱟᱱᱟᱢ + + ᱟᱨᱟᱢ ᱛᱮ ᱯᱚᱨᱫᱟ ᱠᱚ ᱩᱪᱟᱹᱲ ᱞᱟᱹᱜᱤᱫ ᱥᱟᱫᱷᱚᱱ ᱥᱟᱨᱟ ᱨᱮ ᱴᱮᱵᱽ ᱟᱨ ᱫᱟᱱᱟᱝ ᱥᱟᱵᱟᱫ ᱠᱚᱨᱮ ᱟᱹᱭᱩᱨ ᱢᱤᱫ ᱢᱮ ᱾ + + ᱵᱚᱞᱚᱱ ᱥᱩᱦᱤ ᱥᱭᱝᱠ ᱪᱟᱹᱞᱩ ᱢᱮᱱᱟᱜ-ᱟ - - ᱯᱨᱟᱭᱣᱮᱥᱭ ᱡᱷᱚᱛᱚ ᱵᱮᱲᱟ ᱮᱢ ᱪᱷᱚᱭ ᱢᱮ - - %1$s ᱫᱚ ᱵᱟᱦᱨᱮ ᱠᱚᱢᱯᱟᱱᱤ ᱠᱚ ᱣᱮᱵᱽ ᱨᱮ ᱟᱢ ᱯᱟᱸᱡᱟ ᱠᱚ ᱵᱚᱸᱫᱚᱜᱼᱟ ᱾ + + ᱢᱩᱞ ᱞᱮᱠᱷᱟᱛᱮ ᱱᱤᱥᱚᱱ ᱨᱩᱠᱷᱤᱭᱟᱹᱭ ᱢᱮ + + ᱡᱷᱚᱛᱚ ᱥᱟᱭᱤᱴ ᱠᱚᱨᱮ ᱠᱩᱠᱤ ᱯᱟᱧᱡᱟ ᱫᱟᱱᱟᱲ ᱠᱚ ᱵᱟᱹᱲ ᱪᱷᱚ ᱞᱟᱹᱜᱤᱫ ᱢᱩᱴ ᱠᱩᱠᱤ ᱨᱩᱠᱷᱤᱭᱟᱹ ᱫᱮᱠᱷᱟᱣᱜ ᱠᱟᱱᱟ ᱾ ᱵᱮᱥᱟᱜ (ᱢᱩᱞ ᱯᱷᱮᱲᱟᱛ) @@ -1233,17 +1270,18 @@ ᱥᱟᱦᱴᱟ ᱞᱚᱜᱚᱱ ᱞᱳᱰ ᱞᱟᱹᱜᱤᱫ ᱯᱟᱧᱡᱟ ᱫᱟᱱᱟᱲ ᱠᱚ ᱵᱞᱚᱠ ᱠᱚᱟᱭ, ᱦᱮᱞᱮ ᱥᱟᱦᱴᱟ ᱞᱳᱰ ᱨᱮ ᱰᱤᱜᱟᱹᱣ ᱦᱩᱭ ᱫᱟᱲᱮᱭᱟᱜᱼᱟ ᱾ ᱟᱢᱟᱜ ᱴᱩᱞᱵᱟᱨ ᱯᱞᱮᱥᱢᱮᱱᱴ ᱨᱟᱠᱟᱵᱽ ᱛᱟᱢ - - ᱴᱩᱞᱵᱟᱨ ᱫᱚ ᱥᱮᱴᱮᱨᱚᱜ ᱴᱷᱮᱱ ᱫᱚᱦᱚᱭ ᱢᱮ ᱾ ᱞᱟᱛᱟᱨ ᱨᱮ ᱫᱚᱦᱚᱭ ᱢᱮ, ᱟᱨ ᱵᱟᱝ ᱪᱮᱛᱟᱱ ᱥᱮᱫ ᱩᱪᱟᱹᱲ ᱢᱮ ᱾ - - - ᱟᱢᱟᱜ ᱱᱤᱥᱚᱱ - - ᱟᱞᱮ %s ᱞᱮ ᱰᱤᱡᱟᱭᱤᱱ ᱟᱠᱟᱫᱼᱟ ᱚᱠᱟ ᱫᱚ ᱡᱟᱦᱟᱱᱟᱜ ᱠᱚ ᱚᱱᱞᱟᱭᱤᱱ ᱦᱟᱹᱴᱤᱧ ᱨᱮ ᱟᱨ ᱚᱠᱟ ᱠᱚ ᱟᱞᱮ ᱦᱟᱹᱤᱧ ᱟᱞᱮᱭᱟᱢ, ᱜᱚᱲᱚ ᱮᱢᱟᱭ ᱾ + + + ᱞᱟᱛᱟᱨ ᱨᱮ ᱫᱚᱦᱚᱭ ᱢᱮ, ᱵᱟᱝᱠᱷᱟᱱ ᱪᱮᱛᱟᱱ ᱥᱮᱫ ᱩᱪᱟᱹᱲ ᱢᱮ ᱾ + + ᱟᱢᱟᱜ ᱰᱟᱴᱟ ᱟᱢᱟᱜ ᱠᱚᱵᱚᱡᱽ ᱨᱮ ᱛᱟᱦᱮᱱ ᱟ + + Firefox ᱴᱷᱮᱱ ᱡᱟᱦᱱᱟᱜ ᱜᱮ ᱟᱢ ᱚᱱᱞᱟᱭᱤᱱ ᱦᱟᱹᱴᱤᱧ ᱮᱫᱟᱢ ᱟᱨ ᱟᱢ ᱟᱞᱮ ᱥᱟᱶ ᱪᱮᱫ ᱮᱢ ᱦᱟᱹᱴᱤᱧ ᱮᱫᱟᱢ ᱚᱱᱟ ᱨᱮᱭᱟᱜ ᱠᱚᱵᱚᱡᱽ ᱮᱢᱟᱢ ᱠᱟᱱᱟᱭ ᱾ ᱟᱞᱮᱭᱟᱜ ᱱᱤᱥᱚᱱ ᱱᱚᱴᱤᱥ ᱯᱟᱲᱦᱟᱣ ᱯᱮ + + ᱟᱹᱰᱤ ᱱᱟᱯᱟᱭ ᱤᱱᱴᱚᱨᱱᱮᱴ ᱠᱷᱩᱞᱟᱹ ᱞᱟᱹᱜᱤᱫ ᱥᱚᱡᱽ ᱜᱮᱭᱟᱢ ᱥᱮ ? ᱵᱽᱨᱟᱣᱩᱡᱤᱝ ᱮᱦᱚᱵᱽ ᱢᱮ @@ -1330,6 +1368,8 @@ ᱡᱷᱚᱛᱚ ᱯᱮᱼᱯᱟᱨᱴᱭ ᱠᱩᱩᱠᱤ ᱠᱚ (ᱱᱚᱶᱟ ᱫᱚ ᱣᱮᱵᱥᱟᱭᱤᱴ ᱠᱚ ᱨᱟᱹᱯᱩᱫ ᱫᱟᱲᱮᱭᱟᱜᱼᱟᱭ) ᱠᱷᱚᱛᱚ ᱠᱩᱩᱠᱤ ᱠᱚ (ᱱᱚᱶᱟ ᱫᱚ ᱣᱮᱵᱥᱟᱭᱤᱴ ᱠᱚ ᱨᱟᱹᱯᱩᱫᱟᱭ) + + ᱡᱷᱚᱛᱚ ᱥᱟᱭᱤᱴ ᱠᱩᱠᱤᱡᱽ ᱠᱚ ᱛᱷᱚᱞᱚᱜᱽ ᱠᱟᱜ ᱢᱮ ᱯᱟᱧᱡᱟ ᱫᱟᱱᱟᱲ ᱡᱤᱱᱤᱥ @@ -1356,6 +1396,8 @@ ᱥᱟᱭᱤᱨᱼᱵᱟᱨᱯᱟᱦᱴᱟ ᱠᱩᱠᱤᱡᱽ ᱠᱚ ᱮᱰ ᱱᱮᱴᱣᱳᱨᱠ ᱠᱚ ᱟᱨ ᱮᱱᱟᱞᱭᱴᱤᱠ ᱠᱚᱢᱯᱟᱱᱤ ᱠᱚ ᱮᱢᱟᱱ ᱠᱩᱻᱠᱤᱡ ᱠᱚ, ᱚᱠᱟ ᱫᱚ ᱟᱭᱢᱟ ᱵᱽᱨᱟᱣᱩᱡᱤᱝ ᱰᱟᱴᱟ ᱠᱚ ᱠᱚᱢᱯᱟᱭᱤᱞ ᱞᱟᱹᱜᱤᱫᱽ ᱵᱮᱵᱷᱟᱨᱚᱜᱼᱟ ᱚᱱᱟ ᱠᱚ ᱵᱞᱚᱠ ᱟᱭ ᱾ + + ᱢᱩᱴ ᱠᱩᱠᱤ ᱨᱩᱠᱷᱤᱭᱟᱹ ᱫᱚ ᱡᱟᱦᱟᱸ ᱥᱟᱭᱤᱴ ᱨᱮ ᱢᱮᱱᱟᱢᱟᱸ ᱚᱱᱰᱮ ᱠᱩᱠᱤ ᱛᱷᱚᱞᱚᱜᱽ ᱠᱚᱣᱟᱭ ᱢᱮᱱᱠᱷᱟᱱ ᱯᱟᱧᱡᱟᱤᱭᱟᱹ ᱡᱮᱞᱠᱟ ᱰᱷᱟᱶᱨᱟ ᱡᱟᱹᱞᱤ ᱠᱚ ᱫᱚ ᱟᱢ ᱵᱟᱠᱚ ᱯᱟᱧᱡᱟ ᱫᱟᱲᱮ ᱢᱮᱭᱟ ᱠᱚ ᱾ ᱠᱨᱭᱯᱴᱚᱢᱟᱭᱱᱟᱹᱨ ᱠᱚ @@ -1869,7 +1911,9 @@ ᱟᱨᱦᱚᱸ ᱯᱟᱱᱛᱮ ᱧᱟᱢ ᱢᱮ - ᱜᱚᱲᱚᱤᱭᱟᱹ Pocket + ᱜᱚᱲᱚᱤᱭᱟᱹ Pocket + + %1$s ᱫᱟᱨᱟᱭ ᱛᱮ ᱫᱟᱲᱮ ᱮᱢ ᱾ Firefox ᱜᱷᱟᱨᱚᱧᱡᱽ ᱨᱤᱱᱤᱡ ᱦᱟᱹᱴᱤᱧ ᱾ %s @@ -1883,4 +1927,14 @@ ᱥᱟᱡᱟᱣ ᱴᱷᱮᱱ ᱪᱟᱞᱟᱜ ᱢᱮ Firefox ᱵᱟᱛᱟᱣ + + + + ᱜᱷᱟᱥᱟᱣ + + ᱚᱥᱟᱨ + + ᱱᱚᱶᱟ ᱡᱟᱣᱨᱟ ᱵᱮᱵᱚᱫ ᱰᱷᱮᱨ ᱵᱟᱰᱟᱭ ᱞᱟᱹᱜᱤᱫ ᱞᱤᱝᱠ ᱠᱷᱩᱞᱟᱹᱭ ᱢᱮ + + ᱚᱱᱚᱞ ᱯᱟᱲᱦᱟᱣ ᱢᱮ diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index c4ebcf3b9..d68f1c6ca 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -15,6 +15,12 @@ පෞද්. පිරික්සීම අබල කරන්න සොයන්න හෝ ලිපිනය යොදන්න + + ඉතිහාසය සොයන්න + + පොත්යොමු සොයන්න + + පටිති සොයන්න සෙවුම් පද යොදන්න @@ -126,12 +132,6 @@ සියල්ල පෙන්වන්න සියළු මෑත පටිති බොත්තම පෙන්වන්න - - \"%1$s\" සඳහා ඔබගේ සෙවුම - - අඩවි %d සියළු සමමුහූර්ත පටිති බලන්න @@ -248,6 +248,9 @@ සෙවුම් සැකසුම් + + මෙවර සෙවීම: + %1$s හි අළුත් දෑ @@ -270,11 +273,15 @@ ඔබගේ පුද්ගලීකකරණය කළ මුල් පිටුව බලන්න. මෑත පටිති, පොත්යොමු හා සෙවුම් ප්‍රතිඵල මෙහි දිස් වනු ඇත. - ස්වාධීන අන්තර්ජාලයකට පිළිගනිමු + ස්වාධීන අන්තර්ජාලයකට පිළිගනිමු + + වඩාත් පෞද්ගලික අන්තර්ජාලයකට පිළිගනිමු බොහෝ වර්ණ. ඉහළ පෞද්ගලිකත්‍වය. එලෙසම ලාභයට වඩා මිනිසුන්ට කැපවීම. - දුරකථනයෙන් පරිගණකයට සහ ආපසු + දුරකථනයෙන් පරිගණකයට සහ ආපසු + + තිර අතර මාරු වීම වෙනදාට වඩා පහසුය දැන් මුල් පිටුවේ තිබෙන අන් උපාංගවල පටිති සමඟ ඔබ නතර කළ තැනින් අතට ගන්න. @@ -289,6 +296,9 @@ පටිති සමමුහූර්ත වෙමින්! අනෙක් උපාංගයේ ඔබ නතර කළ තැනින් අතට ගන්න. + + වසන්න + නව %1$s පටිත්තක් අරින්න @@ -378,8 +388,6 @@ රිසිකරණය - ෆයර්ෆොක්ස් ගිණුමක් සමඟ පොත්යොමු, ඉතිහාසය හා තවත් දෑ සමමුහූර්ත කරන්න - පටිති, පොත්යොමු, මුරපද හා තවත් දෑ සමමුහූර්තයට පිවිසෙන්න. ෆයර්ෆොක්ස් ගිණුම @@ -445,6 +453,12 @@ මෑතදී ගොඩවැදුණු + + පොකට් + + සිතුවිලි අවුස්සන කතා + + %s මගින් ලිපි බලගැන්වේ අනුග්‍රහය ලද කතා @@ -461,11 +475,29 @@ බලන්න - - ෆයර්ෆොක්ස් මුල්පිටුවේ ලාංඡනය එබීමෙන් බිතුපත වෙනස් කරන්න - - ෆයර්ෆොක්ස් ලාංඡනය - බිතුපත සංශෝධනය, බොත්තම + + බිතුපත බාගැනීමට නොහැකි විය + + යළි උත්සාහය + + බිතුපත වෙනස් කළ නොහැකි විය + + තව දැනගන්න + + + පරණ %s + + සීමිතයි + + නව ස්වාධීන හඬ එකතුව. %s + + නව ස්වාධීන හඬ එකතුව. + + වර්ණ කැලතීමක් බලන්න + + ඔබට කතා කරන බිතුපතක් තෝරන්න. + + තවත් බිතුපත් ගවේශනය @@ -546,8 +578,6 @@ මොස්ල්ලා සඳහා අධ්‍යන ස්ථාපනයට හා ධාවනයට ඉඩ දෙන්න - - සමමුහූර්තය සක්‍රිය කරන්න සමමුහූර්ත කර සුරකින්න @@ -609,6 +639,17 @@ වසන්න + + පටිති %d ක් අරින්නද? + + පටිති බොහොමයක් විවෘත කිරීමෙන් පිටු පූරණය අතරතුර %s මන්දගාමී වීමට හැකිය. ඉදිරියට යාමට වුවමනා ද? + + පටිති අරින්න + + අවලංගු + අඩවි %d @@ -643,10 +684,6 @@ ලේඛනය ජාලකය - - සෙවුම් සමූහ - - ආශ්‍රිත අඩවි සමූහගත කරන්න පටිති වසන්න @@ -768,8 +805,6 @@ ඉතිහාසයෙන් මකන්න %1$s (පෞද්ගලික ප්‍රකාරය) - - වෙනත් පටිති @@ -797,17 +832,6 @@ පරණ මෙහි ඉතිහාසයක් නැත - - වෙනත් උපාංග වලින් සමමුහූර්තයි - - වෙනත් උපාංග වෙතින් - - අන් උපාංග වලින් සමමුහූර්ත වූ ඉතිහාසය බැලීමට පිවිසෙන්න. - - පිවිසෙන්න - - - හෝ සමමුහූර්තය ඇරඹීමට ෆයර්ෆොක්ස් ගිණුමක් සාදන්න]]> @@ -856,6 +880,10 @@ නව පටිත්තක අරින්න පෞද්. පටිත්තක අරින්න + + සියල්ල නව පටිතිවල අරින්න + + සියල්ල පෞද්. පටිතිවල අරින්න මකන්න @@ -1028,6 +1056,10 @@ බෙදාගන්න + + පීඩීඑෆ් ලෙස සුරකින්න + + පීඩීඑෆ් උත්පාදනය කිරීමට නොහැකිය උපාංගයට යවන්න @@ -1039,9 +1071,11 @@ පසුරු පුවරුවට පිටපත් විය - සමමුහූර්තයට පිවිසෙන්න + සමමුහූර්තයට පිවිසෙන්න සමමුහූර්තයට පිවිසෙන්න + + සමමුහූර්ත කර සුරකින්න සියළු උපාංග වෙත යවන්න @@ -1169,8 +1203,6 @@ ඉවත් වන්න - - මෙය ඔබගේ පිරික්සුම් දත්ත සියල්ල මකනු ඇත. මකා දමන කාල පරාසය @@ -1207,19 +1239,33 @@ - %s වෙත පිළිගනිමු! + %s වෙත පිළිගනිමු! + + නව්‍ය අන්තර්ජාලයකට පිළිගනිමු + + ලාභයට නොව මිනිසුන්ට තැනූ අතිරික්සුවකි. - උපාංග අතර ෆයර්ෆොක්ස් සමමුහූර්තය + උපාංග අතර ෆයර්ෆොක්ස් සමමුහූර්තය + + ඔබ නතර කළ තැනින් අරඹන්න - මෙම උපාංගයේ %1$s වෙත පොත්යොමු, ඉතිහාසය සහ මුරපද ගෙනෙන්න. + මෙම උපාංගයේ %1$s වෙත පොත්යොමු, ඉතිහාසය සහ මුරපද ගෙනෙන්න. + + බාධාවකින් තොරව තිර අතර මාරු වීමට උපාංගවල පටිති හා මුරපද සමමුහූර්ත කරන්න. - ලියාපදිංචිය + ලියාපදිංචිය + + පිවිසෙන්න සමමුහූර්තය සක්‍රියයි - සැමවිට සක්‍රිය පෞද්ගලිකත්‍වය + සැමවිට සක්‍රිය පෞද්ගලිකත්‍වය + + පෙරනිමි පෞද්ගලිකත්‍ව රැකවරණය - %1$s මගින් අන්තර්ජාලය පුරා ඔබව රහසිගතව ලුහුබඳින සමාගම් ස්වයංක්‍රීයව නවත්වයි. + %1$s මගින් අන්තර්ජාලය පුරා ඔබව රහසිගතව ලුහුබඳින සමාගම් ස්වයංක්‍රීයව නවත්වයි. + + පූර්ණ දත්තකඩ රැකවරණය මගින් වියමන පුරා දත්තකඩ භාවිතයෙන් ඔබ පසුපස හඹා එන ලුහුබඳින්නන් නවත්වයි. සම්මත (පෙරනිමි) @@ -1232,16 +1278,24 @@ මෙවලම් තීරුව ස්ථානගත කරන්න - මෙවලම් තීරුව පහසුවෙන් ළඟා වීමට හැකි තැනක තබන්න. එය පතුලේ තබා ගන්න, හෝ ඉහළට ගෙන යන්න. + මෙවලම් තීරුව පහසුවෙන් ළඟා වීමට හැකි තැනක තබන්න. එය පතුලේ තබා ගන්න, හෝ ඉහළට ගෙන යන්න. + + එය පතුලේ තබා ගන්න, හෝ මුදුනට ගෙන යන්න. - ඔබ‍‍ගේ පෞද්ගලිකත්‍වය + ඔබ‍‍ගේ පෞද්ගලිකත්‍වය + + ඔබ ඔබගේ දත්ත පාලනය කරයි - ඔබ මාර්ගගතව බෙදා ගන්නා දෑ සහ ඔබ අප සමඟ බෙදා ගන්නා දෑ පහසුවෙන් පාලනය කිරීමට %s නිර්මාණය කර ඇත. + ඔබ මාර්ගගතව බෙදා ගන්නා දෑ සහ ඔබ අප සමඟ බෙදා ගන්නා දෑ පහසුවෙන් පාලනය කිරීමට %s නිර්මාණය කර ඇත. + + ඔබ මාර්ගගතව බෙදා ගන්නා දෑ සහ ඔබ අප සමඟ බෙදා ගන්නා දෑ පහසුවෙන් පාලනය කිරීමට ෆයර්ෆොක්ස් ඉඩ සලසයි. අපගේ රහස්‍යතා දැන්වීම කියවන්න + + විස්මජනක අන්තර්ජාලයක් දැකීමට සූදානම්ද? පිරික්සුම අරඹන්න @@ -1274,7 +1328,7 @@ පරිලෝකනයට සූදානම් - කැමරාව සමඟ පිවිසෙන්න + රූගතය සමඟ පිවිසෙන්න වි-තැපෑල යොදාගන්න @@ -1356,7 +1410,7 @@ බොහෝ අඩවි පුරාවට ඔබගේ පිරික්සුම් දත්ත සම්පාදනය කිරීමට දැන්වීම් ජාල සහ විශ්ලේෂණ සමාගම් භාවිතා කරන දත්තකඩ අවහිර කරයි. - පූර්ණ දත්තකඩ ආරක්‍ෂණය ඔබ සිටින අඩවියට දත්තකඩ හුදකලා කරයි, එබැවින් දැන්වීම් ජාල වැනි ලුහුබැඳීම් සඳහා සියළු අඩවි පුරා ඔබට හඹායාමට ඒවා භාවිතා කිරීමට නොහැකිය. + පූර්ණ දත්තකඩ රැකවරණය ඔබ සිටින අඩවියට දත්තකඩ හුදකලා කරයි, එබැවින් දැන්වීම් ජාල වැනි ලුහුබැඳීම් සඳහා සියළු අඩවි පුරා ඔබට හඹායාමට ඒවා භාවිතා කිරීමට නොහැකිය. අනිෂ්ට අත්පත් සංඛ්‍යාංක මුදල් කැණීම සඳහා ඔබගේ උපාංගයට ප්‍රවේශ වීම වළක්වයි. @@ -1850,6 +1904,10 @@ මාතෘකාව අනුව කතා තව සොයා ගන්න + + පොකට් මගින් බලගැන්වේ. + + %s මගින් බලගැන්වේ. ෆයර්ෆොක්ස් පවුලේ කොටසකි. %s @@ -1859,4 +1917,14 @@ සැකසුම් වෙත යන්න - + + + + හැකිළීම + + විහිදුවීම + + මෙම එකතුව ගැන තව දැන ගැනීමට සබැඳිය අරින්න + + ලිපිය කියවන්න + diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 796ed45e5..b5e7bdd1a 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -15,6 +15,12 @@ Zakázať súkromné prehliadanie Hľadať + + Hľadať v histórii + + Hľadať v záložkách + + Hľadať v kartách Zadajte hľadaný výraz @@ -40,8 +46,6 @@ - Nedávno pridané medzi záložky - Nedávno uložené Zobraziť všetky uložené záložky @@ -130,13 +134,6 @@ Tlačidlo Zobraziť všetky nedávne karty - - Vaše hľadanie výrazu \"%1$s\" - - - Stránky: %d Zobraziť všetky synchronizované karty @@ -261,39 +258,21 @@ Hľadať v nastaveniach - - - Novinky v aplikácii %1$s - - Teraz je jednoduchšie pokračovať tam, kde ste prestali. - - Prispôsobená domovská stránka %1$su - - Prejdite na otvorené karty, záložky a históriu prehliadania. - - Čisté a usporiadané karty - - Odstráňte neporiadok zo záložiek vďaka vylepšenému rozloženiu a automatickému zatváraniu kariet. - - Nedávne vyhľadávania - - Zopakujte svoje najnovšie vyhľadávania z domovskej stránky a kariet. - - - Vaša prispôsobená domovská stránka Firefoxu teraz uľahčuje pokračovať tam, kde ste prestali. Nájdite svoje najnovšie karty, záložky a výsledky vyhľadávania. + + Tentokrát hľadať: + + Tentokrát hľadať v: + + Zoznámte sa so svojou prispôsobenou domovskou stránkou. Tu sa zobrazia nedávne karty, záložky a výsledky vyhľadávania. - - Vitajte na nezávislom internete Vitajte na osobnejšom internete Viac farieb. Lepšie súkromie. Rovnaký záväzok voči ľuďom nadradený ziskom. - Preskočte z telefónu na laptop a späť - Prepínanie obrazoviek je jednoduchšie ako kedykoľvek predtým Pokračujte tam, kde ste prestali, pomocou kariet z iných zariadení teraz na vašej domovskej stránke. @@ -307,6 +286,9 @@ Vaše karty sa synchronizujú! Na druhom zariadení pokračujte tam, kde ste tu prestali. + + Zavrieť + Otvoriť novú kartu %1$su @@ -358,6 +340,14 @@ Pridať odkaz na súkromné prehliadanie Režim "Len HTTPS" + + + Zníženie počtu bannerov súborov cookie + + Znižovať počet bannerov súborov cookie + + Firefox sa automaticky pokúša odmietnuť žiadosti o uloženie súborov cookie na informačných banneroch súborov cookie. Ak možnosť odmietnutia nie je k dispozícii, Firefox môže akceptovať všetky súbory cookie, aby oznámenie zavrel. + Automaticky sa pokúša pripojiť k stránkam pomocou šifrovacieho protokolu HTTPS na zvýšenie bezpečnosti. @@ -467,8 +457,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nedávno navštívené - Pocket + Pocket + + Príbehy na zamyslenie + + Články zo služby %s Sponzorované príbehy @@ -491,12 +485,6 @@ Tapetu sa nepodarilo zmeniť Ďalšie informácie - - Tapetu domovskej stránky zmeniť ťuknutím na logo Firefoxu - - - Logo Firefoxu - zmena tapety, tlačidlo Klasický %s @@ -655,6 +643,17 @@ Zavrieť + + Otvoriť %d kariet? + + Otvorenie tohto množstva kariet môže spomaliť %s počas ich načítavania. Naozaj chcete pokračovať? + + Otvoriť karty + + Zrušiť + %d stránka @@ -684,10 +683,6 @@ Zoznam Mriežka - - Hľadať v skupinách - - Zoskupovať súvisiace stránky Zavrieť karty @@ -839,18 +834,6 @@ Nemáte žiadnu históriu prehliadania - - Synchronizované z iných zariadení - - Z iných zariadení - - - Ak chcete zobraziť históriu synchronizovanú z vašich ostatných zariadení, prihláste sa. - - Prihlásiť sa - - Alebo si vytvorte účet Firefox a spustite synchronizáciu]]> - Stiahnuté súbory boli odstránené @@ -900,6 +883,10 @@ Otvoriť na novej karte Otvoriť na súkromnej karte + + Otvoriť všetky na nových kartách + + Otvoriť všetky na súkromných kartách Odstrániť @@ -1078,6 +1065,10 @@ Zdieľať + + Uložiť ako PDF + + Nedá sa vygenerovať PDF Odoslať do zariadenia @@ -1089,9 +1080,11 @@ Skopírované do schránky - Prihlásiť sa a synchronizovať + Prihlásiť sa a synchronizovať Prihlásiť sa k službe Sync + + Synchronizovať a uložiť údaje Odoslať do všetkých zariadení @@ -1129,6 +1122,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Nastaviť %1$s ako predvolený prehliadač + + Vyskúšajte súkromné prehliadanie + + Prehliadajte bez uložených súborov cookie alebo histórie v prehliadači %1$s + Kolekcia bola odstránená @@ -1251,33 +1250,20 @@ Skupina bola odstránená - - Víta vás %s! Vitajte na lepšom internete Prehliadač vytvorený pre ľudí, nie pre zisky. - - Synchronizácia Firefoxu medzi zariadeniami Pokračujte tam, kde ste prestali - - Preneste si svoje záložky, históriu a heslá do %1$su aj na toto zariadenie. Synchronizujte karty a heslá medzi zariadeniami pre bezproblémové prepínanie obrazovky. - - Prihlásiť sa Prihlásiť sa Synchronizácia je zapnutá - - Vždy zabezpečené súkromie Ochrana súkromia v predvolenom nastavení - - %1$s automaticky zabraňuje spoločnostiam tajne vás sledovať pri prehliadaní webu. Obsahuje úplnú ochranu súborov cookie, aby ste zabránili sledovačom používať súbory cookie, aby vás mohli sledovať na rôznych stránkach. @@ -1290,17 +1276,10 @@ Blokuje viac sledovacích prvkov. Stránky sa načítavajú rýchlejšie, ale niektoré funkcie na stránke môžu fungovať obmedzene. Vyberte umiestnenie panela s nástrojmi - - Umiestnite panel s nástrojmi, aby ste naň ľahko dosiahli. Ponechajte ho na spodku alebo si ho presuňte hore. Ponechajte ho dolu alebo ho presuňte nahor. - - Vaše súkromie Svoje údaje máte pod kontrolou - - %s vám dáva kontrolu nad tým, čo zdieľate na internete a čo zdieľate s nami. Firefox vám dáva kontrolu nad tým, čo zdieľate online a čo zdieľate s nami. @@ -1488,10 +1467,10 @@ Prilepiť a prejsť Prilepiť - + Adresa bola skopírovaná do schránky - + Pridať na úvodnú obrazovku @@ -1935,7 +1914,9 @@ Objavte ďalšie - Službu poskytuje Pocket + Službu poskytuje Pocket + + Vďaka službe %s. Súčasť rodiny Firefoxu. %s @@ -1949,4 +1930,14 @@ Prejsť do nastavení Návrhy Firefoxu + + + + zbaliť + + rozbaliť + + otvorte odkaz a dozviete sa viac o tejto kolekcii + + prečítať článok diff --git a/app/src/main/res/values-skr/strings.xml b/app/src/main/res/values-skr/strings.xml index 41e519ba9..821fb14b3 100644 --- a/app/src/main/res/values-skr/strings.xml +++ b/app/src/main/res/values-skr/strings.xml @@ -16,6 +16,12 @@ نجی براؤزنگ غیرفعال کرو ڳولو یا پتہ درج کرو + + تاریخ ڳولو + + نشانیاں ڳولو + + ٹیب ڳولو ڳولݨ ٹرماں درج کرو @@ -41,11 +47,9 @@ - حالیہ کتاب نشان - حالیہ محفوظ تھیاں - سارے محفوظ تھئے کتاب نشان ݙکھاؤ + سارے محفوظ تھیاں نشانیاں ݙکھاؤ ہٹاؤ @@ -130,12 +134,6 @@ سارے ݙکھاؤ سارے حالیہ ٹیب بٹݨ ݙکھاؤ - - \"%1$s\" کیتے تہاݙیاں ڳولاں - - %d سائٹاں ساریاں ہم وقت تھیاں ٹیباں ݙیکھو @@ -253,36 +251,21 @@ ڳولݨ ترتیباں - - - %1$s وچ کیا نواں ہے؟ - - جتھ تساں چھوڑیا ہے، ہݨ اُتھوں بیک اپ چاوݨ سوکھڑا ہے۔ - - ذاتی تھیا %1$s مکھ پناں - - ٹیب، نشانیاں تے براؤزنگ تاریخ کھولݨ کیتے ٹپ مارو۔ - - ستھریاں، منظم ٹیباں - - بہترین خاکے تے خود کار بند تھیندیاں ٹیباں نال ٹیباں دی بے ترتیبی کوں صاف کرو۔ - - حالیہ ڳولاں - - - آپݨے مکھ پنے تے ٹیباں نال آپݨیاں تازہ ترین ڳولاں تے ولدا ون٘جو۔ - - - جتھوں تساں چھوڑیا ہائی تہاݙا ذاتی تھیا فائرفوکس مُکھ پناں ہݨ اُتھوں شروع کرݨ سوکھا بݨیندا ہے۔ آپݨے حالیہ ٹیب، کتاب نشانیاں تے ڳولݨ نتیجے لبھو۔ + + ایں ویلے دی ڳول: + + ایں ویلے ایندے وچ ڳول: + + آپݨے ذاتی تھئے مکھ پنّے نال ملو۔ حالیہ ٹیباں، نشانیاں تے ڳولݨ نتیجے اتھ ظاہر تھیسن۔ - آزاد انٹرنیٹ وچ ست بسم اللہ + ٻئے ذاتی انٹرنیٹ وچ ست بسم اللہ ٻئے رنگ۔ چنگی رازداری۔ نفعے کنوں ودھ لوکاں نال پریت پالݨ۔ - فون سیٹ کنوں لیپ ٹاپ تے ہاپ کرو تے ولدا واپس وی + سکریناں سوئچ کرݨ ہݨ پہلے کنوں ٻہوں سوکھا ہے آپݨے مکھ پنّے تے ٻئی ڈیوائساں دے ٹیباں نال اُتھاؤں شروع کرو جتھوں تساں چھوڑیا ہائی۔ @@ -295,6 +278,9 @@ تہاݙے ٹیب ہم وقت تھیندے پئے ہن۔ آپݨی ݙوجھی ڈیوائس تے اتھاہوں شروع کرو جتھ تساں چھوڑیا ہائی۔ + + بند کرو + نویں %1$s ٹیب کھولو @@ -344,6 +330,15 @@ نجی براؤزنگ شاٹ کٹ شامل کرو ایچ ٹی ٹی پی ایس ــ صرف موڈ + + + کوکی بینر گھٹاوݨ + + کوکی بینراں کوں تھوڑا کرو + + + فائر فوکس آپݨے آپ کوکی بینراں دی درخواست کوں مسترد کرݨ دی کوشش کرینداے. اگر مسترد کرݨ دا آپشن موجودکائنی ، تاں فائر فوکس ساری کوکیز کوں بینر ختم کرݨ پاروں قبول کر سڳدا ہے. + خودکار طور تے ودھدی ہوئی حفاظت کیتے ایچ ٹی ٹی پی ایس خفیہ کاری پروٹوکول ورتندے ہوئے سائٹاں کوں کنکٹ کرݨ دی کوشش کریندے۔ @@ -383,8 +378,6 @@ تخصیص کرو - آپݨے فائرفوکس کھاتے نال کتاب نشانیاں، تاریخ تے ٻیا ٻہوں کجھ ہم وقت کرو - ٹیباں، نشانیاں، پاس ورڈ تے ٻیا ٻہوں کجھ ہم وقت کرݨ کیتے سائن ان تھیوو۔ فائرفوکس کھاتہ @@ -412,7 +405,7 @@ براؤزنگ تاریخ ڳولو - کتاب نشانیاں ڳولو + نشانیاں ڳولو ہم وقت تھیاں ٹیباں ݙیکھو @@ -455,7 +448,11 @@ a section where users see a list of tabs that they have visited in the past few days --> حالیہ ݙٹھے - پاکٹ + پاکٹ + + فکر انگیز کہاݨیاں + + %s ولوں تکڑے تھئے مضمون سپانسر تھیاں کہاݨیاں @@ -472,11 +469,31 @@ نظارہ - - فائرفوکس مکھ پنے لوگو تے انگل پھیرݨ نال وال پیپر وٹاؤ - - فائر فوکس لوگو ــ وال پیپر وٹاؤ، بٹݨ + + وال پیپر ڈاؤن لوڈ کائنی سڳا + + ولدا کوشش کرو + + وال پیپر کائنی وٹا سڳا + + ٻیا سِکھو + + + کلاسیکل %s + + محدود ایڈیشن + + + آزاد آوازاں دا نواں مجموعہ۔ %s + + آزاد آوازاں دا نواں مجموعہ۔ + + + رنگ دا تُرکا ازماؤ + + ہک وال پیپر چُݨو جہڑا تہاݙے نال الاوے۔ + + ٻئے وال پیپر پھلورو @@ -492,7 +509,7 @@ تاریخ - کتاب نشان + نشانیاں @@ -560,8 +577,6 @@ موزلّا کوں پڑھائی انسٹال کرݨ تے چلاوݨ دی اجازت ݙیندے - - ہم وقت کرݨ چالو کرو آپݨا ڈیٹا ہم وقت کرو تے محفوظ کرو @@ -606,7 +621,7 @@ ڈاؤن لوڈاں - کتاب نشان + نشانیاں ڈیسک ٹاپ نشانیاں @@ -624,6 +639,17 @@ بند کرو + + %d ٹیباں کوں کھولوں؟ + + ورقے لوڈ تھیوݨ ویلے ایݙے سارے ٹیباں کوں کھولݨ نال %s سست تھی سڳدی ہے ۔ کیا تساں واقعی جاری رکھݨا چاہندے ہو؟ + + ٹیباں کھولو + + منسوخ + %d سائٹ @@ -655,10 +681,6 @@ گرڈ - - گروپ ڳولو - - ہکو سن٘ویاں سائٹاں کٹھیاں گروپ کرو ٹیباں بند کرو @@ -782,8 +804,6 @@ تاریخ وچوں مٹاؤ %1$s (نجی موڈ) - - ٻئے ٹیباں @@ -814,17 +834,6 @@ اتھ کوئی تاریخ کائنی - - ٻیاں ڈیوائساں کنوں ہم وقت تھیاں - - ٻیاں ڈیوائساں کنوں - - - آپݨیاں ٻنھاں ڈیوائساں کنوں ہم وقت تھئی تاریخ ݙیکھݨ کیتے سائن ان تھیوو۔ - - سائن ان - - یا ہم وقت کرݨ کیتے فائرفوکس کھاتہ بݨاؤ]]> @@ -874,6 +883,10 @@ نویں ٹیب وچ کھولو نجی ٹیب وچ کھولو + + ساریاں کوں نویاں ٹیباں وچ کھولو + + ساریاں کوں نجی ٹیباں وچ کھولو مٹاؤ @@ -1047,6 +1060,10 @@ "Share" button. Opens the share menu when pressed. --> شیئر + + پی ڈی ایف محفوظ کرو + + پی ڈی ایف بݨاوݨ توں قاصر ڈیوائس تے بھیڄو @@ -1058,9 +1075,11 @@ کلپ بورڈ تے نقل تھی ڳیا - ہم وقت کرݨ کیتے سائن ان تھیوو + ہم وقت کرݨ کیتے سائن ان تھیوو ہم وقت کرݨ کیتے سائن ان تھیوو + + ڈیٹا ہم وقت کرو تے محفوظ کرو ساریاں ڈیوائساں تے بھیڄو @@ -1102,6 +1121,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s کوں آپݨاں پہلوں مقرر براؤز بݨاؤ + + نجی براؤزنگ ازماؤ + + + %1$s وچ محفوظ تھیاں کوکیاں یا تاریخ ٻاجھوں براؤز کرو + مجموعہ مٹ ڳیا @@ -1192,8 +1218,6 @@ نکل ون٘ڄو - - ایہ تہاݙا سارا براؤزنگ ڈیٹا مٹا ݙیسی۔ مٹاوݨ کیتے وقت دی حد @@ -1229,22 +1253,23 @@ گروپ مٹ ڳیا - - %s وچ ست بسم اللہ! - - ڈیوائساں دے درمیان فائرفوکس ہم وقت کرو - - ایں ڈیوائس تے کتاب نشانیاں، تاریخ تے پاس ورڈ %1$s تے گھن آؤ۔ - - سائن اپ - + + بہترین انٹرنیٹ وچ ست بسم اللہ + + لوکاں کیتے بݨا ہویا براؤزر، نہ کہ منافع کیتے۔ + + جتھوں تساں چھوڑیا ہائی، اُتھوں شروع کرو + + ہموار سکرین سوئچنگ کیتے سارے ڈیوائساں تے ٹیباں تے پاس ورڈاں کوں ہم وقت کرو۔ + + + سائن ان ہم وقت کرݨ چالو ہے - - ہمیشہ رازداری تے - - %1$s خودکار طور تے کمپنیاں کوں ویب تے تہاکوں خفیہ فالو کرݨ کنوں روکیندے۔ + + ڈیفالٹ نال رازدای حفاظت + + ٹریکراں کوں تہاکوں ساریاں سائٹاں وچ پیچھا کرݨ آلیاں کوکیاں ورتݨ کنوں روکݨ کیتے مکمل کوکی حفاظت دی خصوصیت معیاری (پہلے کنوں مقرر) @@ -1255,17 +1280,18 @@ ورقیاں کوں تکھیرا لوڈ کرݨ سانگے ٻئے ٹریکراں کوں بلاک کریندے، پر ورقے تے کجھ فعالت ترٹ سڳدی ہے۔ آپݨے ٹول بار دی جاء چُݨو - - ٹول بار کوں سوکھی پہنچ آلی جاء تے رکھو۔ ایں کوں تل وچ رکھو یا چوٹی تے گھن ون٘ڄو۔ - - تہاݙی رازداری - - - تساں جہڑی شئے تساں ساکوں شیئر کرو یا آن لائن شیئر کریندے ہو اوں کوں تہاݙے ڳاٻو وچ ݙیوݨ سانگے اساں %s کوں بݨایا ہے۔ + + ایں کوں تل وچ رکھو، یا اُتے گھن ون٘ڄو۔ + + + تساں آپݨے ڈیٹا کوں کنٹرول کریندے ہو + + تساں جہڑی شئے تساں ساکوں شیئر کرو یا آن لائن شیئر کریندے ہو فائرفوکس اوں کوں تہاݙے قاٻو وچ ݙیندی ہے۔ ساݙا رازداری نوٹس پڑھو + + بھلا تساں ہک حیران کن انٹرنیٹ کھولݨ کیتے تیار ہو؟ براؤزنگ شروع کرو @@ -1894,7 +1920,9 @@ ٻیاں لبھو - پاکٹ ولوں تکڑا تھیا + پاکٹ ولوں تکڑا تھیا + + تکڑا تھیا %s ولوں. فائرفوکس ٹٻر دا حصہ۔ %s @@ -1908,4 +1936,14 @@ ترتیباں تے ون٘ڄو فائرفوکس تجویز + + + + کٹھا کرو + + کھنڈاؤ + + ایں مجموعے بارے ٻیا سکھݨ کیتے لنک کھولو + + مضمون پڑھو diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index e08914de4..2094123d1 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -15,6 +15,12 @@ Iskanje ali naslov strani + + Zgodovina iskanja + + Iskanje po zaznamkih + + Išči po zavihkih Vnesite iskalni niz @@ -40,9 +46,6 @@ Izbrano - - Nedavni zaznamki - Nedavno shranjeno @@ -132,13 +135,6 @@ Gumb za prikaz vseh nedavnih zavihkov - - Vaše iskanje \"%1$s\" - - - %d spletnih mest Prikaži vse sinhronizirane zavihke @@ -259,39 +255,17 @@ Nastavitve iskanja - - - Kaj je novega v %1$su - - Zdaj je lažje nadaljevati, kjer ste nazadnje končali. - - Prilagojena domača stran %1$sa - - Skočite na odprte zavihke, zaznamke in zgodovino brskanja. - - Čisti, urejeni zavihki - - Počistite nered med zavihki z izboljšano postavitvijo in samodejnim zapiranjem zavihkov. - - Nedavna iskanja - - - Znova obiščite najnovejša iskanja na domači strani in v zavihkih. - - - Prilagojena domača stran Firefoxa vam zdaj olajšuje nadaljevanje nedokončanih opravil. Poiščite svoje nedavne zavihke, zaznamke in rezultate iskanja. + + Tokrat išči: + Spoznajte svojo prilagojeno domačo stran. Tukaj bodo prikazani nedavni zavihki, zaznamki in zadetki iskanja. - Dobrodošli v neodvisnem internetu - Dobrodošli v bolj osebnem internetu Več barve. Večja zasebnost. Enaka zavezanost ljudem namesto dobičku. - Skočite s telefona na računalnik in nazaj - Preklapljanje med zasloni je preprostejše kot kdajkoli prej Nadaljujte tam, kjer ste končali - z zavihki iz drugih naprav, ki so zdaj na vaši domači strani. @@ -305,6 +279,9 @@ Vaši zavihki se sinhronizirajo! Nadaljujte tam, kjer ste končali na drugi napravi. + + Zapri + Odpri nov zavihek v %1$su @@ -355,6 +332,7 @@ Dodaj bližnjico zasebnega brskanja Način "samo HTTPS" + Za večjo varnost poskuša samodejno vzpostaviti povezavo s šifrirnim protokolom HTTPS. @@ -463,8 +441,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nedavno obiskano - Pocket + Pocket + + Zgodbe, ki spodbujajo k razmisleku + + Članke zagotavlja %s Sponzorirane zgodbe @@ -488,11 +470,6 @@ Ozadja ni bilo mogoče spremeniti Več o tem - - Spremeni ozadje z dotikom logotipa na domači strani Firefoxa - - Logtip Firefoxa – spremeni ozadje, gumb Klasični %s @@ -653,6 +630,17 @@ Zapri + + Odprem več zavihkov (%d)? + + Odpiranje tako velikega števila zavihkov lahko upočasni %s med nalaganjem strani. Ali ste prepričani, da želite nadaljevati? + + Odpri zavihke + + Prekliči + %d spletno mesto @@ -682,10 +670,6 @@ Seznam Mreža - - Išči skupine - - Združi sorodna spletna mesta v skupine Zapri zavihke @@ -840,19 +824,6 @@ Ni zgodovine - - Sinhronizirano z drugih naprav - - Z drugih naprav - - - Prijavite se za ogled sinhronizirane zgodovine z drugih naprav. - - Prijava - - - Ali ustvarite Firefox Račun za začetek sinhronizacije]]> - Prenosi odstranjeni @@ -902,6 +873,10 @@ Odpri v novem zavihku Odpri v zasebnem zavihku + + Odpri vse v novih zavihkih + + Odpri vse v zasebnih zavihkih Izbriši @@ -1081,6 +1056,10 @@ Deli + + Shrani kot PDF + + Datoteke PDF ni mogoče ustvariti Pošlji na napravo @@ -1092,9 +1071,11 @@ Kopirano v odložišče - Prijava v sinhronizacijo + Prijava v sinhronizacijo Prijava v Sync + + Sinhroniziraj in shrani podatke Pošlji na vse naprave @@ -1130,6 +1111,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Nastavi %1$s kot privzeti brskalnik + + Preizkusite zasebno brskanje + + Brskajte brez shranjevanja piškotkov ali zgodovine v %1$s + Zbirka izbrisana @@ -1254,31 +1241,22 @@ Skupina izbrisana - - Dobrodošli v %s! Dobrodošli v boljšem internetu Brskalnik, razvit za ljudi, ne za dobiček. - - Sinhronizirajte Firefox med napravami Nadaljujte, kjer ste končali - - Prinesite zaznamke, zgodovino in gesla v %1$s na tej napravi. - - Prijava + + Sinhronizirajte zavihke in gesla med napravami za brezhibno preklapljanje med zasloni. Prijava Sync je vklopljen - - Vedno vključena zasebnost Privzeta zaščita zasebnosti - - %1$s samodejno prepreči, da bi vas podjetja skrivaj spremljala po spletu. + + Vključuje popolno zaščito pred piškotki, ki sledilcem onemogoča, da bi vas s pomočjo piškotkov zalezovali po spletnih mestih. Običajno (privzeto) @@ -1289,18 +1267,11 @@ Zavrača več sledilcev in pospeši nalaganje strani, vendar deli strani lahko nehajo delovati. Izberite postavitev orodne vrstice - - Postavite si orodno vrstico na doseg roke. Naj bo na dnu ali pa jo premaknite na vrh. Naj bo na dnu ali pa jo premaknite na vrh. - - Vaša zasebnost Vaši podatki pod vašim nadzorom - - %s smo zasnovali tako, da vam omogočimo nadzor nad tem, kaj delite na spletu in kaj delite z nami. Firefox vam omogoča nadzor nad tem, kaj delite na spletu in kaj delite z nami. @@ -1948,7 +1919,9 @@ Odkrijte več - Omogoča Pocket + Omogoča Pocket + + Omogoča %s. Del družine Firefox. %s @@ -1962,4 +1935,14 @@ Pojdi v nastavitve Firefoxovi predlogi + + + + strnete + + razširite + + odprete povezavo z več informacijami o tej zbirki + + preberete članek diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index ccf347172..6136fde8d 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -14,6 +14,12 @@ Çaktivizo shfletim privat Bëni kërkim ose jepni adresë + + Kërkoni në historik + + Kërkoni te faqerojtësit + + Kërkoni në skeda Jepni terma kërkimi @@ -39,8 +45,7 @@ - Faqerojtës së fundi - + Ruajtur së fundi Shfaqi krejt faqerojtësit e ruajtur @@ -74,6 +79,15 @@ Hidhe tej + + Hidhe tej + + + + Veçoria jonë më e fuqishme deri sot për privatësinë izolon gjurmues që ndjekin nga sajti në sajt. + + Mësoni mbi Mbrojtje Tërësore Nga Cookie-t + Lypset hyrje në kamera. Kaloni te rregullimet e Android-it, prekni Leje, dhe prekni Lejoje. @@ -118,18 +132,13 @@ Shfaq butonin për krejt skedat së fundi - - Kërkimi juaj për \"%1$s\" - - - %d sajte Shihni krejt skedat e njëkohësuara Pajisje e njëkohësuar + + Hiqe Hiqe @@ -244,26 +253,33 @@ Rregullime mbi kërkimin + + Kërkimi këtë herë: + + + Këtë herë kërko te: + - - Ç’ka të re në %1$s - - Tani është më e lehtë t’ia rifilloni atje ku e latë. - - Faqe hyrëse e personalizuar %1$s - - Kaloni te skeda tuajat të hapura, faqerojtës dhe historik shfletimesh. - - Skeda të qëruara, të sistemuara - - Spastroni rrëmujën e skedave, me skemë të përmirësuar dhe skeda me vetëmbyllje. - - Kërkime së fundi - - Rivizitoni kërkimet tuaja më të reja prej faqes tuaj hyrëse dhe skedash. - - - Faqja juaj hyrëse në Firefox, e personalizuar, tani e bën më të lehtë të riktheheni atje ku e latë. Gjeni skedat, faqerojtësit dhe përfundime kërkimi tuajat më të freskëta. + + Njihuni me faqen tuaj hyrëse të personalizuar. Këtu do të shfaqen skeda të hapura së fundi, faqerojtës dhe përfundime kërkimi. + + Mirë se vini te një internet më personal + + Më tepër ngjyra. Privatësi më e mirë. I njëjti përkushtim ndaj njerëzve, jo ndaj fitimeve. + + Ndërrimi i ekraneve është më i lehtë se kurrë + + Vazhdojeni ku e latë, me skeda nga pajisje të tjera tani në faqen tuaj hyrëse. + + Fillojani + + Hyni + + Anashkaloje + + Skedat tuaja po njëkohësohen! Vazhdojeni punën ku e latë në pajisjen tuaj tjetër. + + Mbylle @@ -315,6 +331,14 @@ Shtoni shkurtore shfletimi privat Mënyra Vetëm-HTTPS + + + Reduktim Banderolash Për Cookie-t + + Redukto banderola për cookie-t + + Firefox-i provon automatikisht të hedhë tej kërkesa për “cookie” nga banderola cookie-shbanners. Nëse s’ka mundësi hedhjeje tej, Firefox-i mund të pranojë krejt cookie-t, për të hequr qafe banderolën. + Përpiqet automatikisht të lidhet me sajtet duke përdorur protokollin HTTPS të fshehtëzimit, për më tepër siguri. @@ -354,7 +378,7 @@ Përshtateni - Njëkohësoni faqerojtës, historik, etj me Llogarinë tuaj Firefox + Bëni hyrjen, që të njëkohësoni skeda, faqerojtës, fjalëkalime, etj. Llogari Firefox @@ -421,8 +445,14 @@ a section where users see a list of tabs that they have visited in the past few days --> Vizituar së fundi - Pocket + Pocket + + Histori që të vënë në mendim + + Artikuj të mundësuar nga %s + + Histori të sponsorizuara Sfonde @@ -435,11 +465,29 @@ Sfondi u përditësua! Shiheni - - Ndryshojeni sfondin duke prekur stemën e faqes hyrëse të Firefox-it - - Stemë Firefox-i - ndryshoni sfondin, buton + + + S’u shkarkua dot sfond + + Riprovoni + + S’u ndryshua dot sfond + + Mësoni më tepër + + %s Klasik + + Edicion i Kufizuar + + Koleksioni i ri Zëra të Pavarur. %s + + Koleksioni i ri Zëra të Pavarur. + + Shtoni pakëz ngjyrë + + Zgjidhni një sfond që ju thotë diçka. + + Eksploroni më tepër sfonde @@ -522,8 +570,8 @@ E lejon Mozilla-n të instalojë dhe xhirojë studime - - Aktivizo Sync-un + + Njëkohësoni dhe ruani të dhënat tuaja Bëni hyrjen që të rilidhet @@ -581,6 +629,17 @@ Mbylleni + + Të hapen %d skeda? + + Hapja e kas shumë skedave mund të ngadalësojë %s-in, ndërkohë që ngarkohen faqet. Jeni i sigurt se doni të vazhdohet? + + Hapi skedat + + Anuloje + %d sajt @@ -610,10 +669,6 @@ Listë Rrjetë - - Grupe kërkimi - - Gruponi tok sajte të afërt Mbylli skedat @@ -718,8 +773,6 @@ Ruaj skeda në koleksion - - Menu skedash Fshije koleksionin @@ -739,9 +792,6 @@ %1$s (Mënyrë Private) - - Skeda të tjera - Jepni terma kërkimi @@ -769,11 +819,6 @@ S’ka historik këtu - - Hyni - - Ose krijoni një llogari Firefox, që të fillojë njëkohësimi]]> - Shkarkimet u Hoqën @@ -823,6 +868,10 @@ Hape në skedë të re Hape në skedë private + + Hapi krejt në skeda të reja + + Hapi krejt në skeda private Fshije @@ -1000,6 +1049,10 @@ Ndajeni me të tjerë + + Ruaje si PDF + + S’arrihet të prodhohet PDF Dërgojeni në pajisje @@ -1011,9 +1064,11 @@ U kopjua në të papastër - Që të njëkohësoni, bëni hyrjen + Që të njëkohësoni, bëni hyrjen Për Njëkohësim, bëni hyrjen + + Njëkohësoni dhe ruani të dhëna Dërgoje te krejt pajisjet @@ -1140,8 +1195,6 @@ Dil - - Kjo do të fshijë krejt të dhënat tuaja të shfletimit. Interval kohor për t’u fshirë @@ -1175,21 +1228,22 @@ Grupi u fshi - - Mirë se vini te %s! - - Njëkohësoni Firefox-in mes pajisjesh - - Sillni faqerojtës, historik dhe fjalëkalime te %1$s në këtë pajisje. - - Regjistrohuni + + Mirë se vini në një internet më të mirë + + Një shfletues i ndërtuar për njerëzit, jo për fitime. + + Vazhdoni atje ku e latë + + Njëkohësoni skeda dhe fjalëkalime përmes pajisjesh, për ndërrim të pacen ekranesh. + + Hyni Njëkohësimi është aktiv - - Privatësi gjithnjë në punë - - %1$s i pengon vetvetiu shoqëritë t’ju ndjekin ju fshehtas nëpër internet. + + Mbrojtje privatësie, si parazgjedhje + + Me Mbrojtj Tërësore Nga Cookie-t, për të ndalur gjurmuesit të përdorin “cookies” për t’ju ndjekur nëpër sajte. Standarde (parazgjedhje) @@ -1200,16 +1254,17 @@ Bllokon më shumë gjurmues, ndaj faqet ngarkohen më shpejt, por disa anë, pjesë e faqes, mund të mos punojnë. Zgjidhni vendosjen e panelit tuaj - - Vendoseni panelin diku ku e përdorni kollaj. Mbajeni në fund, ose kalojeni në krye. - - Privatësia juaj - - E kemi hartuar %s për t’ju dhënë kontroll mbi ç’ndani me të tjerë në internet dhe ç’ndani me ne. + + Mbajeni në fund, ose shpjereni në krye. + + Të dhënat tuaja i kontrolloni ju + + Firefox-i ju lejon kontroll mbi ç’ndani me të tjerë në internet dhe ç’ndani me ne. Lexoni shënimin tonë mbi privatësinë + + Gati për të zbuluar një internet mahnitës? Nisni shfletimin @@ -1298,6 +1353,8 @@ Krejt cookie-t nga palë të treta (mund të shkaktojë mosfunksionim të disa sajteve) Krejt cookie-t (do të shkaktojë mosfunksionim sajtesh) + + Izoloni cookies nga sajti në sajt Lëndë gjurmimi @@ -1320,8 +1377,12 @@ Kufizon aftësinë e rrjeteve shoqërorë të gjurmojnë nëpër internet veprimtarinë tuaj të shfletimit. <em>Cookies</em> Gjurmimi Nga Sajte Në Sajte + + Cookies Nga Sajti Në Sajt Bllokon <em>cookies</em> të cilat rrjete reklamash dhe shoqëri analizimesh i përdorin për të përpiluar të dhëna tuajat të shfletimit nëpër mjaft sajte. + + Mbrojtja Tërësore Nga Cookie-t i izolon “cookies” te sajti ku gjendeni, që gjurmuesit të mos i përdorin dot për t’ju ndjekur nga një sajt te tjetri. Nxjerrës kriptomonedhash @@ -1522,6 +1583,9 @@ Ruaj dhe vetëplotëso adresa + + Përfshini hollësi të tilla si numra, email dhe adresa dërgimi + Shtoni kartë @@ -1831,7 +1895,9 @@ Zbuloni më tepër - Bazuar në Pocket. + Bazuar në Pocket. + + Mundësuar nga %s. Pjesë e Familjes Firefox. %s @@ -1845,4 +1911,14 @@ Kalo te rregullimet Firefox-i Sugjeron + + + + tkurre + + zgjeroje + + që të mësoni më tepër mbi këtë koleksion, hapni lidhjen + + lexoni artikullin diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 6ad5c6425..86563d3ce 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -15,6 +15,12 @@ Онемогући приватно прегледање Претражи или унеси адресу + + Претражи историју + + Претражи обележиваче + + Претражи језичке Унеси појмове претраге @@ -40,8 +46,6 @@ - Недавни обележивачи - Недавно сачувано Прикажи све сачуване обележиваче @@ -129,12 +133,6 @@ Дугме за приказ свих недавних језичака - - Ваша претрага за \"%1$s\" - - %d сајтови Погледај све синхронизоване језичке @@ -256,38 +254,22 @@ Подешавања претраге - - - Шта је ново у %1$s - - Сада је лакше да наставите тамо где сте стали. - - Прилагођена %1$s почетна страница - - Приступите отвореним језичцима, обележивачима и историји прегледања. - - Чисти, организовани језичци - - Очистите неред на језичцима помоћу побољшаног распореда и аутоматског затварања језичака. - - Недавне претраге - - - Поново посетите своје недавне претраге са почетне странице и језичака. - - - Ваша лична Firefox почетна страница сада олакшава да наставите тамо где сте стали. Пронађите своје недавне језичке, обележиваче и резултате претраге. + + Овај пут претражујте са: + + Овај пут претражујте: + + Упознајте своју персонализовану почетну страницу. Овде се приказују недавни језичци, обележивачи и резултати претраге. - Добродошли у независни интернет + Добродошли на више личан интернет Више боја. Боља приватност. Иста посвећеност: људи пре профита. - Брзо се пребацујте између телефона и лаптопа - + Пребацивање између екрана је лакше него икада Сада на вашој почетној страници наставите где сте стали са језичцима са других уређаја. @@ -300,6 +282,9 @@ Ваши језичци се синхронизују! Наставите где сте стали на другом уређају. + + Затвори + Отвори нови %1$s језичак @@ -351,6 +336,14 @@ Додајте пречицу за приватно прегледање Строги HTTPS режим + + + Смањење банера колачића + + Смањи банере колачића + + Firefox аутоматски покушава да одбије захтеве за складиштење колачића када се прикаже банер колачића. Ако опција за одбијање није доступна, Firefox може прихватити све колачиће да би сакрио банер. + Самостално се повезујемо на странице користећи HTTPS протокол за шифровање података у преносу зарад боље безбедности. @@ -390,8 +383,6 @@ Прилагоди - Синхронизујте забелешке, историјат и још много тога са својим Firefox налогом - Пријавите се да бисте синхронизовали своје језичке, обележиваче, лозинке и друго. Firefox налог @@ -416,7 +407,7 @@ Прикажи предлоге из оставе - Претражи историјат прегледања + Претражи историју прегледања Претражи забелешке @@ -458,8 +449,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Недавно посећено - Pocket + Pocket + + Побуђујуће и поучне приче + + Чланке обезбеђује %s Спонзорисане приче @@ -474,11 +469,30 @@ Позадина је ажурирана! Погледај - - Промени позадину додиром на лого почетне стране Firefox-а - - Firefox лого - промени позадину, дугме + + + Није могуће преузети позадину + + Покушај поново + + Није могуће променити позадину + + Сазнај више + + Класнични %s + + Ограничено издање + + + Нова збирка „Независни гласови“. %s + + Нова збирка „Независни гласови“. + + Пробајте нове боје + + Изаберите позадину у свом стилу. + + Истражите још позадина @@ -492,7 +506,7 @@ Изаберите шта синхронизовати - Историјат + Историја Забелешке @@ -561,8 +575,6 @@ Омогућава Mozilla-и да инсталира и покреће студије - - Укључите Sync Синхронизујте и сачувате своје податке @@ -617,7 +629,7 @@ Остале забелешке - Историјат + Историја Нови језичак @@ -625,6 +637,17 @@ Затвори + + Отворити %d језичака? + + Отварање толико језичака може да успори %s док се странице учитавају. Сигурни сте да желите да наставите? + + Отвори језичке + + Откажи + %d сајт @@ -654,10 +677,6 @@ Листа Мрежа - - Претраживачке групе - - Групиши сродне сајтове Затвори језичак @@ -781,14 +800,11 @@ %1$s (приватни режим) - - Други језичци - Унеси појмове за претрагу - Обриши историјат + Обриши историју Историја је избрисана @@ -809,18 +825,7 @@ Старије - Овде нема историјата - - - Синхронизовано са другог уређаја - - Са других уређаја - - Пријавите се да бисте видели историју синхронизовану са других уређаја. - - Пријавите се - - или направите Firefox налог да почнете синхронизацију]]> + Овде нема историје @@ -872,6 +877,10 @@ Отвори у новом језичку Отвори у приватном језичку + + Отворите све у новим језичцима + + Отворите све у приватним језичцима Обриши @@ -1049,6 +1058,10 @@ Подели + + Сачувај као PDF + + Није могуће направити PDF Пошаљи на уређај @@ -1060,10 +1073,12 @@ Копирано у остави - Синхронизација + Синхронизација Пријави се на Sync + + Синхронизуј и сачувај податке Пошаљи на све уређаје @@ -1099,6 +1114,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Поставите %1$s као подразумевани прегледач + + Испробајте приватно прегледање + + Прегледајте без чувања колачића и историје уз %1$s + Збирка обрисана @@ -1162,7 +1183,7 @@ %d језичака - Историјат прегледања и подаци страница + Историја прегледања и подаци страница %d адреса @@ -1187,9 +1208,6 @@ Изађи - - Ово ће обрисати све ваше податке прегледања. - Временски распон за брисање @@ -1223,23 +1241,23 @@ Група је обрисана - - Добро дошли у апликацију %s! - - - Синхронизујте Firefox на више уређаја - - Пренесите обележиваче, историју и лозинке у %1$s на овом уређају. - - Пријави се + + Добродошли на бољи интернет + + Прегледач за људе, а не за профит. + + Наставите тамо где сте стали + + Синхронизујте језичке и лозинке на свим уређајима за несметано пребацивање. + + Пријави се Sync је укључен - - Увек укључена приватност - - %1$s аутоматски спречава компаније да вас тајно прате на мрежи. + + Подразумевана заштита приватности + + Свеобухватна заштита колачића спречава трагаче да вас прате по интернету путем колачића. Стандардно (подразумевано) @@ -1250,16 +1268,17 @@ Блокира више пратилаца те се странице учитавају брже али неке могућности на страници можда неће радити. Изаберите положај алатнице - - Постави алатницу на дохват руке. Било на дну или на врху. - - Ваша приватност - - Дизајнирали смо %s тако да имате пуну контролу над оним што делите на мрежи и са нама. + + На дну или на врху екрана - поставите по жељи. + + Имате контролу над својим подацима + + Firefox вам даје контролу над оним што делите на мрежи и оним што делите са нама. Прочитајте наше обавештење о приватности + + Спремни да откријете фантастичан интернет? Започните прегледање @@ -1894,7 +1913,9 @@ Откријте више - Покреће Pocket. + Покреће Pocket. + + Покреће %s. Део Firefox породице. %s @@ -1908,4 +1929,14 @@ Иди у подешавања Firefox предлози + + + + скупи + + рашири + + отворите везу да сазнате више о овој колекцији + + прочитајте чланак diff --git a/app/src/main/res/values-su/strings.xml b/app/src/main/res/values-su/strings.xml index 0a214a752..9550afed8 100644 --- a/app/src/main/res/values-su/strings.xml +++ b/app/src/main/res/values-su/strings.xml @@ -16,6 +16,12 @@ Paluruh atawa asupkeun alamat + + Paluruh jujutan + + Paluruh markah + + Paluruh tab Asupkeun istilah pamaluruhan @@ -40,8 +46,6 @@ - Markah anyar - Anyar diteundeun Témbongkeun sadaya markah anu diteundeun @@ -128,13 +132,6 @@ Témbongkeun sakabéh tombol tab anyar - - Sungsian anjeun ngeunaan \"%1$s\" - - - %d loka Tingali tab anu singkron @@ -258,38 +255,20 @@ Setélan pamaluruhan - - - Nu anyar di %1$s - - Ayeuna leuwih babari nyokot cadangan nalika anjeun ninggalkeun. - - Tepas %1$s pribadi - - Luncat ka tab muka, markah, jeung jujutan ngalanglang. - - Tab beresih tur rapih - - Singkahan tabrakan tab ku tata perenah anu leuwih hadé tur tab oto-nutup. - - Anyar nyungsi - - Anjangan deui sungsian panungtung ti tepas tab. - - - Tepas Firefox pribadi kiwari mantuan anjeun nyokot ti anu ditinggalkeun. Néangan tab anu can lila, markah, jeung hasil nyungsi. + + Ayeuna paluruh: + + + Saayeunaeun paluruh di: + Nepangkeun kaca tepas pribadi anjeun. Tab mutahir, markah, jeung hasil maluruh bakal némbongan di dieu. - Wilujeng sumping di internét mandiri - Wilujeng sumping di internét anu leuwih pribadi Leuwih warnaan. Pripasi leuwih hadé. Komitmen anu sarua pikeun jalma batan bati. - Luncat tina telepon ka laptop jeung sabalikna - Ngagilirkeun layar leuwih babari ti nu atos-atos Buka ti panungtung anu ditinggalkeun maké tab ti séjén parabot ayeuna dina kaca tepas. @@ -303,6 +282,9 @@ Tab anjeun keur disingkronkeun! Pilih ti nu ditinggalkeun dina séjén parabot anjeun. + + Tutup + Buka dina tab %1$s anyar @@ -352,6 +334,14 @@ Tambahan tarabas nyungsi nyamuni Mode HTTPS-Hungkul + + + Kurangan Spanduk Réréméh + + Kurangan spanduk réréméh + + Firefox otomatis nyoba nampik pamundut réréméh dina spanduk réréméh. Upama teu aya pilihan nampik, Firefox bisa nampa sadaya réréméh pikeun ngaleungitkeun spandukna. + Otomatis nyoba nyambung ka loka maké protokol énkripsi HTTPS pikeun ngaronjatkeun kaamanan. @@ -461,8 +451,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Anyar dianjangan - Saku + Saku + + Carita pikiraneun + + Artikel dijalankeun ku %s Carita anu disponsoran @@ -486,11 +480,6 @@ Teu bisa ngarobah latar Leuwih teleb - - Ganti latar ku cara noél logo tepas Firefox - - Logo Firefox - ganti latar, tombol %s klasik @@ -501,6 +490,8 @@ Kumpulan Independent Voices anyar. %s Kumpulan Independent Voices anyar. + + Cobaan képrétkeun kelir Pilih latar anu nyarita ka anjeun. @@ -651,6 +642,17 @@ Tutup + + Buka %d tab? + + Muka loba tab kieu bisa matak meyeted ka %s nalika kaca-kacana dimuat. Rék diteruskeun baé? + + Buka tab + + Bolay + %d loka @@ -680,10 +682,6 @@ Béréndélan Grid - - Sungsi grup - - Gorombolkeun loka anu patali Tutup tab @@ -833,18 +831,6 @@ Teu aya jujutan di dieu - - Disingkronkeun ti séjén alat - - Ti séjén alat - - - Asup pikeun nénjo jujutan anu disingkronkeun tina parangkat anjeun nu séjén. - - Asup - - Atawa jieun akun Firefox pikeun mitembeyan nyingkronkeun]]> - Undeuran Disingkahkeun @@ -894,6 +880,10 @@ Buka dina tab anyar Buka dina tab nyamuni + + Buka kabéh dina tab anyar + + Buka kabéh dina tab nyamuni Pupus @@ -1073,6 +1063,10 @@ Bagikeun + + Simpen salaku PDF + + Teu bisa nyieun PDF Kirim ka parangkat @@ -1084,9 +1078,11 @@ Ditiron kana papan klip - Asup pikeun nyingkronkeun + Asup pikeun nyingkronkeun Asup ka Sync + + Singkronkeun tur simpen data Kirim ka sadaya parangkat @@ -1122,6 +1118,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Jadikeun %1$s panyungsi baku + + Cobaan nyungsi nyamuni + + Nyungsi tanpa neundeun réréméh atawa jujutan dina %1$s + Mupus koléksi @@ -1250,30 +1252,23 @@ Grup dihapus - - Wilujeng sumping di %s! Wilujeng sumping di internét anu leuwih hadé Panyungsi anu diwangun pikeun jalma, lain bati. - - Singkronkeun Firefox sakur parabot Angkut di tempat nu ku anjeun tinggalkeun - - Bawa markah, jujutan, jeung kecap sandi ka %1$s di ieu parabot. - - Daptar + + Singkronkeun tab jeung kecap sandi dina sadaya paranti pikeun pindah layar anu mulus. Asup Singkronna hurung - - Pripasi salawasna - - %1$s otomatis megat maskapé rerencepan nunutur anjeun ngalanglang raramat. + + Salindung pripasi sacara baku + + Miturkeun Total Cookie Protection pikeun ngeureunkeun palacak tina maké réréméh pikeun ngintip anjeun meuntas loka. Baku (bawaan) @@ -1284,17 +1279,12 @@ Meungpeuk palacak leuwih loba sangkan kaca dimuat leuwih gancang, tapi sababaraha fungsionalitas dina kaca bisa gagal. Pilih perenah tulbar anjeun - - Perenahkeun tulbar sangkan babari kahontal. Teundeun di handap, atawa pindahkeun ka punclut. Angger di handap, atawa pindahkeun ka luhur. - - Salindungan anjeun Anjeun ngadalikeun data anjeun - - Kami geus ngarancang %s sangkan anjeun bisa ngatur naon anu dibagikeun onlén jeung naon anu dibagikeun ka kami. + + Firefox ngatur sangkan anjeun bisa nangtukeun naon anu dibagikeun onlén jeung naon anu dibagikeun ka kami. Maca wawaran salindungan kami @@ -1933,7 +1923,9 @@ Panggihan nu lianna - Ditanagaan ku Pocket. + Ditanagaan ku Pocket. + + Dijalankeun ku %s. Bagéan ti kulawarga Firefox. %s @@ -1947,4 +1939,14 @@ Buka setélan Firefox Suggest + + + + tilep + + batek + + buka tutumbu pikeun leuwih teleb ngeunaan ieu koléksi + + baca artikel diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 69b453b48..712e703bd 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -15,6 +15,12 @@ Inaktivera privat surfning Sök eller ange adress + + Sökhistorik + + Sök bokmärken + + Sök flikar Ange söktermer @@ -40,8 +46,6 @@ - Senaste bokmärken - Nyligen sparade Visa alla sparade bokmärken @@ -132,13 +136,6 @@ Visa knappen alla senaste flikar - - Du sökte efter \"%1$s\" - - - %d webbplatser Se alla synkroniserade flikar @@ -263,39 +260,20 @@ Sökinställningar - - - Vad är nytt i %1$s - - Det är nu enklare att fortsätta där du slutade. - - Personlig startsida för %1$s - - Hoppa till dina öppna flikar, bokmärken och surfhistorik. - - Rena, organiserade flikar - - Rensa bort röran med förbättrad layout och flikar som stängs automatiskt. - - Senaste sökningar - - - Återbesök dina senaste sökningar från din startsida och flikar. - - - Din personliga Firefox-startsida gör det nu lättare att fortsätta där du slutade. Hitta dina senaste flikar, bokmärken och sökresultat. + + Denna sökning: + + Denna gång, sök med: + + Möt din personliga startsida. Senaste flikar, bokmärken och sökresultat kommer att visas här. - Välkommen till ett oberoende internet - Välkommen till ett mer personligt internet Mer färger. Bättre integritet. Samma åtagande att sätta människor före vinster. - Byt från telefon till laptop och tillbaka - Att växla mellan skärmar är enklare än någonsin Fortsätt där du slutade med flikar från andra enheter, nu på din startsida. @@ -309,6 +287,9 @@ Dina flikar synkroniseras! Fortsätt där du slutade på din andra enhet. + + Stäng + Öppna en ny %1$s-flik @@ -358,6 +339,14 @@ Lägg till genväg för privat surfning Endast HTTPS-läge + + + Reducering av kakbanner + + Minska kakbanners + + Firefox försöker automatiskt avvisa kak-förfrågningar på kak-banners. Om ett avvisningsalternativ inte är tillgängligt kan Firefox acceptera alla kakor för att ta bort bannern. + Försöker automatiskt ansluta till webbplatser med HTTPS-krypteringsprotokollet för ökad säkerhet. @@ -397,8 +386,6 @@ Anpassa - Synkronisera bokmärken, historik och mer med ditt Firefox-konto - Logga in för att synkronisera flikar, bokmärken, lösenord och mer. Firefox-konto @@ -468,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Nyligen besökta - Pocket + Pocket + + Tankeväckande berättelser + + Artiklar tillhandahålls av %s Sponsrade berättelser @@ -493,12 +484,6 @@ Det gick inte att ändra bakgrundsbild Läs mer - - Ändra bakgrundsbild genom att trycka på Firefox startsidas logotyp - - - Firefox logotyp - knapp för att ändra bakgrundsbild Klassisk %s @@ -597,8 +582,6 @@ Tillåter Mozilla att installera och köra undersökningar - - Aktivera Sync Synkronisera och spara din data @@ -659,6 +642,17 @@ Stäng + + Öppna %d flikar? + + Att öppna så många flikar kan sakta ner %s medan sidorna laddas. Är du säker på att du vill fortsätta? + + Öppna flikar + + Avbryt + %d webbplats @@ -689,10 +683,6 @@ Lista Rutnät - - Sökgrupper - - Gruppera relaterade webbplatser tillsammans Stäng flikar @@ -817,9 +807,6 @@ %1$s (Privat läge) - - Andra flikar - Ange söktermer @@ -848,18 +835,6 @@ Ingen historik här - - Synkroniserad från andra enheter - - Från andra enheter - - - Logga in för att se historik synkroniserad från dina andra enheter. - - Logga in - - Eller skapa ett Firefox-konto för att börja synkronisera]]> - Nedladdningar har tagits bort @@ -909,6 +884,10 @@ Öppna i ny flik Öppna i privat flik + + Öppna alla i nya flikar + + Öppna alla i privata flikar Ta bort @@ -1086,6 +1065,10 @@ Dela + + Spara som PDF + + Det går inte att generera PDF Skicka till enhet @@ -1097,9 +1080,11 @@ Kopierad till urklipp - Logga in för att synkronisera + Logga in för att synkronisera Logga in till Sync + + Synkronisera och spara data Skicka till alla enheter @@ -1139,6 +1124,13 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Gör %1$s till din standardwebbläsare + + Prova privat surfning + + + Surfa utan sparade kakor eller historik i %1$s + Samling borttagen @@ -1229,8 +1221,6 @@ Avsluta - - Detta kommer att ta bort all dina surfdata. Tidsintervall att radera @@ -1264,34 +1254,21 @@ Grupp borttagen - - Välkommen till %s! Välkommen till ett bättre internet En webbläsare byggd för människor, inte för vinster. - - Synkronisera Firefox mellan enheter Fortsätt där du slutade - - Ta med bokmärken, historik och lösenord till %1$s på den här enheten. Synkronisera flikar och lösenord mellan enheter för smidig skärmväxling. - - Registrera dig Logga in Synkronisering är på - - Alltid med integritet Integritetsskydd som standard - - %1$s hindrar automatiskt företag från att i hemlighet följa dig på nätet. Totalt skydd mot kakor hindrar spårare från att använda kakor för att förfölja dig mellan webbplatser. @@ -1304,18 +1281,11 @@ Blockerar fler spårare så att sidor laddas snabbare, men vissa sidor kanske inte fungerar ordentligt. Välj plats för verktygsfältet - - Placera verktygsfältet inom räckhåll. Ha den på botten eller flytta den till toppen. Behåll den på botten eller flytta den till toppen. - - Din integritet Du kontrollerar din data - - Vi har utformat %s för att ge dig kontroll över vad du delar online och vad du delar med oss. Firefox ger dig kontroll över vad du delar online och vad du delar med oss. @@ -1503,10 +1473,10 @@ Klistra in och kör Klistra in - + URL kopierad till urklipp - + Lägg till på startsidan @@ -1952,7 +1922,9 @@ Upptäck mer - Tillhandahålls av Pocket + Tillhandahålls av Pocket + + Tillhandahålls av %s. Del av Firefox-familjen. %s @@ -1966,4 +1938,14 @@ Gå till inställningar Firefox-förslag + + + + fäll in + + expandera + + öppna länken för att lära dig mer om denna samling + + läs artikeln diff --git a/app/src/main/res/values-szl/strings.xml b/app/src/main/res/values-szl/strings.xml index b8ff227d1..b3aeac867 100644 --- a/app/src/main/res/values-szl/strings.xml +++ b/app/src/main/res/values-szl/strings.xml @@ -16,6 +16,8 @@ Szukej abo wkludź adresa + + Wkludź szukane słowa Sam sie pokożōm twoje ôtwarte karty. @@ -39,11 +41,9 @@ - Niydowne zokłodki - - Niydowno spamiyntane zokłodki - - Pokoż wszyske + Niydowne zokłodki + + Ôstatnio spamiyntane Pokoż wszyske zokłodki @@ -79,6 +79,9 @@ Ôdkoż + + Zawrzij + Trza dostympu do kamery. Idź doo sztalōnkōw Androidaa, tyknij "dozwolyństwa" i tyknij "zgoda". @@ -125,10 +128,10 @@ Pokoż knefel wszyskich niydownych kart - Twoje wyszukowanie „%1$s” + Twoje wyszukowanie „%1$s” - Strōny: %d + Strōny: %d Ôbocz wszyske synchrōnizowane karty @@ -238,8 +241,6 @@ Pokazować dorady szukanio we prywatnych ôknach? %s bydzie przekazowoł bazowyj wyszukowarce wszysko, co wkludzosz we posku z adresōm. - - Przewiydz sie wiyncyj Szukej na %s @@ -250,25 +251,25 @@ - Co je nowego w aplikacyji %1$s + Co je nowego w aplikacyji %1$s - Teroz je snadnij zacznōńć nazod tam, kaj sie skōńczyło. + Teroz je snadnij zacznōńć nazod tam, kaj sie skōńczyło. - Spersōnalizowano dōmowo strōna aplikacyje %1$s + Spersōnalizowano dōmowo strōna aplikacyje %1$s - Gibko dostōń do ôtwartych kart, zokłodek i historyje wyszukowanio. + Gibko dostōń do ôtwartych kart, zokłodek i historyje wyszukowanio. - Klarowne, zorganizowane karty + Klarowne, zorganizowane karty - Zrōb porzōndek skuli lepszego rozłożynio i autōmatycznego zawiyranio kart. + Zrōb porzōndek skuli lepszego rozłożynio i autōmatycznego zawiyranio kart. - Niydowne szukania + Niydowne szukania - Wrōć do niydownego szukanio z domowyj strōny i kart. + Wrōć do niydownego szukanio z domowyj strōny i kart. - Twoja spersōnalizowano dōmowo strōna Firefoksa pōmogo teroz snadnij wrōcić tam, kaj sie skōńczyło. Znojdź niydowne karty, zokłodki i wyniki szukanio. + Twoja spersōnalizowano dōmowo strōna Firefoksa pōmogo teroz snadnij wrōcić tam, kaj sie skōńczyło. Znojdź niydowne karty, zokłodki i wyniki szukanio. @@ -361,7 +362,7 @@ Przipasuj - Synchrōnizuj zokłodki, historyjo i inksze ze swojim kōntym Firefox + Synchrōnizuj zokłodki, historyjo i inksze ze swojim kōntym Firefox Kōnto Firefox @@ -448,10 +449,10 @@ Pokoż - Tyknij logo dōmowyj strōny Firefoxa, coby zmiynić tapeta + Tyknij logo dōmowyj strōny Firefoxa, coby zmiynić tapeta - Logo firefoxa - zmiyń tapeta, knefel + Logo firefoxa - zmiyń tapeta, knefel @@ -535,7 +536,7 @@ - Załōncz synchronizacyjo + Załōncz synchronizacyjo Wloguj sie, coby zaś sie połōnczyć @@ -625,9 +626,9 @@ Nec - Grupy szukanio + Grupy szukanio - Zbiyrej społym powiōnzane strōny + Zbiyrej społym powiōnzane strōny Zawrzij karty @@ -734,8 +735,6 @@ Myni ôtwartych kart Spamiyntej karty do kolekcyje - - Myni kart @@ -756,7 +755,7 @@ %1$s (prywatny tryb) - Inksze karty + Inksze karty @@ -786,9 +785,9 @@ Niy ma sam żodnyj historyje - Synchrōnizowane z inkszych maszin + Synchrōnizowane z inkszych maszin - Z inkszych maszin + Z inkszych maszin @@ -1075,8 +1074,6 @@ Karty sōm zawarte Zokłodki sōm spamiyntane! - - Przidane do topowych strōn! Przidane do skrōtōw! @@ -1155,7 +1152,8 @@ Skōńcz - Bez to skasujōm sie wszyske dane przeglōndanio. + Bez to skasujōm sie wszyske dane przeglōndanio. + %s skasuje ôbrane dane przeglōndanio. @@ -1168,9 +1166,6 @@ Kasowanie danych przeglōndanio… - - To skasuje wszyske elymynta. - Pociep @@ -1178,53 +1173,23 @@ Grupa skasowano - - - Firefox Preview to teroz Firefox Nightly - - - Firefox Nightly kożdo noc je aktualizowany i mo nowe, eksperymyntalne funkcyje. - Może ale być mynij stabilny. Pobier nasza przeglōndarka beta, coby używać stabilniyjszyj wersyje. - - - Pobier Firefoxa Beta na Androida - - - Firefox Nightly sie przekludziōł - - - Ta aplikacyjo niy bydzie już dostować bezpiecznych aktualizacyji. Przestōń jij używać i przełōncz sie na nowe Nightly. - \n\nCoby przeniyś swoje zokłodki, dane logowanio i historyjo do inkszyj aplikacyji, załōż kōnto Firefoxa. - - Przełōncz sie na nowe Nightly - - - Firefox Nightly sie przekludziōł - - Ta aplikacyjo niy bydzie już dostować bezpiecznych aktualizacyji. Pobier nowe Nightly i przestōń jij używać. - \n\nCoby przeniyś swoje zokłodki, dane logowanio i historyjo do inkszyj aplikacyji, załōż kōnto Firefoxa. - - Pobier nowe Nightly - - %s wito! + %s wito! - Synchrōnizuj Firefoxa miyndzy maszinami - - Synchrōnizuj aplikacyjo %1$s miyndzy maszinami + Synchrōnizuj Firefoxa miyndzy maszinami - Przekludź zokłodki, historyjo i hasła do aplikacyje %1$s na tyj maszinie. + Przekludź zokłodki, historyjo i hasła do aplikacyje %1$s na tyj maszinie. - Zaregistruj sie + Zaregistruj sie Synchrōnizacyjo je załōnczōno - Zawdy z prywatnościōm + Zawdy z prywatnościōm - %1$s autōmatycznie niy dowo fyrmōm śledzic cie po kryjōmu po necu. + %1$s autōmatycznie niy dowo fyrmōm śledzic cie po kryjōmu po necu. Standardowo (bazowe) @@ -1236,13 +1201,13 @@ Ôbier, kaj mo być posek z noczyniami - Dej posek z noczyniami na spodku abo na wiyrchu, coby snadnie do niego dostować. + Dej posek z noczyniami na spodku abo na wiyrchu, coby snadnie do niego dostować. - Twoja prywatność + Twoja prywatność - %s dowo ci kōntrola nad tym, co udostympniosz online i co udostympniosz nōm. + %s dowo ci kōntrola nad tym, co udostympniosz online i co udostympniosz nōm. Poczytej ô naszych prawidłach prywatności diff --git a/app/src/main/res/values-tg/strings.xml b/app/src/main/res/values-tg/strings.xml index cbae94f1a..129442dd4 100644 --- a/app/src/main/res/values-tg/strings.xml +++ b/app/src/main/res/values-tg/strings.xml @@ -14,6 +14,12 @@ Ғайрифаъол кардани тамошокунии хусусӣ Нишониеро ҷустуҷӯ кунед ё ворид намоед + + Ҷустуҷӯ дар таърих + + Ҷустуҷӯ дар хатбаракҳо + + Ҷустуҷӯ дар варақаҳо Вожаҳои ҷустуҷӯиро ворид намоед @@ -40,8 +46,6 @@ - Хатбаракҳои охирин - Иловашудаи охирин Намоиш додани ҳамаи хатбаракҳои нигоҳдошташуда @@ -132,13 +136,6 @@ Нишон додани тугмаи ҳамаи хатбаракҳои охирин - - Ҷустуҷӯи шумо барои \"%1$s\" - - - %d сомона Дидани ҳамаи варақаҳои ҳамоҳангшуда @@ -260,39 +257,20 @@ Танзимоти ҷустуҷӯ - - - Дар %1$s чӣ нав аст - - Акнун ба он сомонае, ки шумо ба қарибӣ тамошо кардаед, баргардонидан осонтар аст. - - Шахсисозии саҳифаи асосии %1$s - - Ба варақаҳои кушода, хатбаракҳо ва таърихи тамошокунӣ гузаред. - - Варакаҳои ботартиб ва соф - - Ба тартиб даровардани варақаҳо тавассути тарҳбандии беҳтаршуда ва пӯшидани варақаҳо ба таври худкор. - - Ҷустуҷӯҳои охирин - - - Ҷустуҷӯҳои охирини худро тавассути саҳифаи асосӣ ва варақаҳо боздид намоед. - - - Акнун саҳифаи асосии шахсишудаи шумо дар браузери Firefox бозгашти шуморо ба сомонаҳои охирин осон мекунад. Варақаҳо, хатбаракҳо ва натиҷаҳои ҷустуҷӯи охиринро ба даст оред. + + Ҷустуҷӯ дар ин дафъа: + + Ҷустуҷӯ дар ин дафъа дар: + + Бо саҳифаи асосии шахсии худ шинос шавед. Варақаҳо, хатбаракҳо ва натиҷаҳои ҷустуҷӯи охирин дар ин ҷо пайдо мешаванд. - Хуш омадед ба Интернети мустақил - Хуш омадед ба Интернети хусуситар Рангҳои бештар. Махфияти беҳтар. Худи ҳамон вазифадорӣ ба одамон, на ба даромадҳо. - Аз телефон ба ноутбук ба баръакс гузаред - Табдилдиҳии экранҳо боз ҳам осонтар шудааст Ҳамаи он ҷойҳоеро, ки шумо дар варақаҳо аз дастгоҳҳои дигар дидаед, дар саҳифаи асосии худ ба даст оред. @@ -306,6 +284,9 @@ Варақаҳои шумо ҳамоҳанг карда мешаванд! Ҳамаи он ҷойҳоеро, ки шумо дар дастгоҳи дигари худ дидаед, ба даст оред. + + Пӯшидан + Кушодани варақаи нави %1$s @@ -355,6 +336,14 @@ Илова кардани миёнбури тамошокунии хусусӣ Реҷаи «Танҳо HTTPS» + + + Маҳдудкунии баннери куки + + Маҳдуд кардани баннерҳои куки + + Браузери «Firefox» кӯшиш мекунад, ки дархостҳои кукиро дар баннерҳои куки ба таври худкор рад кунад. Агар имкони радкунӣ дастнорас аст, «Firefox» метавонад барои қатъ кардани баннер ҳамаи кукиҳоро қабул кунад. + Ба таври худкор кӯшиш мекунад, ки ба сомонаҳо бо истифода аз протоколи рамзгузории HTTPS барои баланд бардоштани амният пайваст шавад. @@ -394,8 +383,6 @@ Фармоишдиҳӣ - Ба воситаи ҳисоби Firefox-и худ хатбаракҳо, таърих ва чизҳои дигарро ҳамоҳанг кунед. - Барои ҳамоҳангсозии варақаҳо, хатбаракҳо, ниҳонвожаҳо ва чизҳои дигар, ворид шавед. Ҳисоби Firefox @@ -461,8 +448,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Дидашудаи охирин - Pocket + Pocket + + Ҳикояҳои андешаангез + + Мақолаҳои таъминшуда аз ҷониби «%s» Мақолаҳои сарпарастӣ @@ -485,12 +476,6 @@ Тасвири замина иваз карда нашуд Маълумоти бештар - - Тасвири заминаро бо зеркунии тамғаи саҳифаи асосии «Firefox» иваз намоед - - - Тамғаи «Firefox» - иваз кардани тасвири замина, тугма Классикӣ - %s @@ -589,8 +574,6 @@ Ба Mozilla иҷозат медиҳад, ки таҳқиқҳоро насб ва иҷро кунад - - Фаъол кардани ҳамоҳангсозӣ Ҳамоҳангсозӣ ва нигоҳ доштани маълумоти шумо @@ -651,6 +634,18 @@ Пӯшидан + + %d варақаро мекушоед? + + + Кушодани варақаҳои барзиёд метавонад кори «%s»-ро суст кунад, ҳангоме ки саҳифаҳо бор мешаванд. Шумо мутмаин ҳастед, ки мехоҳед идома диҳед? + + Кушодани равақаҳо + + Бекор кардан + %d сомона @@ -681,10 +676,6 @@ Рӯйхат Тӯр - - Гурӯҳҳои ҷустуҷӯ - - Сомонаҳои марбутро гурӯҳбандӣ кунед Пӯшидани варақаҳо @@ -808,9 +799,6 @@ %1$s (Реҷаи хусусӣ) - - Варақаҳои дигар - Вожаҳои ҷустуҷӯиро ворид намоед @@ -838,18 +826,6 @@ Ягон таърих нест - - Аз дастгоҳҳои дигар ҳамоҳанг карда шуд - - Аз дастгоҳҳои дигар - - - Барои дидани таърихи ҳамоҳангшуда аз дастгоҳҳои дигари худ ворид шавед. - - Ворид шудан - - Ё барои оғози ҳамоҳангсозӣ, ҳисоби Firefox-ро эҷод кунед]]> - Боргириҳо тоза шуданд @@ -879,13 +855,13 @@ - Шумо мутмаин ҳастед, ки мехоҳед ин ҷузвадонро нест намоед? + Шумо мутмаин ҳастед, ки мехоҳед ин ҷузвдонро нест намоед? %s ҷузъҳои интихобшударо нест мекунад. Бекор кардан - Илова кардани ҷузвадон + Илова кардани ҷузвдон Хатбарак нигоҳ дошта шуд! @@ -900,6 +876,10 @@ Кушодан дар варақаи нав Кушодан дар варақаи хусусӣ + + Ҳамаро дар варақаҳои нав кушодан + + Ҳамаро дар варақаҳои хусусӣ кушодан Нест кардан @@ -910,19 +890,19 @@ Таҳрир кардани хатбарак - Таҳрир кардани ҷузвадон + Таҳрир кардани ҷузвдон Барои дидани хатбаракҳои ҳамоҳангшуда ворид шавед Нишонии URL - ҶУЗВАДОН + ҶУЗВДОН НОМ - Илова кардани ҷузвадон + Илова кардани ҷузвдон - Интихоб кардани ҷузвадон + Интихоб кардани ҷузвдон Бояд унвон дошта бошад @@ -936,7 +916,7 @@ Хатбаракҳо нест карда шуданд - Несткунии ҷузвадонҳои интихобшуда + Несткунии ҷузвдонҳои интихобшуда БОТИЛ КАРДАН @@ -1079,6 +1059,10 @@ Мубодила кардан + + Нигоҳ доштан ҳамчун PDF + + Файли PDF эҷод карда нашуд Фиристодан ба дастгоҳ @@ -1090,9 +1074,11 @@ Ба ҳофизаи муваққатӣ нусха бардошта шуд - Барои ҳамоҳангсозӣ ворид шавед + Барои ҳамоҳангсозӣ ворид шавед Барои ҳамоҳангсозӣ ворид шавед + + Ҳамоҳангсозӣ ва нигоҳ доштани маълумот Фиристодан ба ҳамаи дастгоҳҳо @@ -1130,6 +1116,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Гузоштани %1$s ҳамчун браузери пешфарз + + Тамошокунии хусусиро озмоед + + Сомонаҳоро бе ягон куки ё таърихи нигоҳдошташуда дар «%1$s» тамошо кунед + Маҷмӯа нест карда шуд @@ -1221,8 +1213,6 @@ Баромадан - - Ин амал маълумоти тамошокуниро нест мекунад. Фосилаи вақте, ки нест карда мешавад @@ -1257,33 +1247,20 @@ Гурӯҳ нест карда шуд - - Хуш омадед ба «%s!» Хуш омадед ба Интернети беҳтар Браузере, ки барои мардум, на барои даромад сохта шудааст. - - Firefox-ро байни дастгоҳҳо ҳамоҳанг кунед Ба он ҷое, ки шумо ба қарибӣ тамошо кардаед, баргардонед - - Хатбаракҳо, таърих ва ниҳонвожаҳоро ба %1$s дар ин дастгоҳ интиқол диҳед. Барои гузариши бехалал байни экранҳои дастгоҳҳои худ, варақаҳо ва ниҳонвожаҳоро ҳамоҳанг созед. - - Бақайдгирӣ Ворид шудан Ҳамоҳангсозӣ фаъол аст - - Махфияти доимӣ Муҳофизати махфият ба таври пешфарз кор мекунад - - %1$s маъракаҳоеро, ки шуморо дар атрофи Интернет пинҳонӣ пайгирӣ мекунанд, ба таври худкор қатъ мекунад. Хусусияти «Муҳофизати пурра аз кукиҳо» васоити пайгириро аз истифодаи кукиҳо қатъ мекунад, то ки онҳо шуморо дар шабака ба таври пинҳонӣ пайгирӣ накунанд. @@ -1296,17 +1273,10 @@ Васоити пайгирии бештарро қатъ мекунад, то ки саҳифаҳо тезтар кушода шаванд, аммо баъзеи функсияҳои саҳифа метавонанд вайрон шаванд. Ҷойгиркунии навори абзорҳои худро интихоб кунед - - Навори абзорҳоро барои дастрасии осон дар наздикӣ ҷойгир намоед. Онро дар поён нигоҳ доред ё ба боло гузоред. Онро дар поён нигоҳ доред ё ба боло ҳаракат кунед. - - Махфияти шумо Шумо маълумоти худро идора мекунед - - Мо %s-ро ҳамин тавр тарҳрезӣ кардаем, ки шумо тавонед он чизҳоеро, ки дар онлайн ва бо мо мубодила мекунед, идора намоед. Браузери «Firefox» имкон медиҳад, ки шумо тавонед он чизҳоеро, ки дар онлайн ва бо мо мубодила мекунед, мустақилона идора намоед. @@ -1943,7 +1913,9 @@ Бештар омӯзед - Дар асоси Pocket кор мекунад. + Дар асоси Pocket кор мекунад. + + Аз ҷониби «%s» таъмин карда шудааст. Қисми оилаи Firefox.%s @@ -1957,4 +1929,14 @@ Гузариш ба танзимот Пешниҳоди Firefox + + + + печондан + + баркушодан + + барои гирифтани маълумоти бештар оид ба ин маҷмуа пайвандро кушоед + + мақоларо хонед diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml index 1a9accdf5..e24b18df1 100644 --- a/app/src/main/res/values-th/strings.xml +++ b/app/src/main/res/values-th/strings.xml @@ -14,6 +14,12 @@ ปิดใช้งานการเรียกดูแบบส่วนตัว ค้นหาหรือป้อนที่อยู่ + + ค้นหาประวัติ + + ค้นหาที่คั่นหน้า + + ค้นหาแท็บ ป้อนคำค้นหา @@ -38,9 +44,6 @@ เลือกแล้ว - - ที่คั่นหน้าล่าสุด - บันทึกไว้ล่าสุด @@ -128,13 +131,6 @@ แสดงปุ่มแท็บล่าสุดทั้งหมด - - การค้นหา \"%1$s\" ของคุณ - - - %d เว็บไซต์ ดูแท็บที่ซิงค์ทั้งหมด @@ -257,39 +253,17 @@ ตั้งค่าการค้นหา - - - มีอะไรใหม่ใน %1$s - - คุณสามารถกลับมาดูหน้าเว็บที่คุณดูค้างไว้ได้ง่ายขึ้นแล้ว - - หน้าแรกของ %1$s ที่ปรับแต่งแบบส่วนตัว - - ข้ามไปยังแท็บที่เปิดอยู่ ที่คั่นหน้า และประวัติการเรียกดู - - แท็บที่สะอาดและเป็นระเบียบ - - ขจัดความยุ่งเหยิงของแท็บด้วยเลย์เอาต์ที่ได้รับการปรับปรุงและแท็บที่ปิดอัตโนมัติ - - ผลค้นหาล่าสุด - - - เยี่ยมชมการค้นหาล่าสุดของคุณใหม่จากหน้าแรกและแท็บของคุณ - - - ขณะนี้หน้าแรกของ Firefox ที่ปรับแต่งแบบคุณได้รับการปรับปรุงให้คุณสามารถกลับมาดูหน้าเว็บที่คุณดูค้างไว้ได้ง่ายขึ้นแล้ว ค้นหาแท็บ ที่คั่นหน้า และผลการค้นหาล่าสุดของคุณ + + ครั้งนี้ค้นหา: + พบกับโฮมเพจส่วนบุคคลของคุณ แท็บล่าสุด ที่คั่นหน้า และผลการค้นหาจะปรากฏที่นี่ - ยินดีต้อนรับสู่อินเทอร์เน็ตที่เป็นอิสระ - ยินดีต้อนรับสู่อินเทอร์เน็ตที่เป็นส่วนตัวมากขึ้น สีสันที่มากขึ้น ความเป็นส่วนตัวที่ดีขึ้น ให้ความมุ่งมั่นกับผู้คนมากกว่าผลกำไร - สับเปลี่ยนไปมาระหว่างโทรศัพท์กับแล็ปท็อป - สลับหน้าจอง่ายกว่าที่เคย เรียกดูต่อจากที่คุณค้างไว้ด้วยแท็บจากอุปกรณ์อื่นๆ บนหน้าแรกของคุณได้แล้วตอนนี้ @@ -303,6 +277,9 @@ กำลังซิงค์แท็บของคุณ! เรียกดูต่อจากที่คุณค้างไว้บนอุปกรณ์อื่นๆ ของคุณ + + ปิด + เปิดแท็บ %1$s ใหม่ @@ -353,6 +330,7 @@ เพิ่มทางลัดการเรียกดูแบบส่วนตัว โหมด HTTPS-Only + พยายามเชื่อมต่อกับเว็บไซต์โดยใช้โปรโตคอลการเข้ารหัส HTTPS โดยอัตโนมัติเพื่อเพิ่มความปลอดภัย @@ -459,8 +437,12 @@ a section where users see a list of tabs that they have visited in the past few days --> เยี่ยมชมล่าสุด - Pocket + Pocket + + เรื่องราวที่จุดประกายความคิด + + บทความขับเคลื่อนโดย %s เรื่องราวที่ได้รับการสนับสนุน @@ -485,17 +467,16 @@ ไม่สามารถเปลี่ยนรูปพื้นหลัง เรียนรู้เพิ่มเติม - - เปลี่ยนวอลเปเปอร์โดยแตะโลโก้หน้าแรกของ Firefox - - โลโก้ Firefox - เปลี่ยนวอลเปเปอร์, ปุ่ม คลาสสิค %s เวลาจำกัด + + คอลเลกชันเสียงแห่งอิสระใหม่ %s + + คอลเลกชันเสียงแห่งอิสระใหม่ ลองเลือกสีสันที่คุณชอบ @@ -642,6 +623,17 @@ ปิด + + ต้องการเปิด %d แท็บหรือไม่? + + การเปิดแท็บจำนวนมากนี้อาจทำให้ %s ช้าลงขณะที่หน้ากำลังโหลด คุณแน่ใจหรือไม่ว่าต้องการดำเนินการต่อ? + + แท็บที่เปิด + + ยกเลิก + %d เว็บไซต์ @@ -671,10 +663,6 @@ รายการ เส้นตาราง - - ค้นหากลุ่ม - - จัดกลุ่มเว็บไซต์ที่เกี่ยวข้องกัน ปิดแท็บ @@ -827,19 +815,6 @@ ไม่มีประวัติที่นี่ - - ซิงค์จากอุปกรณ์อื่น - - จากอุปกรณ์อื่นๆ - - - ลงชื่อเข้าเพื่อดูประวัติที่ซิงค์จากอุปกรณ์อื่น ๆ ของคุณ - - ลงชื่อเข้า - - - หรือสร้างบัญชี Firefox เพื่อเริ่มซิงค์]]> - การดาวน์โหลดถูกลบ @@ -889,6 +864,10 @@ เปิดในแท็บใหม่ เปิดในแท็บส่วนตัว + + เปิดทั้งหมดในแท็บใหม่ + + เปิดทั้งหมดในแท็บส่วนตัว ลบ @@ -1065,6 +1044,10 @@ แบ่งปัน + + บันทึกเป็น PDF + + ไม่สามารถสร้าง PDF ส่งไปยังอุปกรณ์ @@ -1076,9 +1059,11 @@ คัดลอกไปยังคลิปบอร์ดแล้ว - ลงชื่อเข้าใช้เพื่อซิงค์ + ลงชื่อเข้าใช้เพื่อซิงค์ ลงชื่อเข้าไปยัง Sync + + ซิงค์และบันทึกข้อมูล ส่งไปยังอุปกรณ์ทั้งหมด @@ -1237,31 +1222,22 @@ ลบกลุ่มแล้ว - - ยินดีต้อนรับสู่ %s! ยินดีต้อนรับสู่อินเทอร์เน็ตที่ดีกว่า เบราว์เซอร์ที่สร้างขึ้นสำหรับผู้คนเท่านั้น ไม่ใช่ผลกำไร - - ซิงค์ Firefox ระหว่างอุปกรณ์ หยิบจากที่ที่คุณทำค้างไว้ - - นำที่คั่นหน้า ประวัติ และรหัสผ่านไปยัง %1$s บนอุปกรณ์นี้ - - ลงทะเบียน + + ซิงค์แท็บและรหัสผ่านระหว่างอุปกรณ์เพื่อการสลับหน้าจอที่ราบรื่น เข้าสู่ระบบ Sync เปิดอยู่ - - ความเป็นส่วนตัวตลอดเวลา การปกป้องความเป็นส่วนตัวตามค่าเริ่มต้น - - %1$s จะหยุดบริษัทต่าง ๆ ไม่ให้ติดตามคุณอย่างลับ ๆ ขณะที่คุณท่องเว็บโดยอัตโนมัติ + + มีการป้องกันคุกกี้ทั้งหมดเพื่อหยุดตัวติดตามไม่ให้ใช้คุกกี้ตามรอยคุณในไซต์ต่าง ๆ มาตรฐาน (ค่าเริ่มต้น) @@ -1272,15 +1248,12 @@ ปิดกั้นตัวติดตามเพิ่มเติมเพื่อให้โหลดหน้าเว็บได้เร็วขึ้น แต่การทำงานบางอย่างในหน้าเว็บอาจพัง เลือกตำแหน่งแถบเครื่องมือของคุณ - - วางแถบเครื่องมือไว้ใกล้ ๆ เก็บไว้ที่ด้านล่างหรือย้ายไปด้านบน - - ความเป็นส่วนตัวของคุณ + + เก็บไว้ด้านล่างหรือย้ายไปด้านบน คุณควบคุมข้อมูลของคุณ - - เราได้ออกแบบ %s เพื่อให้คุณสามารถควบคุมสิ่งที่คุณต้องการแบ่งปันออนไลน์และสิ่งที่คุณต้องการแบ่งปันกับเราได้ + + Firefox ให้คุณควบคุมสิ่งที่คุณแบ่งปันทางออนไลน์และสิ่งที่คุณแบ่งปันกับเรา อ่านประกาศความเป็นส่วนตัวของเรา @@ -1917,7 +1890,9 @@ ค้นพบสิ่งอื่น - ขับเคลื่อนโดย Pocket + ขับเคลื่อนโดย Pocket + + ขับเคลื่อนโดย %s ส่วนหนึ่งของตระกูล Firefox %s @@ -1931,4 +1906,14 @@ ไปยังการตั้งค่า Firefox Suggest + + + + ยุบ + + ขยาย + + เปิดลิงก์เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับคอลเลกชันนี้ + + อ่านบทความ diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index fc7b84b58..32b10f398 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -15,6 +15,12 @@ Gizli gezintiyi kapat Arama yap veya adres yaz + + Geçmişte ara + + Yer imlerinde ara + + Sekmelerde ara Aranacak terimleri yazın @@ -40,8 +46,6 @@ - Son yer imleri - Son kaydedilenler Tüm kayıtlı yer imlerini göster @@ -130,13 +134,6 @@ Son sekmeleri göster düğmesi - - \"%1$s\" aramanız - - - %d site Tüm eşitlenmiş sekmeleri gör @@ -259,39 +256,20 @@ Arama ayarları - - - %1$s tarayıcınızdaki yenilikler - - Kaldığınız yerden devam etmek artık daha kolay. - - Size özel %1$s giriş sayfası - - Açık sekmelerinizi, yer imlerinizi ve gezinti geçmişinizi görün. - - Düzenli sekmeler - - Yeni sekme düzeni ve kendiliğinden kapanan sekmelerle karmaşayı ortadan kaldırın. - - Son aramalar - - - Son aramalarınıza giriş sayfasından ve sekmelerden tekrar ulaşın. - - - Kişisel Firefox giriş sayfanız, kaldığınız yerden devam etmeyi kolaylaştırıyor. Son sekmeleriniz, yer imleriniz ve arama sonuçlarınız artık giriş sayfanızda. + + Bununla ara: + + Bununla ara: + + Size özel giriş sayfanızla tanışın. Son sekmeleriniz, yer imleriniz ve arama sonuçlarınız burada görünecek. - Bağımsız bir internete hoş geldiniz - Daha kişisel bir internete hoş geldiniz Daha renkli. Daha gizli. Para için değil, insanlık için. - Telefondan bilgisayara, bilgisayardan telefona geçin - Cihazdan cihaza geçmek artık daha kolay Diğer cihazlardaki sekmeleriniz artık giriş sayfanızda. @@ -305,6 +283,9 @@ Sekmeleriniz eşitleniyor! Diğer cihazınızda kaldığınız yerden devam edin. + + Kapat + Yeni %1$s sekmesi aç @@ -354,6 +335,14 @@ Gizli gezinti kısayolu ekle Yalnızca HTTPS modu + + + Çerez duyurularını azalt + + Çerez duyurularını azalt + + Firefox, çerez duyurularındaki çerez isteklerini otomatik olarak reddetmeye çalışır. Reddetme seçeneği mevcut değilse Firefox, duyuruyu kapatmak için tüm çerezleri kabul edebilir. + Daha fazla güvenlik için sitelere otomatik olarak HTTPS şifreleme protokolüyle bağlanmaya çalışır. @@ -393,8 +382,6 @@ Özelleştir - Firefox hesabınızı kullanarak yer imlerini, geçmişi ve daha fazlasını eşitleyin - Sekmeleri, yer imlerini, parolaları ve daha fazlasını eşitlemek için giriş yapın. Firefox Hesabı @@ -463,8 +450,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Son bakılanlar - Pocket + Pocket + + Merak uyandıran makaleler + + Makaleler %s tarafından derlenmektedir Sponsorlu haberler @@ -487,12 +478,6 @@ Duvar kâğıdı değiştirilemedi Daha fazla bilgi alın - - Giriş sayfasındaki Firefox logosuna dokunarak duvar kâğıdını değiştirin - - - Firefox logosu - duvar kağıdını değiştir, düğme Klasik %s @@ -590,8 +575,6 @@ Mozilla’nın araştırmalar yükleyip çalıştırmasına izin verir - - Sync’i etkinleştir Verilerinizi eşitleyin ve kaydedin @@ -652,6 +635,18 @@ Kapat + + %d sekme açılsın mı? + + Bu kadar çok sekme açmak, sayfalar yüklenirken %s tarayıcısını yavaşlatabilir. Devam etmek istediğinize emin misiniz? + + Sekmeleri aç + + + Vazgeç + %d site @@ -681,10 +676,6 @@ Liste Izgara - - Arama grupları - - İlgili siteleri gruplandırın Sekmeleri kapat @@ -810,9 +801,6 @@ %1$s (Gizli Mod) - - Diğer sekmeler - Aranacak terimleri yazın @@ -840,19 +828,6 @@ Geçmiş yok - - Diğer cihazlarla eşitlendi - - Diğer cihazlardan - - - Diğer cihazlarınızdan eşitlenen geçmişi görmek için giriş yapın. - - Giriş yap - - - Veya eşitlemeye başlamak için Firefox hesabı açın]]> - İndirmeler kaldırıldı @@ -902,6 +877,10 @@ Yeni sekmede aç Gizli sekmede aç + + Tümünü yeni sekmelerde aç + + Tümünü gizli sekmelerde aç Sil @@ -1079,6 +1058,10 @@ Paylaş + + PDF olarak kaydet + + PDF oluşturulamadı Cihaza gönder @@ -1090,9 +1073,11 @@ Panoya kopyalandı - Eşitlemek için giriş yap + Eşitlemek için giriş yap Sync’e giriş yap + + Verileri eşitle ve kaydet Tüm cihazlara gönder @@ -1129,6 +1114,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> %1$s varsayılan tarayıcınız olsun + + Gizli gezintiyi deneyin + + %1$s ile çerezleriniz ve geçmişiniz kaydedilmeden gezin + Koleksiyon silindi @@ -1218,8 +1209,6 @@ Çık - - Bu işlem tüm gezinti verilerinizi silecektir. Silinecek zaman aralığı @@ -1253,33 +1242,20 @@ Grup silindi - - %s’a hoş geldiniz! Daha iyi bir internete hoş geldiniz Para için değil, insanlık için geliştirilen bir tarayıcı. - - Firefox’u cihazlar arasında eşitleyin Kaldığınız yerden devam edin - - Yer imlerinizi, geçmişinizi ve parolalarınız bu cihazdaki %1$s tarayıcınıza taşıyın. Cihazlarınız arasında sorunsuz geçiş için sekmelerinizi ve parolalarınızı senkronize edin. - - Kaydol Giriş yap Sync açık - - Sürekli gizlilik Gizlilik koruması hep açık - - %1$s şirketlerin sizi web’de gizlice takip etmesini otomatik olarak engeller. Komple çerez koruması, takip kodlarının sizi web’de takip etmek için çerezleri kullanmasını engeller. @@ -1292,17 +1268,10 @@ Sayfaların daha hızlı yüklenmesi için daha fazla takipçiyi engeller ancak bazı sayfa işlevleri bozulabilir. Araç çubuğu konumunu seçin - - Araç çubuğunu kolayca erişilebileceğiniz bir yere koyun. Altta tutabilir veya en üste taşıyabilirsiniz. Altta tutun veya en üste taşıyın. - - Gizliliğiniz Verilerinizin kontrolü sizde - - %s, internette başkalarıyla ve bizimle neleri paylaşacağınızın kontrolünü size verir. Firefox, internette başkalarıyla ve bizimle neleri paylaşacağınızın kontrolünü size verir. @@ -1490,10 +1459,10 @@ Yapıştır ve git Yapıştır - + Adres panoya kopyalandı - + Ana ekrana ekle @@ -1939,7 +1908,9 @@ Daha fazlasını keşfedin - Pocket desteğiyle. + Pocket desteğiyle. + + %s desteğiyle. Firefox ailesinden. %s @@ -1953,4 +1924,14 @@ Ayarlara git Firefox Önerileri + + + + daralt + + genişlet + + bu koleksiyon hakkında daha fazla bilgi edinmek için bağlantıyı açın + + makaleyi oku diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3b03db096..e66942a7b 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -14,6 +14,12 @@ Вимкнути приватний перегляд Введіть запит чи адресу + + Шукати в історії + + Шукати в закладках + + Шукати у вкладках Введіть пошукові терміни @@ -39,8 +45,6 @@ - Останні закладки - Недавно збережені Показати всі збережені закладки @@ -129,13 +133,6 @@ Кнопка показу всіх останніх вкладок - - Результати пошуку \"%1$s\" - - - Сайтів: %d Переглянути всі синхронізовані вкладки @@ -260,38 +257,20 @@ Налаштування пошуку - - - Що нового у %1$s - - Тепер легше повернутися туди, де ви зупинилися. - - Персоналізована сторінка домівки %1$s - - Переходьте до відкритих вкладок, закладок та історії перегляду. - - Чисті, упорядковані вкладки - - Приберіть безлад у вкладках із вдосконаленим виглядом та автозакриттям вкладок. - - Недавні пошуки - - Перегляньте останні пошукові запити зі своєї сторінки домівки та вкладок. - - - Відтепер ваша персоналізована сторінка домівки Firefox полегшує продовження роботи з місця, де ви зупинилися. Знайдіть останні вкладки, закладки та результати пошуку. + + Шукати за допомогою: + + Шукати в: + + Зустрічайте свою персоналізовану домівку. Тут з’являтимуться останні вкладки, закладки та результати пошуку. - Вітаємо у незалежному інтернеті - Вітаємо у персоналізованому інтернеті Більше кольорів. Краща приватність. Та ж сама відданість людям, а не прибутку. - Перемикайтеся між телефоном і комп’ютером - Перемикати екрани стало простіше, ніж будь-коли Продовжуйте з того ж місця, де зупинилися, завдяки вкладкам з інших пристроїв, які відтепер доступні на вашій домашній сторінці. @@ -305,6 +284,9 @@ Ваші вкладки синхронізуються! Продовжте з того ж місця, де зупинилися на іншому пристрої. + + Закрити + Відкрити нову вкладку %1$s @@ -355,6 +337,14 @@ Додати ярлик приватного перегляду HTTPS-режим + + + Зменшення кількості банерів кук + + Зменшити кількість банерів кук + + Firefox автоматично намагається відхилити банери запитів на розміщення кук. Якщо параметр відхилення недоступний, Firefox може погодитися розмістити всі куки, щоб закрити банер. + Намагатися автоматично доступатися до сайтів за допомогою протоколу шифрування HTTPS для поліпшення безпеки. @@ -395,8 +385,6 @@ Пристосування - Синхронізуйте закладки, історію та інші дані з Обліковим записом Firefox - Увійдіть для синхронізації вкладок, закладок, паролів та інших даних. Обліковий запис Firefox @@ -466,8 +454,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Недавно відвідані - Pocket + Pocket + + Розповіді, що спонукають замислитися + + Пропоновані статті від %s Матеріали від спонсорів @@ -491,12 +483,6 @@ Не вдалося змінити шпалери Докладніше - - Змінювати шпалери торканням логотипу домівки Firefox - - - Логотип Firefox - змінити шпалери, кнопка Класичні %s @@ -595,8 +581,6 @@ Дозволяє Mozilla встановлювати та запускати дослідження - - Увімкнути синхронізацію Синхронізувати та зберегти дані @@ -657,6 +641,17 @@ Закрити + + Відкрити %d вкладок? + + Відкриття такої кількості вкладок може сповільнити %s поки вони завантажуватимуться. Ви дійсно хочете продовжити? + + Відкрити вкладки + + Скасувати + %d сайт @@ -686,10 +681,6 @@ Списком Сіткою - - Пошук груп - - Групуйте пов’язані сайти разом Закривати вкладки @@ -814,9 +805,6 @@ %1$s (Приватний режим) - - Інші вкладки - Введіть пошукові терміни @@ -845,18 +833,6 @@ Історія відсутня - - Синхронізовано з інших пристроїв - - З інших пристроїв - - - Увійдіть, щоб переглядати історію, синхронізовану з інших ваших пристроїв. - - Увійти - - Або створіть обліковий запис Firefox, щоб розпочати синхронізацію]]> - Завантаження вилучено @@ -906,6 +882,10 @@ Відкрити у новій вкладці Відкрити у приватній вкладці + + Відкрити всі у нових вкладках + + Відкрити всі у приватних вкладках Видалити @@ -1084,6 +1064,10 @@ Поділитися + + Зберегти як PDF + + Неможливо створити PDF Надіслати на пристрій @@ -1096,9 +1080,11 @@ Скопійовано у буфер обміну - Увійти до синхронізації + Увійти до синхронізації Увійти до Синхронізації + + Синхронізувати й зберегти дані Надіслати на всі пристрої @@ -1134,6 +1120,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Зробіть %1$s своїм типовим браузером + + Спробуйте приватний перегляд + + Переглядайте без збереження кук чи історії у %1$s + Збірку видалено @@ -1223,8 +1215,6 @@ Вихід - - Це видалить усі ваші дані перегляду. Проміжок часу для видалення @@ -1257,35 +1247,21 @@ Групу видалено - - Вітаємо в %s! - Ласкаво просимо до кращого інтернету Браузер, створений для людей, а не для прибутку. - - Синхронізуйте Firefox між пристроями Продовжуйте звідти, де зупинилися - - Перенесіть свої закладки, історію та паролі у %1$s на цьому пристрої. Синхронізуйте вкладки та паролі на всіх пристроях для плавного перемикання між ними. - - Зареєструватись Увійти Синхронізація увімкнена - - Постійна приватність Типовий захист приватності - - %1$s автоматично блокує таємне стеження компаній за вами в інтернеті. Функція повний захист кук не дає змогу елементам стеження переслідувати вас на різних сайтах за допомогою кук. @@ -1298,19 +1274,12 @@ Блокує більше стеження, тому сторінки завантажуються швидше, однак можливі порушення їх роботи. Оберіть розташування панелі інструментів - - Розташуйте панель для легкого доступу. Тримайте її внизу, або перемістіть вгору. Залиште її внизу або перемістіть угору. - - Ваша приватність Ви контролюєте свої дані - - Ми створили %s, щоб надати вам контроль над тим, чим ви ділитесь в Інтернеті та з нами. Firefox надає вам контроль над тим, чим ви ділитесь в інтернеті та з нами. @@ -1950,7 +1919,9 @@ Знайти більше - Надано Pocket. + Надано Pocket. + + Від %s. Частина родини Firefox. %s @@ -1964,4 +1935,14 @@ Перейти до налаштувань Пропозиції Firefox + + + + згорнути + + розгорнути + + відкрийте посилання, щоб дізнатися більше про цю збірку + + читати статтю diff --git a/app/src/main/res/values-uz/strings.xml b/app/src/main/res/values-uz/strings.xml index 3054c18aa..141e2ae56 100644 --- a/app/src/main/res/values-uz/strings.xml +++ b/app/src/main/res/values-uz/strings.xml @@ -15,6 +15,14 @@ Qidiring yoki manzilni kiriting + + Tarixdan qidirish + + Xatchoʻplar ichidan qidirish + + Varaqlar ichidan qidirish + + Qidiriladigan soʻzni kiriting Ochiq varaqlar shu yerda koʻrinadi. @@ -37,10 +45,13 @@ - Oxirgi xatchoʻplar + Yaqinda saqlangan Barcha saqlangan xatchoʻplarni koʻrsatish + + Olib tashlash + %1$s brauzerini @fork-maintainers ishlab chiqqan. @@ -58,11 +69,23 @@ Kerak emas + + + %1$sni ilovalarda avtomatik ravishda ochadigan qilib sozlashingiz mumkin. Sozlamalarni ochish Rad etish + + Rad qilish + + + + Bizning eng kuchli maxfiylik funksiyamiz saytlararo kuzatuvchilarni izolyatsiya qiladi. + + Umumiy Cookie himoyasi haqida batafsil + Kameradan foydalanish zarur. Android sozlamalariga oʻting, ruxsatnomalarga kiring va ruxsat berish tugmasini bosing. @@ -82,6 +105,9 @@ Sozlamalar orqali oʻchiring Bir oydan keyin avtomatik yopilsinmi? + + %1$s oxirgi oy davomida koʻrmagan varaqlarni yopishi mumkin. Yopish @@ -102,12 +128,16 @@ Barchasini koʻrsatish Barcha oxirgi varaqlarni koʻrsatish tugmasi - - \"%1$s\" uchun qidiruvingiz - - %d ta sayt + + + Barcha sinxronlangan varaqlarni qidirish + + Sinxronlangan qurilma + + Olib tashlash + + Olib tashlash Toʻgʻridan-toʻgʻri manzil panelidan qidiring - - Endi toʻxtagan joydan davom etish osonroq. - - Ochiq varaqlar, xatchoʻplar va tarixiga oʻting. - - Qulay tartibli varaqlar - - Yaxshilangan tartib va avtomatik yopiladigan varaqlar yordamida tartibsizliklarni toʻgʻrilang. - - Oxirgi qidiruvlar - - Bosh sahifa va varaqlar orqali oxirgi qidiruvlarga yana tashrif buyuring. - - - Moslashtirilgan Firefox bosh sahifasi endi toʻxtagan joydan davom etishni osonlashtiradi. Oxirgi varaqlar, xatchoʻplar va qidiruv natijalarini endi osongina topasiz. - + + Izlash sozlamalari + + + Bu safar qidiramiz: + + + Bu safar quyidagi bilan qidiramiz: + + + + Moshlashtirilgan bosh sahifangizni kutib oling. Oxirgi varaqlar, xatchoʻplar va qidiruv natijalar shu yerda chiqadi. + + Shaxsiy internetga xush kelibsiz + + Koʻplab ranglar. Yaxshiroq maxfiylik. Odamlarga foydali bir xil majburiyat. + + Ekranlarga oʻtish har doimgidan osonroq + + Endi bosh sahifangizda boshqa qurilmalardagi varaqlarda toʻxtagan joydan davom etasiz. Boshlash @@ -246,6 +280,9 @@ Varaqlar sinxronlanmoqda! Ishni qolgan joyidan boshqa qurilmada davom ettiring. + + Yopish + Yangi %1$s ta varaqni ochish @@ -295,6 +332,14 @@ Maxfiy koʻrish tezkor buyrugʻini qoʻshish Faqat HTTPS rejimi + + + Cookie bannerlarini kamaytirish + + Cookie bannerlarini kamaytirish + + Firefox avtomatik ravishda cookie bannerlarida cookie soʻrovlarini rad etishga harakat qiladi. Agar rad etish tanlovi mavjud boʻlmasa, Firefox bannerni oʻchirish uchun barcha cookie fayllarni qabul qilishi mumkin. + Xavfsizlikni oshirish uchun HTTPS shifrlash protokoli yordamida saytlarga avtomatik ulanishga harakat qiladi. @@ -335,8 +380,6 @@ Moslash - Xatchoʻplar va tarix kabilarni Firefox hisobingiz bilan sinxronlang - Varaq va xatchoʻplarni sinxronlash uchun hisobingizga kiring. Firefox hisobi @@ -403,8 +446,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Oxirgi ochilgan - Pocket + Pocket + + Oʻylantiruvchi hikoyalar + + %s maqolalari Homiy maqolalari @@ -419,11 +466,30 @@ Fon rasmi yangilandi! Koʻrish - - Firefox bosh sahifasi logotipiga teginish orqali fon rasmini oʻzgartiring - - Firefox logotipi – fon rasmi, tugmani oʻzgartiring + + + Fon rasmi yuklab olinmadi + + Qayta urining + + Fon rasmi oʻzgarmadi + + Batafsil maʼlumot + + + Klassik %s + + Cheklangan versiya + + Yangi “Mustaqil ovozlar” toʻplami. %s + + Yangi “Mustaqil ovozlar” toʻplami. + + Rangni chayqashga harakat qiling + + Didingizga mos fon rasmini tanlang. + + Boshqa fon rasmlarini koʻrish @@ -511,8 +577,6 @@ Mozillaga tadqiqotlarni oʻrnatish va ishga tushirish imkonini beradi - - Sinxronizatsiyani yoqish Maʼlumotlaringizni sinxronlang va saqlang @@ -572,6 +636,17 @@ Yopish + + %d ta varaq ochilsinmi? + + Koʻp varaqlarni ochish %s sahifalarini yuklash uchun ketadigan vaqtni choʻzishi mumkin. Rostdan ham buni qilishni xohlaysizmi? + + Varaqlarni ochish + + Bekor qilish + %d ta sayt @@ -602,10 +677,6 @@ Roʻyxat Jadval - - Guruhlarni qidirish - - Aloqador saytlarni birgalikda guruhlang Varaqlarni yopish @@ -655,28 +726,55 @@ Batafsil maʼlumot + + Oʻzgartirishlarni qoʻllash uchun ilova yopiladi + + OK + + Bekor qilish + + Oʻzgarishlarni qoʻllash uchun ilovadan chiqilmoqda… + Varaqlarni ochish Maxfiy varaqlar + + Sinxronlangan varaqlar Varaq qoʻshish Maxfiy varaq qoʻshish Maxfiy + + Sinxronizatsiya Barcha varaqlarni ulashish Yaqinda yopilgan varaqlar + + Yaqinda yopilgan + + Hisob sozlamalari Varaq sozlamalari Ichki varaqlarni yopish + + Xatchoʻp + + Yopish + + Tanlangan varaqlarni ulashish + + Tanlangan varaqlar menyusi Kolleksiyadan varaqni olib tashlash + + Varaqlarni tanlash Varaqni yopish @@ -692,13 +790,20 @@ Kolleksiya nomini oʻzgartirish Varaqlarni ochish - + + Toʻplam nomi + + Nomini oʻzgartirish + Olib tashlash Tarixdan oʻchirish %1$s (Maxfiy rejim) + + + Qidiriladigan soʻzni kiriting Tarixni oʻchirish @@ -710,6 +815,10 @@ Tanlandi: %1$d + + Bugun + + Kecha Soʻnggi 7 kun @@ -720,11 +829,22 @@ Tarix yoʻq + + + Yuklanmalar olib tashlandi + + %1$s olib tashlandi + + Yuklab olingan fayllar yoʻq Tanlandi: %1$d + + Olib tashlash + + Kechirasiz, %1$s bu sahifani yuklay olmadi. @@ -740,6 +860,8 @@ Bu jildni oʻchirishni xohlaysizmi? %s tanlangan elementlarni oʻchiradi. + + Bekor qilish Jild qoʻshish @@ -757,6 +879,10 @@ Yangi varaqda ochish Yangi maxfiy varaqda ochish + + Barchasini yangi varaqlarda ochish + + Barchasini maxfiy varaqlarda ochish Oʻchirish @@ -796,6 +922,9 @@ BEKOR QILISH + + Qidiriladigan soʻzni kiriting + Sozlamalarga oʻting @@ -807,8 +936,16 @@ Tavsiya qilinadi Ruxsatlarni tozalash + + OK + + Bekor qilish Ruxsatni tozalash + + OK + + Bekor qilish Barcha saytlardagi ruxsatlarni tozalash @@ -822,6 +959,12 @@ Manzil Bildirishnoma + + Doimiy xotira + + Saytlararo cookie fayllari + + DRM bilan himoyalangan kontent Ruxsat berishni soʻrang @@ -838,19 +981,30 @@ Oʻchiq Audio va videoga ruxsat berish + + Audio va videoga ruxsat berish Audio va video faqat mobil internetda bloklansin Audio va video faqat Wi-Fi yoniqligida ijro etilsin Faqat audioni bloklash + + Faqat audioni bloklash Audio va videoni bloklash + + Audio va videoni bloklash Yoniq Oʻchiq + + Yoniq + + Oʻchiq + Kolleksiyalar @@ -892,6 +1046,11 @@ Koʻrinishi + + OK + + Bekor qilish + Kolleksiya %d @@ -901,14 +1060,26 @@ Ulashish + + PDF sifatida saqlash + + PDF yaratilmadi Qurilmaga joʻnatish Barcha amallar Yaqinda ishlatilgan + + Vaqtinchalik xotiraga nusxalash + + Vaqtinchalik xotiraga nusxalalandi + + Sinxronlash uchun hisobingizga kiring Sinxronlash uchun hisobingizga kiring + + Sinxronizatsiya va maʼlumotlarni saqlash Barcha qurilmalarga joʻnatish @@ -936,6 +1107,15 @@ Maxfiy varaqlarni yopish + + Marketing + + %1$s tez va maxfiy + + %1$sni asosiy brauzer qiling + Kolleksiya oʻchirildi @@ -946,6 +1126,10 @@ Varaqlar yopildi + + Xatchoʻplar saqlandi! + + Yorliqlarga qoʻshildi! Maxfiy varaq yopildi @@ -961,6 +1145,10 @@ RUXSAT BERISH RAD ETISH + + Manzil xato kiritilgan. + + OK Siz %1$sni oʻchirishni xohlaysizmi? @@ -977,14 +1165,574 @@ Bu namuna matn. Bu sozlamalar yordamida hajmni kattalashtirish yoki kamaytirishda matn qanday koʻrinishini namoyish etadi. + + Veb-saytlardagi matnni kattaroq yoki kichikroq qiling + + Shrift hajmi + + + Avtomatik shrift hajmlari + + Shrift hajmi Android sozlamalaringizga mos keladi. Bu yerda shrift hajmini boshqarishni oʻchirib qoʻying. + + + Brauzer maʼlumotlarini oʻchirish + + Varaqlarni ochish + + %d ta varaq + + Brauzer tarixi va sayt maʼlumotlari + + %d ta manzil + + Cookie fayllar + + Koʻp saytlardan chiqib ketasiz + + Keshlangan rasmlar va fayllar + + Xotiradan boʻsh joy ochadi + + Sayt ruxsatlari + + Yuklanmalar + + Brauzer maʼlumotlarini oʻchirish + + Chiqish vaqtida brauzer maʼlumotlarini oʻchirish + + Asosiy menyudan \"Chiqish\"ni tanlaganingizda, brauzer maʼlumotlari avtomatik ravishda oʻchiriladi + + Chiqish + + + Oʻchirish uchun vaqt oraligʻi + + Tarixni (shu jumladan, boshqa qurilmalardan sinxronlangan tarixni), cookie-fayllarni va brauzer maʼlumotlarini oʻchirib tashlaydi. + + Oxirgi soat + + Bugun va kecha + + Hammasi + + + %s tanlangan brauzer maʼlumotlarini oʻchiradi. + + Bekor qilish + + Oʻchirish + + Brauzer maʼlumotlari oʻchirildi + + Brauzer maʼlumotlari oʻchirilmoqda… + + + “%s”dagi barcha saytlarni oʻchirish + + Bekor qilish + + Oʻchirish + + Guruh oʻchirildi + + + + Yaxshiroq internetga xush kelibsiz + + Foyda uchun emas, insonlar uchun tuzilgan brauzer. + + Qolgan joyidan davom eting + + Ekranlar oʻrtasida uzluksiz oʻtish uchun yorliqlar va parollarni qurilmalar oʻrtasida sinxronlang. + + Kirish + + Sinxronizatsiya yoqilgan + + Standart maxfiylik himoyasi + + Kuzatuvchilar sizni saytlar boʻylab kuzatish uchun cookie-fayllardan foydalanishiga yoʻl qoʻyilmaydi. + + Standart + + + Maxfiylik va samaradorlikning eng yaxshi muvozanatini taʼminlaydi. Sahifalar normal yuklanadi. + + Qatʼiy + + Sahifalar tezroq yuklanishi uchun koʻproq kuzatuvchilarni bloklaydi, lekin baʼzi sahifalar toʻgʻri ishlamasligi mumkin. + + Asboblar paneli joylashuvini tanlang + + Uni pastki qismida qoldiring yoki yuqoriga koʻchiring. + + Maʼlumotlaringizni oʻzingiz boshqaring + + Firefox sizga nimalarni onlayn va nimalarni bizga ulashishingiz uchun nazoratni sizga taqdim etadi. + + Maxfiylik toʻgʻrisidagi bildirishnomamizni oʻqing + + Qiziqarli internetni kashf etish uchun tayyormisiz? + + Koʻrishni boshlash + + + + Mavzungizni tanlang + + + Qorongʻi mavzu bilan batareya quvvati va koʻrish qobiliyatingizni asrang. + + Avtomatik + + Qurilmangiz sozlamalarga moslashadi + + Qorongʻi mavzu + + Yorqin mavzu + + + Varaqlar yuborildi! + + Varaq yuborildi! + + Yuborib boʻlmadi + + QAYTA URINING + + Kodni skanerlang + + https://firefox.com/pairga oʻting]]> + + Skanerlashga tayyor + + Kamera bilan tizimga kiring + + Buning oʻrniga e-pochtadan foydalaning + + + Unda yangisini yarating va Firefoxni qurilmalararo sinxronlang.]]> + + %s hisobingiz bilan sinxronlashni toʻxtatadi, ammo qurilmangizdagi brauzer tarixini oʻchirmaydi. + + Aloqani uzish + + Bekor qilish + + Standart jildlarni tahrirlash mumkin emas + + + + Himoya sozlamalari + + Takomillashtirilgan kuzatuvdan himoya + + Internetda iz qoldirmay kezing + + Maʼlumotlaringizni oʻzingiz uchun saqlang. Internetda sizni taqib qiladigan koʻplab kuzatuvchilardan %s himoya qiladi. + + + Batafsil + + Standart + + Maxfiylik va samaradorlikning eng yaxshi muvozanatini taʼminlaydi. Sahifalar normal yuklanadi. + + Standart kuzatuv muhofazasi orqali nimalar bloklangan? + + Qatʼiy + + Sahifalar tezroq yuklanishi uchun koʻproq kuzatuvchilarni bloklaydi, lekin baʼzi sahifalar toʻgʻri ishlamasligi mumkin. + + Qatʼiy kuzatuvdan himoya bilan nima bloklangan + + Boshqa + + Qaysi kuzatuvchilar va skriptlarni bloklashni tanlang. + + Maxsus kuzatuv vositasi bilan nimalar bloklangan + + + Cookie fayllar + + Saytlararo va ijtimoiy tarmoqlarning kuzatuvchilari + + Tashrif buyurilmagan saytlardan olingan cookie fayllar + + Barcha uchinchi tomon cookie fayllar (saytlarning buzilishiga olib kelishi mumkin) + + + Barcha cookie fayllar (saytlar ishlashini buzadi) + + Saytlararo cookie fayllarni izolyatsiyalash + + Tarkibni kuzatish + + Barcha varaqlarda + + Faqat maxsiy varaqlarda + + Kriptomaynerlar + + Raqamli imzo yigʻuvchilar + + Tafsilotlar + + Bloklangan + + Ruxsat berilgan + + Ijtimoiy tarmoq kuzatuvchilari + + + Ijtimoiy tarmoqlarning sahifadagi brauzeringiz faoliyatini kuzatib borish imkoniyatini cheklaydi. + + Saytlararo kuzatuvchi cookie fayllar + + Saytlararo cookie fayllar + + Reklama tarmoqlari va analitik kompaniyalar koʻplab saytlarda brauzer maʼlumotlarini yigʻish uchun foydalanadigan cookie fayllarni bloklaydi. + + + “Toʻliq cookie himoyasi” cookie fayllarni siz kirgan saytdan izolyatsiya qiladi, shuning uchun reklama tarmoqlari kabi kuzatuvchilar saytlarda sizni kuzatib borish uchun foydalana olmaydi. + + Kriptomaynerlar + + Raqamli valyutani yaratish uchun zararli skriptlarning qurilmangizga kirishiga yoʻl qoʻymaydi. + + Raqamli imzo yigʻuvchilar + + Qurilmangiz haqida kuzatib borish uchun ishlatilishi mumkin boʻlgan yagona aniqlanadigan maʼlumotlarni toʻplashni toʻxtatadi. + + Kontentni kuzatish + + Kuzatuv kodini oʻz ichiga olgan reklamalar, videolar va boshqa kontentni yuklashni toʻxtatadi. Baʼzi veb-saytlarning ishlashiga taʼsir qilishi mumkin. + + + Ushbu sayt uchun himoya yoqilgan + + Ushbu sayt uchun himoya oʻchirilgan + + Ushbu sayt uchun takomillashtirilgan kuzatuvdan himoya oʻchirilgan. + + Orqaga oʻting + + %sdagi yangiliklar + + %s | OSS kutubxonlari + + Qayta yoʻnaltiruvchi kuzatuvchilar + + Maʼlum kuzatuv saytlariga yoʻnaltirish orqali oʻrnatilgan cookie fayllarini oʻchiradi. + + + Quyida belgilangan ayrim kuzatuvchilar ushbu sahifada qisman ochilgan, chunki siz ular bilan muloqot qilgansiz *. + + Batafsil maʼlumot + + + Qoʻllab-quvvatlash + + Nosozliklar + + Maxfiylik eslatmalari + + Huquqlaringizni biling + + Litsenziya maʼlumotlari + + Biz foydalanadigan kutubxonalar + + Nosozliklarni tuzatish menyusi: faollashtirish uchun %1$d tugmachani bosing + Nosozliklarni tuzatish menyusi yoqilgan + + + + Nusxa olish + + Qoʻyish va oʻtish + + Qoʻyish + + URL buferga koʻchirildi + + + Bosh ekranga qoʻshish + + Bekor qilish + + Qoʻshish + + Saytga oʻting + + Yorliq nomi + + + Tez kirish uchun ushbu saytni qurilmangizning bosh ekraniga osongina qoʻshishingiz mumkin. + + + Login va parollar + + Login va parollarni saqlang + + Saqlash soʻralsin + + Hech qachon saqlanmasin + + %1$sda avtomatik toʻldirilsin + + %1$s dan foydalanganda saytlarda foydalanuvchi nomlari va parollarni toʻldiring va saqlang. + + Boshqa ilovalarda avtomatik toʻldirish + + Qurilmangizdagi boshqa ilovalarda foydalanuvchi nomlari va parollarni kiriting. + + Login qoʻshish + + + Loginlarni sinxronlash + + Loginlarni qurilmalararo sinxronlang + + Saqlangan loginlar + + Siz saqlagan yoki %s bilan sinxronlangan loginlar shu yerda koʻrinadi. + + Sinxronlash haqida batafsil maʼlumot + + Istisnolar + + Saqlanmagan login va parollar shu yerda koʻrsatiladi. + + Ushbu saytlar uchun login va parollar saqlanmaydi. + + Barcha istisnolarni oʻchirib tashlash + + Loginlarni qidirish + + Sayt + + Foydalanuvchi nomi + + Parol + + Parol buferga nusxalandi + + Foydalanuvchi nomi buferga nusxalandi + + Paroldan nusxa olish + + Parolni tozalash + + Foydalanuvchi nomidan nusxa olish + + Foydalanuvchi nomini tozalash + + Host nomini tozalash + + Saytni brauzerda ochish + + Parolni koʻrsatish + + Parolni yashirish + + Saqlangan loginlaringizni koʻrish uchun qulfni oching + + Login va parollaringizni himoya qiling + + Saqlangan login va parollaringizni kimdir qurilmangizga ega boʻlsa, ularga kirishdan himoya qilish uchun qurilmani qulflang, PIN kod yoki parol oʻrnating. + + Keyinroq + + Hoziroq sozlash + + Qurilmangizning qulfini oching Barcha veb-saytlarni kattalashtirish Bu ishorani taqiqlovchi saytlar uchun ham chimdish va kattalashtirishga ruxsat berishni yoqing. + + Nomi boʻyicha (A-Z) + + Soʻnggi foydalanilgan + + Loginlarni saralash menyusi + + + + Avtomatik toʻldirish + + Manzillar + + Kredit kartalar + + Kartalarni saqlash va avtomatik toʻldirish + + Maʼlumotlar shifrlangan + + Kartalarni qurilmalar oʻrtasida sinxronlash + + Kartalarni sinxronlash + + Kredit karta qoʻshish + + Saqlangan kartalarni boshqarish + + Manzil qoʻshish + + Manzillarni boshqarish + + Manzillarni saqlash va avtomatik toʻldirish + + Raqamlar, email va yetkazib berish manzillari kabi maʼlumotlar ham kiradi + + + Karta qoʻshish + + Kartani tahrirlash + + Karta raqami + + Muddati + + + Tugash muddati sanasi va oyi + + Tugash muddati yili + + Karta egasi nomi + + Kartani oʻchirish + + Kartani oʻchirish + + + Haqiqatan ham bu kredit kartani oʻchirib tashlamoqchimisiz? + + Oʻchirish + + Saqlash + + Saqlash + + Bekor qilish + + Saqlangan kartalar + + Yaroqli kredit karta raqamini kiriting + + Ushbu maydonni toʻldiring + + Saqlangan kartalaringizni koʻrish uchun qulfni oching + + Kredit kartalaringizni himoya qiling + + Agar qurilmangiz boshqa birovda boʻlsa, saqlangan kredit kartalaringizga kirishdan himoya qilish uchun qurilmani qulflash uchun grafik kalit, PIN kod yoki parolni sozlang. + + Hozir sozlash + + Keyinroq + + Qurilmangizning qulfini oching + + Saqlangan kredit karta maʼlumotlaridan foydalanish uchun qulfni oching + + Manzil qoʻshish + + Manzilni tahrirlash + + Manzillarni boshqarish + + Ismi + + Otasining ismi + + Familiyasi + + Koʻcha manzili + + Shahar + + Shtat + + Viloyat + + Pochta indeksi + + Mamlakat yoki mintaqa + + Telefon + + Email + + Saqlash + + Bekor qilish + + Manzilni oʻchirish + + Haqiqatan ham bu manzilni oʻchirib tashlamoqchimisiz? + + Oʻchirish + + Bekor qilish + + Manzilni saqlash + + Manzilni oʻchirish + + + Qidiruv tizimini qoʻshish + + Qidiruv tizimini tahrirlash + + Qoʻshish + + Saqlash + + Tahrirlash + + Oʻchirish + + + Boshqa + + Nomi + + Foydalanish uchun qidiruv qatori Soʻrovni “%s” bilan almashtiring. Masalan:\nhttps://www.google.com/search?q=%s + + Maxsus qidiruv tizimining tafsilotlari + + + Qidiruv tizimi nomini kiriting + + + Qidiruv qatorini kiriting + + Qidiruv qatorining Namuna formatiga mos kelishini tekshiring + + + “%s”ga ulanishda xatolik yuz berdi + + %s yaratildi + + + %s saqlandi + + + %s oʻchirildi + Ruxsat berish uchun: @@ -994,6 +1742,14 @@ %1$sYONIQ ustiga bosing]]> + + Ulanish xavfsiz + + Ulanish xavfsiz emas + + Cookie va sayt maʼlumotlarini tozalash + + %s saytining barcha cookie fayllari va maʼlumotlarini oʻchirib tashlashni istaysizmi?]]> Barcha saytlarga berilgan barcha ruxsatlarni olib tashlashni xoxhlaysizmi? @@ -1004,6 +1760,10 @@ Hech qanday sayt istisnolarisiz Bu xatchoʻpni oʻchirishni xohlaysizmi? + + Yorliqlarga qoʻshish + + Yorliqlardan olib tashlash Tekshiruvchi: %1$s @@ -1015,6 +1775,8 @@ Bu loginni oʻchirishni xohlaysizmi? Oʻchirish + + Bekor qilish Login parametrlari @@ -1028,8 +1790,14 @@ Oʻzgarishlarni loginga saqlash Tahrirlash + + Yangi login qoʻshish Parol kiritish kerak + + Foydalanuvchi nomi kerak + + Host nomi kerak Ovozli qidiruv @@ -1037,6 +1805,13 @@ Shu nomdagi login oldindan bor + + https://www.example.com + + Veb manzilda "https://" yoki "http://" boʻlishi kerak + + Host nomi xatosiz kiritilishi kerak + Boshqa qurilmani ulash @@ -1051,7 +1826,106 @@ Sinxronlash uchun hisobingizga kiring + + Ochiq varaqlar yoʻq + + Sinxronlangan yorliqlar guruhini kengaytirish + + Sinxronlangan yorliqlar guruhini yigʻish + + + + Yorliqlar chekloviga yetdi + + Yangi yorliq qoʻshish uchun eskilaridan birini olib tashlang. Saytni bosib turing va oʻchirishni tanlang. OK, tushundim - + + Yorliqlar + + Nomi + + + Yorliq nomi + + OK + + Bekor qilish + + Sozlamalar + + Bizning homiylarimiz va sizning maxfiyligingiz + + Homiylik qilgan + + + + Nofaol varaqlar + + Barcha nofaol varaqlarni yopish + + + Nofaol varaqlarni yoyish + + Nofaol varaqlarni yigʻish + + + + Bir oydan keyin avtomatik yopilsinmi? + + Oʻtgan oy ochilmagan varaqlarni Firefox yopishi mumkin. + + AVTOMATIK YOPISHNI YOQISH + + Avtomatik yoqish yoniq + + + Saytlar, elektron pochta va xabarlar havolalarini Firefoxda avtomatik ravishda ochiladigan qilib sozlang. + + + Olib tashlash + + + Batafsil axborot uchun bosing + + + Yuqoriga oʻtish + + + Yopish + + + + Oʻylantiruvchi hikoyalar + + Mavzu boʻyicha hikoyalar + + Koʻproq bilib oling + + Pocket tomonidan quvvatlanadi. + + %s tomonidan quvvatlanadi. + + Firefox oilasining bir qismi hisoblanadi. %s + + Batafsil ma’lumot + + Homiylik qilgan + + + Maʼlumotlarni yuborish uchun telemetriyani yoqing. + + Sozlamalarni ochish + Firefox Suggest + + + + + + yigʻish + + ushbu kolleksiya haqida koʻproq maʼlumot olish uchun havolani oching + + maqolani oʻqish + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index b60038145..551d6650c 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -15,6 +15,12 @@ Tắt duyệt web riêng tư Tìm kiếm hoặc nhập địa chỉ + + Tìm kiếm lịch sử + + Tìm kiếm dấu trang + + Tìm kiếm thẻ Nhập từ tìm kiếm @@ -40,8 +46,6 @@ - Dấu trang gần đây - Đã lưu gần đây Hiển thị tất cả các dấu trang đã lưu @@ -130,13 +134,6 @@ Hiển thị nút tất cả các thẻ gần đây - - Tìm kiếm của bạn cho \"%1$s\" - - - %d trang web Xem các thẻ đã đồng bộ hóa @@ -257,38 +254,20 @@ Cài đặt tìm kiếm - - - Có gì mới trong %1$s - - Giờ đây, việc tiếp tục nơi bạn đã dừng lại sẽ trở nên dễ dàng hơn. - - Trang chủ %1$s được cá nhân hóa - - Chuyển đến các thẻ đang mở, dấu trang và lịch sử duyệt web của bạn. - - Các thẻ gọn gàng, có tổ chức - - Xóa các thẻ lộn xộn với bố cục được cải thiện và tự động đóng các thẻ. - - Tìm kiếm gần đây - - Xem lại các tìm kiếm mới nhất của bạn từ trang chủ và các thẻ của bạn. - - - Trang chủ Firefox được cá nhân hóa của bạn giờ đây giúp bạn tiếp tục lại nơi bạn đã dừng lại dễ dàng hơn. Tìm các thẻ, dấu trang và kết quả tìm kiếm gần đây của bạn. + + Lần này tìm kiếm: + + Lần này tìm kiếm trong: + + Gặp gỡ trang chủ được cá nhân hóa của bạn. Các thẻ, dấu trang và kết quả tìm kiếm gần đây sẽ xuất hiện ở đây. - Chào mừng bạn đến với internet độc lập - Chào mừng bạn đến với một Internet cá nhân hơn Màu sắc mới. Riêng tư hơn. Cùng cam kết với mọi người vì lợi nhuận. - Chuyển từ điện thoại sang máy tính xách tay và ngược lại - Chuyển đổi màn hình dễ dàng hơn bao giờ hết Tiếp tục nơi bạn đã dừng lại với các thẻ từ các thiết bị khác ngay bây giờ trên trang chủ của bạn. @@ -302,6 +281,9 @@ Các thẻ của bạn đang đồng bộ hóa! Tiếp tục nơi bạn đã dừng lại trên thiết bị khác của mình. + + Đóng + Mở thẻ %1$s mới @@ -351,6 +333,14 @@ Thêm lối tắt duyệt web riêng tư Chế độ chỉ HTTPS + + + Giảm biểu ngữ cookie + + Giảm biểu ngữ cookie + + Firefox tự động cố gắng từ chối yêu cầu cookie trên biểu ngữ cookie. Nếu không có tùy chọn từ chối, Firefox có thể chấp nhận tất cả cookie để loại bỏ biểu ngữ. + Tự động cố gắng kết nối với các trang web bằng giao thức mã hóa HTTPS để tăng cường bảo mật. @@ -390,8 +380,6 @@ Tùy biến - Đồng bộ hóa dấu trang, lịch sử và hơn thế nữa với tài khoản Firefox của bạn - Đăng nhập để đồng bộ các thẻ, dấu trang, mật khẩu, v.v. Tài khoản Firefox @@ -459,8 +447,12 @@ a section where users see a list of tabs that they have visited in the past few days --> Đã xem gần đây - Pocket + Pocket + + Những câu chuyện kích động tư tưởng + + Các bài báo được cung cấp bởi %s Câu chuyện được tài trợ @@ -483,12 +475,6 @@ Không thể thay đổi hình nền Tìm hiểu thêm - - Thay đổi hình nền bằng cách nhấn vào biểu trưng trang chủ của Firefox - - - Logo Firefox - thay đổi hình nền, nút %s cổ điển @@ -586,8 +572,6 @@ Cho phép Mozilla cài đặt và chạy các nghiên cứu - - Bật đồng bộ hóa Đồng bộ hóa và lưu dữ liệu của bạn @@ -647,6 +631,17 @@ Đóng + + Mở %d thẻ? + + Việc mở nhiều thẻ này có thể làm chậm %s trong khi các trang đang tải. Bạn có chắc chắn muốn tiếp tục không? + + Mở các thẻ + + Hủy bỏ + %d trang web @@ -676,10 +671,6 @@ Danh sách Lưới - - Tìm kiếm nhóm - - Nhóm các trang web liên quan lại với nhau Đóng thẻ @@ -803,9 +794,6 @@ %1$s (Chế độ riêng tư) - - Các thẻ khác - Nhập từ tìm kiếm @@ -833,18 +821,6 @@ Không có lịch sử ở đây - - Được đồng bộ hóa từ thiết bị khác - - Từ các thiết bị khác - - - Đăng nhập để xem lịch sử được đồng bộ hóa từ các thiết bị khác của bạn. - - Đăng nhập - - Hoặc tạo tài khoản Firefox để bắt đầu đồng bộ hóa]]> - Đã xóa tải xuống @@ -894,6 +870,10 @@ Mở trong thẻ mới Mở trong thẻ riêng tư + + Mở tất cả trong các thẻ mới + + Mở tất cả trong các thẻ riêng tư Xóa @@ -1071,6 +1051,10 @@ Chia sẻ + + Lưu dưới dạng PDF + + Không thể tạo PDF Gửi đến thiết bị @@ -1082,9 +1066,11 @@ Đã sao chép vào khay nhớ tạm - Đăng nhập vào đồng bộ hóa + Đăng nhập vào đồng bộ hóa Đăng nhập vào đồng bộ hóa + + Đồng bộ hóa và lưu dữ liệu Gửi đến tất cả các thiết bị @@ -1120,6 +1106,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> Đặt %1$s làm trình duyệt mặc định của bạn + + Thử duyệt web riêng tư + + Duyệt mà không để lại lịch sử hoặc cookie trong %1$s + Đã xóa bộ sưu tập @@ -1208,8 +1200,6 @@ Thoát - - Điều này sẽ xóa tất cả dữ liệu duyệt web của bạn. Khoảng thời gian để xóa @@ -1242,33 +1232,20 @@ Đã xóa nhóm - - Chào mừng đến với %s! Chào mừng bạn đến với một internet tốt hơn Một trình duyệt được xây dựng cho mọi người, không vì lợi nhuận. - - Đồng bộ hóa Firefox giữa các thiết bị Tiếp tục trang mà bạn vừa rời khỏi - - Mang dấu trang, lịch sử và mật khẩu vào %1$s trên thiết bị này. Đồng bộ hóa các thẻ và mật khẩu trên các thiết bị để chuyển đổi màn hình liền mạch. - - Đăng ký Đăng nhập Đồng bộ hóa được bật - - Luôn bảo vệ quyền riêng tư Bảo vệ quyền riêng tư theo mặc định - - %1$s tự động ngăn các công ty bí mật theo dõi bạn trên web. Trình chống cookie chung ngăn trình theo dõi sử dụng cookie để theo dõi bạn trên các trang web. @@ -1281,17 +1258,10 @@ Chặn nhiều trình theo dõi hơn để các trang tải nhanh hơn, nhưng một số trên trang có thể bị hỏng về mặt chức năng. Chọn vị trí thanh công cụ của bạn - - Đặt thanh công cụ trong tầm với. Giữ nó ở dưới cùng hoặc di chuyển nó lên trên cùng. Giữ nó ở dưới cùng hoặc di chuyển nó lên trên cùng. - - Quyền riêng tư của bạn Bạn kiểm soát dữ liệu của mình - - Chúng tôi đã thiết kế %s để cung cấp cho bạn quyền kiểm soát những gì bạn chia sẻ trực tuyến và những gì bạn chia sẻ với chúng tôi. Firefox cho phép bạn kiểm soát những gì bạn chia sẻ trực tuyến và những gì bạn chia sẻ với chúng tôi. @@ -1925,7 +1895,9 @@ Khám phá thêm nữa - Được cung cấp bởi Pocket. + Được cung cấp bởi Pocket. + + Được cung cấp bởi %s. Một phần của gia đình Firefox. %s @@ -1939,4 +1911,14 @@ Đi đến cài đặt Đề xuất của Firefox + + + + thu gọn + + mở rộng + + mở liên kết để tìm hiểu thêm về bộ sưu tập này + + đọc bài viết diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9e5147942..8ab0cb044 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -18,6 +18,12 @@ 搜索或输入网址 + + 搜索历史记录 + + 搜索书签 + + 搜索标签页 输入搜索词 @@ -44,8 +50,6 @@ - 最近的书签 - 最近保存 显示所有保存书签 @@ -133,13 +137,6 @@ 显示所有近期标签页按钮 - - “%1$s”的搜索结果 - - - %d 个网站 查看所有同步的标签页 @@ -266,40 +263,20 @@ 搜索设置 - - - %1$s 新版变化 - - 现在可以更轻松地从上次中断的地方继续浏览。 - - - 个性化的 %1$s 主页 - - 跳转到您打开的标签页、书签和浏览历史。 - - - 简洁有序的标签页 - - 改进的布局和自动关闭标签页,消除标签页混乱。 - - 最近的搜索 - - 从主页和标签页快速访问您的上次搜索。 - - - 个性化的 Firefox 主页,让您可以更轻松地从上次中断的地方继续浏览。快速找到您最近打开的标签页、书签和搜索结果。 + + 这次搜索: + + 此次搜索: + + 认识您的个性化主页。这里将显示最近的标签页、书签和搜索结果。 - 欢迎开启不受巨头左右的互联网世界 - 欢迎进入更个性化的互联网 更靓、更保护隐私,但始终不变的是以人为本的承诺。 - 全平台快速切换 - 多屏切换更顺手 您现在从主页就可以继续浏览其他设备上的标签页。 @@ -313,6 +290,9 @@ 标签页正在同步!您可在另一设备上继续浏览。 + + 关闭 + 新建 %1$s 标签页 @@ -363,6 +343,14 @@ 添加隐私浏览快捷方式 HTTPS-Only 模式 + + + 减少 Cookie 横幅 + + 减少 Cookie 横幅 + + Firefox 会自动尝试点击 Cookie 横幅上的“拒绝”按钮。若网站未提供拒绝选项,则可能会接受所有 Cookie 以关闭横幅。 + 自动尝试使用 HTTPS 加密协议连接至网站,增强安全性。 @@ -470,8 +458,12 @@ a section where users see a list of tabs that they have visited in the past few days --> 最近访问 - Pocket + Pocket + + 精选文章 + + 由 %s 提供的文章 赞助内容 @@ -496,12 +488,6 @@ 无法更换壁纸 详细了解 - - 点按 Firefox 主页徽标以更换壁纸 - - - Firefox 徽标 - 也是更换壁纸的按钮 %s 经典 @@ -664,6 +650,17 @@ 关闭 + + 要打开这 %d 个标签页吗? + + 一并载入太多页面可能会减慢 %s 的运行。您确定要一并打开吗? + + 打开标签页 + + 取消 + %d 个网站 @@ -693,10 +690,6 @@ 列表 网格 - - 搜索分组 - - 将有关联的网站分组归并 关闭标签页 @@ -851,18 +844,6 @@ 无历史记录 - - 同步自其他设备 - - 来自其他设备 - - - 登录以查看同步自您其他设备的历史记录。 - - 登录 - - 或创建 Firefox 账户进行同步]]> - 下载记录已清除 @@ -914,6 +895,10 @@ 新建标签页打开 新建隐私标签页打开 + + 新建标签页全部打开 + + 新建隐私标签页全部打开 删除 @@ -1106,6 +1091,10 @@ 分享 + + 保存为 PDF + + 无法生成 PDF 发送到设备 @@ -1117,9 +1106,11 @@ 已复制到剪贴板 - 登录同步服务 + 登录同步服务 登录同步服务 + + 同步并保存数据 发送到所有设备 @@ -1157,6 +1148,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> 将 %1$s 设为默认浏览器 + + 试用隐私浏览功能 + + %1$s 将不会保存浏览期间的 Cookie 和历史记录 + 收藏集已删除 @@ -1286,33 +1283,20 @@ 已删除分组 - - 欢迎使用 %s! 欢迎进入更美好的互联网 生为民,不谋利的浏览器。 - - 在设备之间同步 Firefox 从上次看到的地方继续 - - 将 %1$s 的书签、历史记录和密码带到此设备。 跨设备同步标签页和密码,实现无缝浏览体验。 - - 注册 登录 同步已开启 - - 隐私与您同行 默认启用隐私保护 - - %1$s 会自动阻止大公司在网上偷偷跟踪您。 “全方位 Cookie 保护”功能可阻止跟踪器借 Cookie 跨站跟踪您。 @@ -1325,17 +1309,10 @@ 拦截更多跟踪器,页面加载更快,但可能导致页面上某些功能异常。 选择您的工具栏位置 - - 将工具栏放在顺手的位置。可以留在底部,或移到顶部。 将工具栏置于底部,或移至顶部。 - - 您的隐私权 数据由自己掌控 - - %s 的设计旨在让您可以控制要在网上披露哪些内容,以及告诉我们哪些信息。 Firefox 让您可以控制要在网上披露哪些内容,以及告诉我们哪些信息。 @@ -1373,7 +1350,7 @@ https://firefox.com/pair]]> - 扫描就绪 + 立即扫码 使用相机登录 @@ -1523,10 +1500,10 @@ 粘贴并前往 粘贴 - + 网址已复制到剪贴板 - + 添加到主屏幕 @@ -1974,7 +1951,9 @@ 探索更多 - 由 Pocket 提供 + 由 Pocket 提供 + + 由 %s 提供。 Firefox 系列产品。%s @@ -1988,4 +1967,14 @@ 前往设置 Firefox 建议 + + + + 折叠 + + 展开 + + 访问链接了解此壁纸集的更多信息 + + 阅读文章 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index dafae6f59..9e3789ef7 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -18,6 +18,12 @@ 搜尋或輸入網址 + + 搜尋紀錄 + + 搜尋書籤 + + 搜尋分頁 輸入搜尋詞彙 @@ -43,8 +49,6 @@ - 最近加入的書籤 - 最近儲存 顯示所有儲存書籤 @@ -131,13 +135,6 @@ 顯示所有近期分頁按鈕 - - 「%1$s」的搜尋結果 - - - %d 個網站 檢視所有同步的分頁 @@ -262,38 +259,20 @@ 搜尋設定 - - - %1$s 有什麼新鮮事 - - 更簡單就能回到上次中斷的地方繼續上網。 - - 個人化的 %1$s 首頁 - - 跳到您開啟的分頁、書籤、上網紀錄等。 - - 精簡有條理的分頁標籤 - - 透過改善過的版面設計與自動關閉閒置分頁功能,解決分頁雜亂的問題。 - - 最近搜尋內容 - - 從首頁與分頁快速重新造訪先前的搜尋結果。 - - - 現在起,有您的風格的 Firefox 首頁,可讓您更簡單就從上次結束瀏覽的地方繼續上網。快速找到您最近開啟的分頁、書籤、搜尋結果等分頁。 + + 這次搜尋使用: + + 這次搜尋: + + 了解您的個人化首頁。這裡將顯示最近開啟過的分頁、書籤、搜尋結果。 - 歡迎來到一個更加獨立的網路環境 - 歡迎使用更加個人化的網頁瀏覽器 更多色彩、更加保護您的隱私,依然承諾把人們看得比利益更重要。 - 在手機與筆電間快速切換 - 切換畫面變得更容易 現在起,直接從首頁就可以繼續瀏覽其他裝置上開啟的分頁。 @@ -307,6 +286,9 @@ 分頁同步中!繼續瀏覽其他裝置上開啟的分頁。 + + 關閉 + 開啟新 %1$s 分頁 @@ -357,6 +339,14 @@ 新增隱私瀏覽模式捷徑 純 HTTPS 模式 + + + 減少 Cookie 橫幅 + + 減少 Cookie 橫幅 + + Firefox 會自動嘗試為您點擊 Cookie 橫幅上的「拒絕」按鈕。若網站未提供拒絕選向,可能還是會接受所有 Cookie 來讓橫幅消失。 + 自動嘗試使用加密過的 HTTPS 通訊協定連線到網站,以增加安全性。 @@ -465,8 +455,12 @@ a section where users see a list of tabs that they have visited in the past few days --> 最近造訪 - Pocket + Pocket + + 發人深省的文章 + + 由 %s 提供的文章 贊助內容 @@ -490,12 +484,6 @@ 無法變更背景圖 了解更多 - - 點擊 Firefox 首頁的圖示即可更改背景圖 - - - Firefox 圖示,點擊此圖示變更背景圖 經典 %s @@ -654,6 +642,17 @@ 關閉 + + 要一次開啟 %d 個分頁嗎? + + 一次開啟這麼多分頁會使 %s 於載入頁面時變得很慢。您確定要繼續嗎? + + 開啟分頁 + + 取消 + %d 個網站 @@ -684,10 +683,6 @@ 清單 格線 - - 搜尋分頁群組 - - 將相關的網站放在一起 自動關閉分頁 @@ -841,19 +836,6 @@ 沒有紀錄 - - 從其他裝置同步過來 - - - 來自其他裝置 - - - 登入以檢視您其他裝置中的瀏覽紀錄。 - - 登入 - - 或註冊 Firefox 帳號進行同步]]> - 已移除下載紀錄 @@ -905,6 +887,10 @@ 用新分頁開啟 用新隱私分頁開啟 + + 用新分頁開啟全部 + + 用隱私保護分頁開啟全部 刪除 @@ -1094,6 +1080,10 @@ 分享 + + 儲存為 PDF + + 無法產生 PDF 傳送到裝置 @@ -1105,9 +1095,11 @@ 已複製至剪貼簿 - 登入進行同步 + 登入進行同步 登入 Sync + + 同步並儲存資料 傳送到所有裝置 @@ -1145,6 +1137,12 @@ %1$s is a placeholder that will be replaced by the app name (Fenix). --> 將 %1$s 設為預設瀏覽器 + + 試用隱私瀏覽功能 + + 上網結束後,%1$s 將不會保留任何 Cookie 與瀏覽紀錄 + 已刪除收藏集 @@ -1275,34 +1273,21 @@ 已刪除群組 - - 歡迎使用 %s! 歡迎來到更好的網路環境 一套為人們,而不為利益打造的瀏覽器。 - - 在不同裝置間同步 Firefox 從結束的地方繼續 - - 將 %1$s 上的書籤、瀏覽紀錄、網站密碼帶到此裝置。 在不同裝置間同步分頁、密碼,讓您無縫切換裝置。 - - 註冊 登入 已開啟 Sync - - 隨時都有隱私保護 預設開啟隱私保護 - - %1$s 會自動封鎖讓大企業在網路上偷偷跟蹤您的程式。 「全方位 Cookie 保護」功能可防止追蹤器透過 Cookie 在網路上追蹤您。 @@ -1315,17 +1300,10 @@ 封鎖更多追蹤器,讓網頁可以更快載入,但頁面上的某些功能可能會故障。 挑選工具列要放置的位置 - - 可以將工具列放在畫面底端或頂端,容易操作的地方。 放在畫面底部或頂端都沒問題。 - - 您的隱私權 自行控制自己的資料 - - 我們將 %s 設計成讓您可以完整控制要在網路上分享哪些東西、以及與我們分享哪些東西。 Firefox 讓您可自行控制要在網路上分享哪些東西、以及與我們分享哪些東西。 @@ -1512,10 +1490,10 @@ 貼上並瀏覽 貼上 - + 已將網址複製至剪貼簿 - + 新增至裝置主畫面 @@ -1961,7 +1939,9 @@ 探索更多 - Powered by Pocket + Powered by Pocket + + 由 %s 提供。 Firefox 系列產品。%s @@ -1975,4 +1955,14 @@ 開啟設定 Firefox 建議 + + + + 摺疊 + + 展開 + + 開啟鏈結,了解此收藏集的更多資訊 + + 閱讀此文章 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 61352760c..48a699234 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -60,7 +60,7 @@ @color/photonRed70 - @color/photonRed70 + @color/photonRed70 @color/photonViolet70 @@ -97,7 +97,7 @@ @color/photonInk20 @color/photonRed70 - @color/photonRed70 + @color/photonRed70 @color/photonViolet60 @color/photonBlue60 @color/photonPink60 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d0f0286df..4d59261aa 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -167,16 +167,15 @@ 48dp - 4dp 12dp - 2dp + 6dp 36dp 0dp 4dp - 84dp - 72dp - 8dp + 60dp + 4dp + 12dp 6dp 8dp diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index 5eabb2a84..65ab1d0fe 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -38,7 +38,6 @@ pref_key_addons pref_key_override_amo_user pref_key_override_amo_collection - pref_key_last_maintenance pref_key_help pref_key_rate pref_key_about @@ -215,9 +214,11 @@ pref_key_wallpapers pref_key_current_wallpaper pref_key_current_wallpaper_text_color - pref_key_current_wallpaper_card_color + pref_key_current_wallpaper_card_color_light + pref_key_current_wallpaper_card_color_dark pref_key_wallpapers_onboarding pref_key_should_migrate_wallpaper + pref_key_should_migrate_wallpaper_card_colors pref_key_encryption_key_generated @@ -315,4 +316,12 @@ pref_key_nimbus_use_preview pref_key_history_metadata_feature pref_key_show_unified_search + pref_key_custom_glean_server_url + + + pref_key_growth_set_as_default + pref_key_growth_last_resumed + pref_key_growth_uri_load_last_sent + pref_key_growth_first_week_series_sent + pref_key_growth_first_week_days_of_use diff --git a/app/src/main/res/values/static_strings.xml b/app/src/main/res/values/static_strings.xml index ed5438de7..225987f22 100644 --- a/app/src/main/res/values/static_strings.xml +++ b/app/src/main/res/values/static_strings.xml @@ -26,6 +26,8 @@ AC AS + + Pocket @@ -44,6 +46,8 @@ Enable Task Continuity Enable Unified Search (requires restart) + + Custom Glean server URL (requires restart) Sync Debug diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a3cae86c0..2a310ed79 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,6 +16,12 @@ Disable private browsing Search or enter address + + Search history + + Search bookmarks + + Search tabs Enter search terms @@ -128,12 +134,6 @@ Show all Show all recent tabs button - - Your search for \"%1$s\" - - %d sites See all synced tabs @@ -247,6 +247,8 @@ Search directly from the address bar Search settings + + This time search: @@ -289,6 +291,8 @@ Skip Your tabs are syncing! Pick up where you left off on your other device. + + Close @@ -381,8 +385,6 @@ Customize - Sync bookmarks, history, and more with your Firefox Account - Sign in to sync tabs, bookmarks, passwords, and more. Firefox Account @@ -452,7 +454,11 @@ a section where users see a list of tabs that they have visited in the past few days --> Recently visited - Pocket + Pocket + + Thought-provoking stories + + Articles powered by %s Sponsored stories @@ -475,11 +481,6 @@ Couldn’t change wallpaper Learn more - - Change wallpaper by tapping Firefox homepage logo - - Firefox logo - change the wallpaper, button Classic %s @@ -573,8 +574,6 @@ Allows Mozilla to install and run studies - - Turn on Sync Sync and save your data @@ -634,6 +633,17 @@ Close + + Open %d tabs? + + Opening this many tabs may slow down %s while the pages are loading. Are you sure you want to continue? + + Open tabs + + Cancel + %d site @@ -663,10 +673,6 @@ List Grid - - Search groups - - Group related sites together Close tabs @@ -785,8 +791,6 @@ Delete from history %1$s (Private Mode) - - Other tabs @@ -814,16 +818,6 @@ Older No history here - - Synced from other devices - - From other devices - - Sign in to see history synced from your other devices. - - Sign in - - Or create a Firefox account to start syncing]]> @@ -872,6 +866,10 @@ Open in new tab Open in private tab + + Open all in new tabs + + Open all in private tabs Delete @@ -1044,6 +1042,10 @@ Share + + Save as PDF + + Unable to generate PDF Send to device @@ -1055,9 +1057,11 @@ Copied to clipboard - Sign in to sync + Sign in to sync Sign in to Sync + + Sync and save data Send to all devices @@ -1181,8 +1185,6 @@ Quit - - This will delete all of your browsing data. Time range to delete @@ -1924,7 +1926,9 @@ Discover more - Powered by Pocket. + Powered by Pocket. + + Powered by %s. Part of the Firefox family. %s @@ -1937,4 +1941,14 @@ Go to settings Firefox Suggest + + + + collapse + + expand + + open link to learn more about this collection + + read the article diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 94479402c..fe7e269c9 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -368,8 +368,8 @@ - @@ -674,14 +674,11 @@ 0.001 -