v1-t
harvey186 2025-06-30 10:56:29 +02:00
parent 1ca61b3bef
commit c47bd82b0c
217 changed files with 18308 additions and 2048 deletions

View File

@ -1,30 +0,0 @@
# Definitions for jobs that run periodically. For details on the format, see
# `taskcluster/taskgraph/cron/schema.py`. For documentation, see
# `taskcluster/docs/cron.rst`.
---
jobs:
- name: fennec-production
job:
type: decision-task
treeherder-symbol: fennec-production
target-tasks-method: fennec-production
when: [] # Force hook only
- name: bump-android-components
job:
type: decision-task
treeherder-symbol: bump-ac
target-tasks-method: bump_android_components
when: [{hour: 15, minute: 30}]
- name: screenshots
job:
type: decision-task
treeherder-symbol: screenshots-D
target-tasks-method: screenshots
when: [{weekday: 'Monday', hour: 10, minute: 0}]
- name: legacy-api-ui-tests
job:
type: decision-task
treeherder-symbol: legacy-api-ui
target-tasks-method: legacy_api_ui_tests
when: [{hour: 10, minute: 30}]

7
.gitignore vendored
View File

@ -14,6 +14,9 @@
# Java class files # Java class files
*.class *.class
# Kotlin
.kotlin
# Generated files # Generated files
bin/ bin/
gen/ gen/
@ -83,6 +86,10 @@ gen-external-apklibs
.mls_token .mls_token
.wallpaper_url .wallpaper_url
# Google Play Publisher credentials
play-service-account.json
*.p12
# Python Byte-compiled / optimized / DLL files # Python Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]

View File

@ -1,100 +0,0 @@
queue_rules:
- name: default
conditions:
- or:
- status-success=complete-pr
- and:
# For more context, see "Auto Merge" rules down below
- base~=^releases[_/].*
- status-success=complete-push
- or:
- head~=^automation/sync-strings-\d+
- head~=^relbot/fenix-\d+
pull_request_rules:
- name: Resolve conflict
conditions:
- conflict
actions:
comment:
message: This pull request has conflicts when rebasing. Could you fix it @{{author}}? 🙏
- name: Android-Components bump - Auto Merge
conditions:
- and:
- files=buildSrc/src/main/java/AndroidComponents.kt
- -files~=^(?!buildSrc/src/main/java/AndroidComponents.kt).+$
- or:
- and:
- author=MickeyMoz
- base=main
- head=ac-update
- status-success=complete-pr
- and:
- author=github-actions[bot]
- base~=^releases[_/].*
- head~=^relbot/fenix-\d+
- status-success=complete-push
actions:
review:
type: APPROVE
message: 🚢
queue:
method: rebase
name: default
rebase_fallback: none
- name: L10N - Auto Merge
conditions:
- and:
- files~=^(l10n.toml|app/src/main/res/values[A-Za-z-]*/strings\.xml)$
# /!\ The line above doesn't prevent random files to be changed alongside
# l10n ones. That's why the additional condition exists below. For more
# information: https://docs.mergify.com/conditions/#how-to-match-lists
- -files~=^(?!(l10n.toml|app/src/main/res/values[A-Za-z-]*/strings\.xml)).+$
- or:
- and:
- author=mozilla-l10n-automation-bot
- base=main
- head=import-l10n
- status-success=complete-pr
- and:
- author=github-actions[bot]
- base~=^releases[_/].*
- head~=^automation/sync-strings-\d+
- status-success=complete-push
# Taskcluster only runs on git-push events because github-actions[bot] is not considered
# a collaborator, so pull request events are triggered. That said, github-actions[bot]
# doesn't create the PR on a separate fork (unlike mozilla-l10n-automation-bot). That's
# why git-push events are taken into account
actions:
review:
type: APPROVE
message: LGTM 😎
queue:
method: rebase
name: default
rebase_fallback: none
- name: Needs landing - Rebase
conditions:
- check-success=complete-pr
- label=pr:needs-landing
- "#approved-reviews-by>=1"
- -draft
- label!=pr:work-in-progress
- label!=pr:do-not-land
actions:
queue:
method: rebase
name: default
rebase_fallback: none
- name: Needs landing - Squash
conditions:
- check-success=complete-pr
- label=pr:needs-landing-squashed
- "#approved-reviews-by>=1"
- -draft
- label!=pr:work-in-progress
- label!=pr:do-not-land
actions:
queue:
method: squash
name: default
rebase_fallback: none

View File

@ -1,15 +0,0 @@
# Community Participation Guidelines
This repository is governed by Mozilla's code of conduct and etiquette guidelines.
For more details, please read the
[Mozilla Community Participation Guidelines](https://www.mozilla.org/about/governance/policies/participation/).
## How to Report
For more information on how to report violations of the Community Participation Guidelines, please read our '[How to Report](https://www.mozilla.org/about/governance/policies/participation/reporting/)' page.
<!--
## Project Specific Etiquette
In some cases, there will be additional project etiquette i.e.: (https://bugzilla.mozilla.org/page.cgi?id=etiquette.html).
Please update for your project.
-->

View File

@ -1,3 +0,0 @@
source "https://rubygems.org"
gem "fastlane"

53
Jenkinsfile vendored
View File

@ -1,53 +0,0 @@
pipeline {
agent any
triggers {
cron(env.BRANCH_NAME == 'main' ? 'H 0 * * *' : '')
}
options {
timestamps()
timeout(time: 1, unit: 'HOURS')
}
stages {
stage('test') {
when { branch 'main' }
steps {
dir('app/src/androidTest/java/net/waterfox/android/syncIntegration') {
sh 'pipenv install'
sh 'pipenv check'
sh 'pipenv run pytest'
}
}
}
}
post {
always {
script {
if (env.BRANCH_NAME == 'main') {
publishHTML(target: [
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'app/src/androidTest/java/net/waterfox/android/syncintegration/results',
reportFiles: 'index.html',
reportName: 'HTML Report'])
}
}
}
failure {
script {
if (env.BRANCH_NAME == 'main') {
slackSend(
color: 'danger',
message: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL}HTML_20Report/)")
}
}
}
fixed {
slackSend(
color: 'good',
message: "FIXED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' (${env.BUILD_URL}HTML_20Report/)")
}
}
}

123
README.md
View File

@ -4,7 +4,128 @@ The all-new Waterfox for Android browser is based on [GeckoView](https://mozilla
## License ## License
This Source Code Form is subject to the terms of the Mozilla Public 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 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/ file, You can obtain one at http://mozilla.org/MPL/2.0/
## Building with Local Android Components
To build Waterfox for Android with local Android components - as opposed to via Android Studio and Mozilla's Maven respository - you'll first need to build GeckoView from source and then build Waterfox for Android itself, pointing it to your local GeckoView build.
These instructions are based on if you were to start from a clean Linux distribution installation.
### 1. Clone and Prepare GeckoView
First, clone the Firefox repository (which contains GeckoView). These instructions assume you will clone it into a directory named `firefox`. We do not care about the commit history, so we are shallow cloning.
```shell
git clone --depth 1 --branch release https://github.com/mozilla-firefox/firefox/
cd firefox
```
### 2. Install Python Dependencies
Ensure you have `python3-pip` installed, which is required by Mozilla's build scripts.
```shell
sudo apt-get install python3-pip
```
### 3. Bootstrap GeckoView
Run the `mach` bootstrap command to set up the build environment for GeckoView specifically for Android.
```shell
./mach --no-interactive bootstrap --application-choice="GeckoView/Firefox for Android"
```
### 4. Configure the GeckoView Build
Create a `.mozconfig` file in the `firefox` directory with the necessary build options. This configuration enables the Android mobile project, optimizes the build, disables debug symbols, and enables GeckoView Lite.
```shell
rm -f mozconfig
cat > .mozconfig << 'EOF'
ac_add_options --enable-project=mobile/android
ac_add_options --enable-optimize
ac_add_options --disable-debug
ac_add_options --enable-geckoview-lite
EOF
```
### 5. Build GeckoView
Compile GeckoView and its binaries. This can take a significant amount of time.
```shell
./mach build && ./mach build binaries
```
### 6. Publish GeckoView to Maven Local
Publish the GeckoView and Exoplayer2 artifacts to your local Maven repository. This makes them accessible to the Waterfox for Android build system.
```shell
./mach gradle geckoview:publishDebugPublicationToMavenLocal
./mach gradle exoplayer2:publishDebugPublicationToMavenLocal
```
### 7. Clone Waterfox-Android
Navigate out of the `firefox` directory (or whatever you named your GeckoView clone) and clone the Waterfox-Android repository.
```shell
cd ../
git clone git@github.com:BrowserWorks/Waterfox-Android.git
cd Waterfox-Android
```
### 8. Configure Local Properties for Waterfox-Android
Create a `local.properties` file in the root of the `Waterfox-Android` project. This file tells the Waterfox build system where to find your locally built GeckoView.
Execute the following command in the `Waterfox-Android` directory:
```shell
cat > local.properties << 'EOF'
dependencySubstitutions.geckoviewTopsrcdir=/home/$USER/firefox
dependencySubstitutions.geckoviewTopobjdir=/home/$USER/firefox/obj-$TRIPLET
EOF
```
The `dependencySubstitutions.geckoviewTopsrcdir` path should point to the root of your GeckoView source code (e.g., the `firefox` directory you cloned in Step 1). The `dependencySubstitutions.geckoviewTopobjdir` path should point to the object directory within your GeckoView build, which is typically `obj-` followed by your architecture triplet (e.g., `obj-x86_64-unknown-linux-android`).
For example, if you cloned GeckoView to `/workspace/firefox` and your object directory is `/workspace/firefox/obj-x86_64-unknown-linux-android`, your `local.properties` would look like:
```Waterfox-Android/local.properties#L1-2
dependencySubstitutions.geckoviewTopsrcdir=/workspace/firefox
dependencySubstitutions.geckoviewTopobjdir=/workspace/firefox/obj-x86_64-unknown-linux-android
```
### 9. Set Environment Variables
Set the `JAVA_HOME` and `ANDROID_HOME` environment variables. The paths shown below are typical for a `.mozbuild` setup (created during GeckoView bootstrap) but might differ on your system. Ensure these point to a JDK 17 and a valid Android SDK.
```shell
# These paths might differ based on your .mozbuild setup
export JAVA_HOME=$HOME/.mozbuild/jdk/jdk-17.0.13+11/ # Or your JDK 17 path
export ANDROID_HOME=$HOME/.mozbuild/android-sdk-linux/ # Or your Android SDK path
```
### 10. Build Waterfox-Android
Finally, clean and build the Waterfox for Android application.
To build a **debug** version:
```shell
./gradlew clean app:assembleDebug
```
To build a **release** version:
```shell
./gradlew clean app:assembleRelease
```
Note: For release builds, you will need to have set up signing configurations as per standard Android development practices.

View File

@ -1,5 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Report all security vunerablites to [Bugzilla Fenix::Security](https://bugzilla.mozilla.org/enter_bug.cgi?product=Fenix&component=Security). If they are not a security bug you will be asked to move your report to [Fenix GitHub](https://github.com/mozilla-mobile/fenix/issues). See the [Mozilla Security Bug Bounty Program](https://www.mozilla.org/en-US/security/bug-bounty/) and the [client security reporting](https://www.mozilla.org/en-US/security/client-bug-bounty/) pages for details. In any case where this document and the Mozilla.org pages differ the Mozilla.org pages are the official documentation.

View File

@ -2,16 +2,31 @@ import com.android.build.OutputFile
import groovy.json.JsonOutput import groovy.json.JsonOutput
import net.waterfox.android.gradle.tasks.ApkSizeTask import net.waterfox.android.gradle.tasks.ApkSizeTask
plugins { plugins {
alias libs.plugins.android.application
alias libs.plugins.kotlin.android
alias libs.plugins.androidx.safeargs
alias libs.plugins.kotlin.parcelize
alias libs.plugins.compose.compiler
alias libs.plugins.play.publisher
id "com.jetbrains.python.envs" version "0.0.26" id "com.jetbrains.python.envs" version "0.0.26"
id 'jacoco'
id 'com.google.android.gms.oss-licenses-plugin'
id("app.accrescent.tools.bundletool") version "0.2.4"
} }
apply plugin: 'com.android.application' bundletool {
apply plugin: 'kotlin-android' // Only configure signing if the KEYSTORE environment variable is set
apply plugin: 'kotlin-parcelize' if (System.getenv("KEYSTORE") != null) {
apply plugin: 'jacoco' signingConfig {
apply plugin: 'androidx.navigation.safeargs.kotlin' storeFile = file(System.getenv("KEYSTORE"))
apply plugin: 'com.google.android.gms.oss-licenses-plugin' storePassword = System.getenv("KEYSTORE_PWD")
keyAlias = System.getenv("KEY_ALIAS")
keyPassword = System.getenv("KEY_ALIAS_PWD")
}
}
}
import org.gradle.internal.logging.text.StyledTextOutput.Style import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory import org.gradle.internal.logging.text.StyledTextOutputFactory
@ -20,6 +35,16 @@ import static org.gradle.api.tasks.testing.TestResult.ResultType
apply from: 'benchmark.gradle' apply from: 'benchmark.gradle'
play {
// The plugin will read the service account credentials from the
// ANDROID_PUBLISHER_CREDENTIALS environment variable if it's set
enabled.set(gradle.hasProperty("enablePlayPublisher") || System.getenv("ANDROID_PUBLISHER_CREDENTIALS") != null)
// Only publish release builds
defaultToAppBundles.set(true)
track.set("internal") // Start with internal track for safety
}
android { android {
project.maybeConfigForJetpackBenchmark(it) project.maybeConfigForJetpackBenchmark(it)
if (project.hasProperty("testBuildType")) { if (project.hasProperty("testBuildType")) {
@ -43,7 +68,7 @@ android {
buildConfigField "String", "GIT_HASH", "\"\"" // see override in release builds for why it's blank. buildConfigField "String", "GIT_HASH", "\"\"" // see override in release builds for why it's blank.
// This should be the "public" base URL of AMO. // This should be the "public" base URL of AMO.
buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\"" buildConfigField "String", "AMO_BASE_URL", "\"https://addons.mozilla.org\""
buildConfigField "String", "AMO_COLLECTION_NAME", "\"Waterfox-Android\"" buildConfigField "String", "AMO_COLLECTION_NAME", "\"LeOSium-Android\""
buildConfigField "String", "AMO_COLLECTION_USER", "\"17224042\"" buildConfigField "String", "AMO_COLLECTION_USER", "\"17224042\""
// This should be the base URL used to call the AMO API. // This should be the base URL used to call the AMO API.
buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\"" buildConfigField "String", "AMO_SERVER_URL", "\"https://services.addons.mozilla.org\""
@ -84,6 +109,7 @@ android {
applicationIdSuffix ".debug" applicationIdSuffix ".debug"
resValue "bool", "IS_DEBUG", "true" resValue "bool", "IS_DEBUG", "true"
pseudoLocalesEnabled true pseudoLocalesEnabled true
testCoverageEnabled true
} }
release releaseTemplate >> { release releaseTemplate >> {
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true" buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
@ -119,7 +145,13 @@ android {
animationsDisabled = true animationsDisabled = true
} }
flavorDimensions "engine" flavorDimensions.add("product")
productFlavors {
waterfox {
dimension "product"
}
}
sourceSets { sourceSets {
androidTest { androidTest {
@ -140,6 +172,7 @@ android {
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17
coreLibraryDesugaringEnabled true
} }
lint { lint {
@ -229,7 +262,7 @@ android.applicationVariants.all { variant ->
buildConfigField 'String', 'SENTRY_TOKEN', 'null' buildConfigField 'String', 'SENTRY_TOKEN', 'null'
if (!isDebug) { if (!isDebug) {
buildConfigField 'boolean', 'CRASH_REPORTING', 'true' buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
// Reading sentry token from local file (if it exists). In a release task on Fastlane it will be available. // Reading sentry token from local file (if it exists). In a release task on Fastlane it will be available.
try { try {
def token = new File("${rootDir}/.sentry_token").text.trim() def token = new File("${rootDir}/.sentry_token").text.trim()
@ -304,145 +337,146 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
} }
dependencies { dependencies {
implementation Deps.mozilla_browser_engine_gecko implementation libs.mozilla.browser.engine.gecko
implementation Deps.kotlin_stdlib implementation libs.kotlin.stdlib
implementation Deps.kotlin_coroutines implementation libs.kotlin.coroutines
implementation Deps.kotlin_coroutines_android implementation libs.kotlin.coroutines.android
testImplementation Deps.kotlin_coroutines_test testImplementation libs.kotlin.coroutines.test
implementation Deps.androidx_appcompat implementation libs.androidx.appcompat
implementation Deps.androidx_activity_compose implementation libs.androidx.activity.compose
implementation Deps.androidx_constraintlayout implementation libs.androidx.constraintlayout
implementation Deps.androidx_coordinatorlayout implementation libs.androidx.coordinatorlayout
implementation Deps.google_accompanist_drawablepainter implementation libs.google.accompanist.drawablepainter
implementation Deps.google_accompanist_insets implementation libs.google.accompanist.insets
implementation Deps.google_accompanist_swiperefresh implementation libs.google.accompanist.swiperefresh
implementation Deps.coil implementation libs.coil
// implementation Deps.sentry // implementation libs.sentry
implementation Deps.mozilla_compose_awesomebar implementation libs.mozilla.compose.awesomebar
implementation Deps.mozilla_concept_awesomebar implementation libs.mozilla.concept.awesomebar
implementation Deps.mozilla_concept_base implementation libs.mozilla.concept.base
implementation Deps.mozilla_concept_engine implementation libs.mozilla.concept.engine
implementation Deps.mozilla_concept_menu implementation libs.mozilla.concept.menu
implementation Deps.mozilla_concept_push implementation libs.mozilla.concept.push
implementation Deps.mozilla_concept_storage implementation libs.mozilla.concept.storage
implementation Deps.mozilla_concept_sync implementation libs.mozilla.concept.sync
implementation Deps.mozilla_concept_toolbar implementation libs.mozilla.concept.toolbar
implementation Deps.mozilla_concept_tabstray implementation libs.mozilla.concept.tabstray
implementation Deps.mozilla_browser_domains implementation libs.mozilla.browser.domains
implementation Deps.mozilla_browser_icons implementation libs.mozilla.browser.icons
implementation Deps.mozilla_browser_menu implementation libs.mozilla.browser.menu
implementation Deps.mozilla_browser_menu2 implementation libs.mozilla.browser.menu2
implementation Deps.mozilla_browser_session_storage implementation libs.mozilla.browser.session.storage
implementation Deps.mozilla_browser_state implementation libs.mozilla.browser.state
implementation Deps.mozilla_browser_storage_sync implementation libs.mozilla.browser.storage.sync
implementation Deps.mozilla_browser_tabstray implementation libs.mozilla.browser.tabstray
implementation Deps.mozilla_browser_thumbnails implementation libs.mozilla.browser.thumbnails
implementation Deps.mozilla_browser_toolbar implementation libs.mozilla.browser.toolbar
implementation Deps.mozilla_feature_addons implementation libs.mozilla.feature.addons
implementation Deps.mozilla_feature_accounts implementation libs.mozilla.feature.accounts
implementation Deps.mozilla_feature_app_links implementation libs.mozilla.feature.app.links
implementation Deps.mozilla_feature_autofill implementation libs.mozilla.feature.autofill
implementation Deps.mozilla_feature_awesomebar implementation libs.mozilla.feature.awesomebar
implementation Deps.mozilla_feature_contextmenu implementation libs.mozilla.feature.contextmenu
implementation Deps.mozilla_feature_customtabs implementation libs.mozilla.feature.customtabs
implementation Deps.mozilla_feature_downloads implementation libs.mozilla.feature.downloads
implementation Deps.mozilla_feature_intent implementation libs.mozilla.feature.intent
implementation Deps.mozilla_feature_media implementation libs.mozilla.feature.media
implementation Deps.mozilla_feature_prompts implementation libs.mozilla.feature.prompts
implementation Deps.mozilla_feature_push implementation libs.mozilla.feature.push
implementation Deps.mozilla_feature_privatemode implementation libs.mozilla.feature.privatemode
implementation Deps.mozilla_feature_pwa implementation libs.mozilla.feature.pwa
implementation Deps.mozilla_feature_qr implementation libs.mozilla.feature.qr
implementation Deps.mozilla_feature_search implementation libs.mozilla.feature.search
implementation Deps.mozilla_feature_session implementation libs.mozilla.feature.session
implementation Deps.mozilla_feature_syncedtabs implementation libs.mozilla.feature.syncedtabs
implementation Deps.mozilla_feature_toolbar implementation libs.mozilla.feature.toolbar
implementation Deps.mozilla_feature_tabs implementation libs.mozilla.feature.tabs
implementation Deps.mozilla_feature_findinpage implementation libs.mozilla.feature.findinpage
implementation Deps.mozilla_feature_logins implementation libs.mozilla.feature.logins
implementation Deps.mozilla_feature_site_permissions implementation libs.mozilla.feature.site.permissions
implementation Deps.mozilla_feature_readerview implementation libs.mozilla.feature.readerview
implementation Deps.mozilla_feature_tab_collections implementation libs.mozilla.feature.tab.collections
implementation Deps.mozilla_feature_recentlyclosed implementation libs.mozilla.feature.recentlyclosed
implementation Deps.mozilla_feature_top_sites implementation libs.mozilla.feature.top.sites
implementation Deps.mozilla_feature_share implementation libs.mozilla.feature.share
implementation Deps.mozilla_feature_accounts_push implementation libs.mozilla.feature.accounts.push
implementation Deps.mozilla_feature_webauthn implementation libs.mozilla.feature.webauthn
implementation Deps.mozilla_feature_webcompat implementation libs.mozilla.feature.webcompat
implementation Deps.mozilla_feature_webnotifications implementation libs.mozilla.feature.webnotifications
implementation Deps.mozilla_feature_webcompat_reporter implementation libs.mozilla.feature.webcompat.reporter
implementation Deps.mozilla_service_mars implementation libs.mozilla.service.mars
implementation Deps.mozilla_service_digitalassetlinks implementation libs.mozilla.service.digitalassetlinks
implementation Deps.mozilla_service_sync_autofill implementation libs.mozilla.service.sync.autofill
implementation Deps.mozilla_service_sync_logins implementation libs.mozilla.service.sync.logins
implementation Deps.mozilla_service_firefox_accounts implementation libs.mozilla.service.firefox.accounts
implementation Deps.mozilla_service_location implementation libs.mozilla.service.location
implementation Deps.mozilla_support_extensions implementation libs.mozilla.support.extensions
implementation Deps.mozilla_support_base implementation libs.mozilla.support.base
implementation Deps.mozilla_support_rusterrors implementation libs.mozilla.support.rusterrors
implementation Deps.mozilla_support_images implementation libs.mozilla.support.images
implementation Deps.mozilla_support_ktx implementation libs.mozilla.support.ktx
implementation Deps.mozilla_support_rustlog implementation libs.mozilla.support.rustlog
implementation Deps.mozilla_support_utils implementation libs.mozilla.support.utils
implementation Deps.mozilla_support_locale implementation libs.mozilla.support.locale
implementation Deps.mozilla_ui_colors implementation libs.mozilla.ui.colors
implementation Deps.mozilla_ui_icons implementation libs.mozilla.ui.icons
implementation Deps.mozilla_lib_publicsuffixlist implementation libs.mozilla.lib.publicsuffixlist
implementation Deps.mozilla_ui_widgets implementation libs.mozilla.ui.widgets
implementation Deps.mozilla_ui_tabcounter implementation libs.mozilla.ui.tabcounter
implementation Deps.mozilla_lib_crash implementation libs.mozilla.lib.crash
implementation Deps.lib_crash_sentry // implementation libs.lib.crash.sentry
implementation Deps.mozilla_lib_state implementation libs.mozilla.lib.push.firebase
implementation Deps.mozilla_lib_dataprotect implementation libs.mozilla.lib.state
debugImplementation Deps.leakcanary implementation libs.mozilla.lib.dataprotect
debugImplementation libs.leakcanary
implementation Deps.androidx_compose_ui implementation libs.androidx.compose.ui
implementation Deps.androidx_compose_ui_tooling implementation libs.androidx.compose.ui.tooling
implementation Deps.androidx_compose_foundation implementation libs.androidx.compose.foundation
implementation Deps.androidx_compose_material implementation libs.androidx.compose.material
implementation Deps.androidx_compose_paging implementation libs.androidx.compose.paging
implementation Deps.androidx_legacy implementation libs.androidx.legacy
implementation Deps.androidx_biometric implementation libs.androidx.biometric
implementation Deps.androidx_paging implementation libs.androidx.paging
implementation Deps.androidx_preference implementation libs.androidx.preference
implementation Deps.androidx_fragment implementation libs.androidx.fragment
implementation Deps.androidx_navigation_fragment implementation libs.androidx.navigation.fragment
implementation Deps.androidx_navigation_ui implementation libs.androidx.navigation.ui
implementation Deps.androidx_recyclerview implementation libs.androidx.recyclerview
implementation Deps.androidx_lifecycle_common implementation libs.androidx.lifecycle.common
implementation Deps.androidx_lifecycle_livedata implementation libs.androidx.lifecycle.livedata
implementation Deps.androidx_lifecycle_process implementation libs.androidx.lifecycle.process
implementation Deps.androidx_lifecycle_runtime implementation libs.androidx.lifecycle.runtime
implementation Deps.androidx_lifecycle_viewmodel implementation libs.androidx.lifecycle.viewmodel
implementation Deps.androidx_core implementation libs.androidx.core
implementation Deps.androidx_core_ktx implementation libs.androidx.core.ktx
implementation Deps.androidx_transition implementation libs.androidx.transition
implementation Deps.androidx_work_ktx implementation libs.androidx.work.ktx
implementation Deps.androidx_datastore implementation libs.androidx.datastore
implementation Deps.google_material implementation libs.google.material
androidTestImplementation Deps.uiautomator androidTestImplementation libs.uiautomator
androidTestImplementation "tools.fastlane:screengrab:2.0.0" androidTestImplementation "tools.fastlane:screengrab:2.0.0"
// This Falcon version is added to maven central now required for Screengrab // This Falcon version is added to maven central now required for Screengrab
implementation 'com.jraska:falcon:2.2.0' implementation 'com.jraska:falcon:2.2.0'
androidTestImplementation Deps.androidx_compose_ui_test androidTestImplementation libs.androidx.compose.ui.test.manifest
androidTestImplementation Deps.espresso_core, { androidTestImplementation libs.espresso.core, {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
} }
androidTestImplementation(Deps.espresso_contrib) { androidTestImplementation libs.espresso.contrib, {
exclude module: 'appcompat-v7' exclude module: 'appcompat-v7'
exclude module: 'support-v4' exclude module: 'support-v4'
exclude module: 'support-annotations' exclude module: 'support-annotations'
@ -452,37 +486,40 @@ dependencies {
exclude module: 'protobuf-lite' exclude module: 'protobuf-lite'
} }
androidTestImplementation Deps.androidx_test_core androidTestImplementation libs.androidx.test.core
androidTestImplementation Deps.espresso_idling_resources androidTestImplementation libs.espresso.idling.resources
androidTestImplementation Deps.espresso_intents androidTestImplementation libs.espresso.intents
androidTestImplementation Deps.tools_test_runner androidTestImplementation libs.tools.test.runner
androidTestImplementation Deps.tools_test_rules androidTestImplementation libs.tools.test.rules
androidTestUtil Deps.orchestrator androidTestUtil libs.orchestrator
androidTestImplementation Deps.espresso_core, { androidTestImplementation libs.espresso.core, {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
} }
androidTestImplementation Deps.androidx_junit androidTestImplementation libs.androidx.junit
androidTestImplementation Deps.androidx_test_extensions androidTestImplementation libs.androidx.test.extensions
androidTestImplementation Deps.androidx_work_testing androidTestImplementation libs.androidx.work.testing
androidTestImplementation Deps.androidx_benchmark_junit4 androidTestImplementation libs.androidx.benchmark.junit4
androidTestImplementation Deps.mockwebserver androidTestImplementation libs.mockwebserver
testImplementation Deps.mozilla_support_test androidTestImplementation libs.androidx.compose.ui.test
testImplementation Deps.mozilla_support_test_libstate testImplementation libs.mozilla.support.test
testImplementation Deps.androidx_junit testImplementation libs.mozilla.support.test.libstate
testImplementation Deps.androidx_test_extensions testImplementation libs.androidx.junit
testImplementation Deps.androidx_work_testing testImplementation libs.androidx.test.extensions
testImplementation (Deps.robolectric) { testImplementation libs.androidx.work.testing
testImplementation (libs.robolectric) {
exclude group: 'org.apache.maven' exclude group: 'org.apache.maven'
} }
testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3' testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
implementation Deps.mozilla_support_rusthttp implementation libs.mozilla.support.rusthttp
testImplementation Deps.mockk testImplementation libs.mockk
lintChecks project(":mozilla-lint-rules") lintChecks project(":mozilla-lint-rules")
coreLibraryDesugaring libs.desugar
} }
if (project.hasProperty("coverage")) { if (project.hasProperty("coverage")) {
@ -519,14 +556,6 @@ if (project.hasProperty("coverage")) {
])) ]))
} }
} }
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
} }
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------

View File

@ -200,7 +200,7 @@ fun editBookmarkFolder() = onView(withText(R.string.bookmark_menu_edit_button)).
fun deleteBookmarkFolder() = onView(withText(R.string.bookmark_menu_delete_button)).click() fun deleteBookmarkFolder() = onView(withText(R.string.bookmark_menu_delete_button)).click()
fun tapOnTabCounter() = onView(withId(R.id.counter_text)).click() fun tapOnTabCounter() = onView(withId(mozilla.components.ui.tabcounter.R.id.counter_text)).click()
fun settingsAccountPreferences() = onView(withText(R.string.preferences_sync_2)).click() fun settingsAccountPreferences() = onView(withText(R.string.preferences_sync_2)).click()

View File

@ -21,11 +21,11 @@ import net.waterfox.android.ui.robots.navigationToolbar
* Tests that verify errors encountered while browsing websites: unsafe pages, connection errors, etc * Tests that verify errors encountered while browsing websites: unsafe pages, connection errors, etc
*/ */
class BrowsingErrorPagesTest { class BrowsingErrorPagesTest {
private val malwareWarning = getStringResource(R.string.mozac_browser_errorpages_safe_browsing_malware_uri_title) private val malwareWarning = getStringResource(mozilla.components.browser.errorpages.R.string.mozac_browser_errorpages_safe_browsing_malware_uri_title)
private val phishingWarning = getStringResource(R.string.mozac_browser_errorpages_safe_phishing_uri_title) private val phishingWarning = getStringResource(mozilla.components.browser.errorpages.R.string.mozac_browser_errorpages_safe_phishing_uri_title)
private val unwantedSoftwareWarning = private val unwantedSoftwareWarning =
getStringResource(R.string.mozac_browser_errorpages_safe_browsing_unwanted_uri_title) getStringResource(mozilla.components.browser.errorpages.R.string.mozac_browser_errorpages_safe_browsing_unwanted_uri_title)
private val harmfulSiteWarning = getStringResource(R.string.mozac_browser_errorpages_safe_harmful_uri_title) private val harmfulSiteWarning = getStringResource(mozilla.components.browser.errorpages.R.string.mozac_browser_errorpages_safe_harmful_uri_title)
private val featureSettingsHelper = FeatureSettingsHelper() private val featureSettingsHelper = FeatureSettingsHelper()
@get: Rule @get: Rule

View File

@ -113,7 +113,7 @@ class NoNetworkAccessStartupTests {
verifyUrl( verifyUrl(
"waterfox.net", "waterfox.net",
"$packageName:id/mozac_browser_toolbar_url_view", "$packageName:id/mozac_browser_toolbar_url_view",
R.id.mozac_browser_toolbar_url_view mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view
) )
} }
} }

View File

@ -76,7 +76,7 @@ class ReaderViewTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityIntentTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )
@ -119,7 +119,7 @@ class ReaderViewTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityIntentTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )
@ -157,7 +157,7 @@ class ReaderViewTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityIntentTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )
@ -197,7 +197,7 @@ class ReaderViewTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityIntentTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )
@ -243,7 +243,7 @@ class ReaderViewTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityIntentTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityIntentTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )

View File

@ -762,7 +762,7 @@ class SmokeTest {
} }
readerViewNotification = ViewVisibilityIdlingResource( readerViewNotification = ViewVisibilityIdlingResource(
activityTestRule.activity.findViewById(R.id.mozac_browser_toolbar_page_actions), activityTestRule.activity.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions),
View.VISIBLE View.VISIBLE
) )

View File

@ -971,7 +971,7 @@ fun browserScreen(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
fun navURLBar() = mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar")) fun navURLBar() = mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar"))
fun searchBar() = onView(withId(R.id.mozac_browser_toolbar_url_view)) fun searchBar() = onView(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view))
fun homeScreenButton() = onView(withContentDescription(R.string.browser_toolbar_home)) fun homeScreenButton() = onView(withContentDescription(R.string.browser_toolbar_home))
@ -985,7 +985,7 @@ private fun assertNavURLBar() = assertTrue(navURLBar().waitForExists(waitingTime
private fun assertNavURLBarHidden() = assertTrue(navURLBar().waitUntilGone(waitingTime)) private fun assertNavURLBarHidden() = assertTrue(navURLBar().waitUntilGone(waitingTime))
private fun assertSecureConnectionLockIcon() { private fun assertSecureConnectionLockIcon() {
onView(withId(R.id.mozac_browser_toolbar_security_indicator)) onView(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_site_info_indicator))
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }

View File

@ -67,11 +67,11 @@ class FindInPageRobot {
} }
} }
private fun findInPageQuery() = onView(withId(R.id.find_in_page_query_text)) private fun findInPageQuery() = onView(withId(mozilla.components.feature.findinpage.R.id.find_in_page_query_text))
private fun findInPageResult() = onView(withId(R.id.find_in_page_result_text)) private fun findInPageResult() = onView(withId(mozilla.components.feature.findinpage.R.id.find_in_page_result_text))
private fun findInPageNextButton() = onView(withId(R.id.find_in_page_next_btn)) private fun findInPageNextButton() = onView(withId(mozilla.components.feature.findinpage.R.id.find_in_page_next_btn))
private fun findInPagePrevButton() = onView(withId(R.id.find_in_page_prev_btn)) private fun findInPagePrevButton() = onView(withId(mozilla.components.feature.findinpage.R.id.find_in_page_prev_btn))
private fun findInPageCloseButton() = onView(withId(R.id.find_in_page_close_btn)) private fun findInPageCloseButton() = onView(withId(mozilla.components.feature.findinpage.R.id.find_in_page_close_btn))
private fun assertFindInPageQuery() = findInPageQuery() private fun assertFindInPageQuery() = findInPageQuery()
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))

View File

@ -523,7 +523,7 @@ private fun assertHomeComponent() =
onView(ViewMatchers.withResourceName("sessionControlRecyclerView")) onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
private fun assertNoTabsOpened() = onView(withId(R.id.counter_text)).check(matches(withText("0"))) private fun assertNoTabsOpened() = onView(withId(mozilla.components.ui.tabcounter.R.id.counter_text)).check(matches(withText("0")))
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton))) private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
@ -778,7 +778,7 @@ private fun startBrowsingButton(): UiObject {
val deleteFromHistory = val deleteFromHistory =
onView( onView(
allOf( allOf(
withId(R.id.simple_text), withId(mozilla.components.browser.menu2.R.id.simple_text),
withText(R.string.delete_from_history) withText(R.string.delete_from_history)
) )
).inRoot(RootMatchers.isPlatformPopup()) ).inRoot(RootMatchers.isPlatformPopup())

View File

@ -185,7 +185,7 @@ class NavigationToolbarRobot {
fun closeTabFromShortcutsMenu(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition { fun closeTabFromShortcutsMenu(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {
mDevice.waitForIdle(waitingTime) mDevice.waitForIdle(waitingTime)
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>( RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendant( hasDescendant(
@ -202,7 +202,7 @@ class NavigationToolbarRobot {
fun openTabFromShortcutsMenu(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { fun openTabFromShortcutsMenu(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle(waitingTime) mDevice.waitForIdle(waitingTime)
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>( RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendant( hasDescendant(
@ -219,7 +219,7 @@ class NavigationToolbarRobot {
fun openNewPrivateTabFromShortcutsMenu(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { fun openNewPrivateTabFromShortcutsMenu(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle(waitingTime) mDevice.waitForIdle(waitingTime)
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>( RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendant( hasDescendant(
@ -271,7 +271,7 @@ private fun assertNoHistoryBookmarks() {
} }
private fun assertTabButtonShortcutMenuItems() { private fun assertTabButtonShortcutMenuItems() {
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.check(matches(hasDescendant(withText("Close tab")))) .check(matches(hasDescendant(withText("Close tab"))))
.check(matches(hasDescendant(withText("New private tab")))) .check(matches(hasDescendant(withText("New private tab"))))
.check(matches(hasDescendant(withText("New tab")))) .check(matches(hasDescendant(withText("New tab"))))
@ -280,14 +280,14 @@ private fun assertTabButtonShortcutMenuItems() {
private fun urlBar() = mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar")) private fun urlBar() = mDevice.findObject(UiSelector().resourceId("$packageName:id/toolbar"))
private fun awesomeBar() = private fun awesomeBar() =
mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view")) mDevice.findObject(UiSelector().resourceId("$packageName:id/mozac_browser_toolbar_edit_url_view"))
private fun threeDotButton() = onView(withId(R.id.mozac_browser_toolbar_menu)) private fun threeDotButton() = onView(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_menu))
private fun tabTrayButton() = onView(withId(R.id.tab_button)) private fun tabTrayButton() = onView(withId(R.id.tab_button))
private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard)) private fun fillLinkButton() = onView(withId(R.id.fill_link_from_clipboard))
private fun clearAddressBar() = 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 goBackButton() = mDevice.pressBack()
private fun readerViewToggle() = private fun readerViewToggle() =
onView(withParent(withId(R.id.mozac_browser_toolbar_page_actions))) onView(withParent(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions)))
private fun assertReaderViewDetected(visible: Boolean) { private fun assertReaderViewDetected(visible: Boolean) {
mDevice.findObject( mDevice.findObject(
@ -298,7 +298,7 @@ private fun assertReaderViewDetected(visible: Boolean) {
onView( onView(
allOf( allOf(
withParent(withId(R.id.mozac_browser_toolbar_page_actions)), withParent(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions)),
withContentDescription("Reader view") withContentDescription("Reader view")
) )
).check( ).check(
@ -316,7 +316,7 @@ private fun assertCloseReaderViewDetected(visible: Boolean) {
onView( onView(
allOf( allOf(
withParent(withId(R.id.mozac_browser_toolbar_page_actions)), withParent(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_page_actions)),
withContentDescription("Close reader view") withContentDescription("Close reader view")
) )
).check( ).check(

View File

@ -92,7 +92,7 @@ class ReaderViewRobot {
fun toggleSansSerif(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleSansSerif(interact: ReaderViewRobot.() -> Unit): Transition {
fun sansSerifButton() = fun sansSerifButton() =
onView( onView(
withId(R.id.mozac_feature_readerview_font_sans_serif) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_sans_serif)
) )
sansSerifButton().click() sansSerifButton().click()
@ -104,7 +104,7 @@ class ReaderViewRobot {
fun toggleSerif(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleSerif(interact: ReaderViewRobot.() -> Unit): Transition {
fun serifButton() = fun serifButton() =
onView( onView(
withId(R.id.mozac_feature_readerview_font_serif) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_serif)
) )
serifButton().click() serifButton().click()
@ -116,7 +116,7 @@ class ReaderViewRobot {
fun toggleFontSizeDecrease(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleFontSizeDecrease(interact: ReaderViewRobot.() -> Unit): Transition {
fun fontSizeDecrease() = fun fontSizeDecrease() =
onView( onView(
withId(R.id.mozac_feature_readerview_font_size_decrease) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_decrease)
) )
fontSizeDecrease().click() fontSizeDecrease().click()
@ -128,7 +128,7 @@ class ReaderViewRobot {
fun toggleFontSizeIncrease(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleFontSizeIncrease(interact: ReaderViewRobot.() -> Unit): Transition {
fun fontSizeIncrease() = fun fontSizeIncrease() =
onView( onView(
withId(R.id.mozac_feature_readerview_font_size_increase) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_increase)
) )
fontSizeIncrease().click() fontSizeIncrease().click()
@ -140,7 +140,7 @@ class ReaderViewRobot {
fun toggleColorSchemeChangeLight(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleColorSchemeChangeLight(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleLightColorSchemeButton() = fun toggleLightColorSchemeButton() =
onView( onView(
withId(R.id.mozac_feature_readerview_color_light) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_light)
) )
toggleLightColorSchemeButton().click() toggleLightColorSchemeButton().click()
@ -152,7 +152,7 @@ class ReaderViewRobot {
fun toggleColorSchemeChangeDark(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleColorSchemeChangeDark(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleDarkColorSchemeButton() = fun toggleDarkColorSchemeButton() =
onView( onView(
withId(R.id.mozac_feature_readerview_color_dark) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_dark)
) )
toggleDarkColorSchemeButton().click() toggleDarkColorSchemeButton().click()
@ -164,7 +164,7 @@ class ReaderViewRobot {
fun toggleColorSchemeChangeSepia(interact: ReaderViewRobot.() -> Unit): Transition { fun toggleColorSchemeChangeSepia(interact: ReaderViewRobot.() -> Unit): Transition {
fun toggleSepiaColorSchemeButton() = fun toggleSepiaColorSchemeButton() =
onView( onView(
withId(R.id.mozac_feature_readerview_color_sepia) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_sepia)
) )
toggleSepiaColorSchemeButton().click() toggleSepiaColorSchemeButton().click()
@ -182,63 +182,63 @@ fun readerViewRobot(interact: ReaderViewRobot.() -> Unit): ReaderViewRobot.Trans
private fun assertAppearanceFontGroup(visible: Boolean) = private fun assertAppearanceFontGroup(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_font_group) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_group)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceFontSansSerif(visible: Boolean) = private fun assertAppearanceFontSansSerif(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_font_sans_serif) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_sans_serif)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceFontSerif(visible: Boolean) = private fun assertAppearanceFontSerif(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_font_serif) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_serif)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceFontDecrease(visible: Boolean) = private fun assertAppearanceFontDecrease(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_font_size_decrease) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_decrease)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceFontIncrease(visible: Boolean) = private fun assertAppearanceFontIncrease(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_font_size_increase) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_increase)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceColorDark(visible: Boolean) = private fun assertAppearanceColorDark(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_color_dark) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_dark)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceColorLight(visible: Boolean) = private fun assertAppearanceColorLight(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_color_light) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_light)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceColorSepia(visible: Boolean) = private fun assertAppearanceColorSepia(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_color_sepia) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_sepia)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )
private fun assertAppearanceColorGroup(visible: Boolean) = private fun assertAppearanceColorGroup(visible: Boolean) =
onView( onView(
withId(R.id.mozac_feature_readerview_color_scheme_group) withId(mozilla.components.feature.readerview.R.id.mozac_feature_readerview_color_scheme_group)
).check( ).check(
matches(withEffectiveVisibility(visibleOrGone(visible))) matches(withEffectiveVisibility(visibleOrGone(visible)))
) )

View File

@ -392,7 +392,7 @@ private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean): () -> Unit
} }
private fun ComposeTestRule.assertSearchEngineList() { private fun ComposeTestRule.assertSearchEngineList() {
onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() onView(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_edit_icon)).click()
onNodeWithText("Google") onNodeWithText("Google")
.assertExists() .assertExists()
@ -445,7 +445,7 @@ private fun assertEngineListShortcutContains(rule: ComposeTestRule, searchEngine
} }
private fun ComposeTestRule.selectDefaultSearchEngine(searchEngine: String) { private fun ComposeTestRule.selectDefaultSearchEngine(searchEngine: String) {
onView(withId(R.id.mozac_browser_toolbar_edit_icon)).click() onView(withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_edit_icon)).click()
onNodeWithText(searchEngine) onNodeWithText(searchEngine)
.assertExists() .assertExists()
@ -470,7 +470,7 @@ private fun assertPastedToolbarText(expectedText: String) {
onView( onView(
allOf( allOf(
withSubstring(expectedText), withSubstring(expectedText),
withId(R.id.mozac_browser_toolbar_edit_url_view) withId(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_edit_url_view)
) )
).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) ).check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
} }

View File

@ -131,7 +131,7 @@ private fun assertSupport(rule: ComposeTestRule) {
TestHelper.verifyUrl( TestHelper.verifyUrl(
"waterfox.net/docs/support", "waterfox.net/docs/support",
"$packageName:id/mozac_browser_toolbar_url_view", "$packageName:id/mozac_browser_toolbar_url_view",
R.id.mozac_browser_toolbar_url_view mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view
) )
} }
@ -165,7 +165,7 @@ private fun assertPrivacyNotice(rule: ComposeTestRule) {
TestHelper.verifyUrl( TestHelper.verifyUrl(
"waterfox.net/docs/policies/privacy", "waterfox.net/docs/policies/privacy",
"$packageName:id/mozac_browser_toolbar_url_view", "$packageName:id/mozac_browser_toolbar_url_view",
R.id.mozac_browser_toolbar_url_view mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view
) )
} }
@ -180,7 +180,7 @@ private fun assertKnowYourRights(rule: ComposeTestRule) {
TestHelper.verifyUrl( TestHelper.verifyUrl(
SupportUtils.SumoTopic.YOUR_RIGHTS.topicStr, SupportUtils.SumoTopic.YOUR_RIGHTS.topicStr,
"$packageName:id/mozac_browser_toolbar_url_view", "$packageName:id/mozac_browser_toolbar_url_view",
R.id.mozac_browser_toolbar_url_view mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view
) )
} }
@ -195,7 +195,7 @@ private fun assertLicensingInformation(rule: ComposeTestRule) {
TestHelper.verifyUrl( TestHelper.verifyUrl(
"about:license", "about:license",
"$packageName:id/mozac_browser_toolbar_url_view", "$packageName:id/mozac_browser_toolbar_url_view",
R.id.mozac_browser_toolbar_url_view mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_url_view
) )
} }

View File

@ -107,15 +107,15 @@ private fun assertSliderBar() {
// onView(withId(net.waterfox.android.R.id.sampleText)) // onView(withId(net.waterfox.android.R.id.sampleText))
// .check(matches(withText("This is sample text. It is here to show how text will appear when you increase or decrease the size with this setting."))) // .check(matches(withText("This is sample text. It is here to show how text will appear when you increase or decrease the size with this setting.")))
onView(withId(net.waterfox.android.R.id.seekbar_value)) onView(withId(androidx.preference.R.id.seekbar_value))
.check(matches(withText("100%"))) .check(matches(withText("100%")))
onView(withId(net.waterfox.android.R.id.seekbar)) onView(withId(androidx.preference.R.id.seekbar))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
private fun adjustTextSizeSlider(seekBarPercentage: Int) { private fun adjustTextSizeSlider(seekBarPercentage: Int) {
onView(withId(net.waterfox.android.R.id.seekbar)) onView(withId(androidx.preference.R.id.seekbar))
.perform(SeekBarChangeProgressViewAction(seekBarPercentage)) .perform(SeekBarChangeProgressViewAction(seekBarPercentage))
} }
@ -134,9 +134,9 @@ private fun assertMenuItemsAreDisabled() {
// onView(withId(net.waterfox.android.R.id.sampleText)).assertIsEnabled(false) // onView(withId(net.waterfox.android.R.id.sampleText)).assertIsEnabled(false)
onView(withId(net.waterfox.android.R.id.seekbar_value)).assertIsEnabled(false) onView(withId(androidx.preference.R.id.seekbar_value)).assertIsEnabled(false)
onView(withId(net.waterfox.android.R.id.seekbar)).assertIsEnabled(false) onView(withId(androidx.preference.R.id.seekbar)).assertIsEnabled(false)
} }
private fun goBackButton() = private fun goBackButton() =

View File

@ -124,7 +124,7 @@ class SettingsSubMenuAddonsManagerRobot {
mDevice.findObject(UiSelector().text("Allow in private browsing")) mDevice.findObject(UiSelector().text("Allow in private browsing"))
.waitForExists(waitingTimeLong) .waitForExists(waitingTimeLong)
) )
onView(withId(R.id.allow_in_private_browsing)).click() onView(withId(mozilla.components.feature.addons.R.id.allow_in_private_browsing)).click()
} }
fun installAddon(addonName: String) { fun installAddon(addonName: String) {
@ -154,10 +154,10 @@ class SettingsSubMenuAddonsManagerRobot {
onView( onView(
allOf( allOf(
withId(R.id.add_on_item), withId(mozilla.components.feature.addons.R.id.add_on_item),
hasDescendant( hasDescendant(
allOf( allOf(
withId(R.id.add_on_name), withId(mozilla.components.feature.addons.R.id.add_on_name),
withText(addonName) withText(addonName)
) )
) )
@ -173,8 +173,8 @@ class SettingsSubMenuAddonsManagerRobot {
private fun installButtonForAddon(addonName: String) = private fun installButtonForAddon(addonName: String) =
onView( onView(
allOf( allOf(
withContentDescription(R.string.mozac_feature_addons_install_addon_content_description_2), withContentDescription(mozilla.components.feature.addons.R.string.mozac_feature_addons_install_addon_content_description_2),
isDescendantOfA(withId(R.id.add_on_item)), isDescendantOfA(withId(mozilla.components.feature.addons.R.id.add_on_item)),
hasSibling(hasDescendant(withText(addonName))) hasSibling(hasDescendant(withText(addonName)))
) )
) )
@ -196,10 +196,10 @@ class SettingsSubMenuAddonsManagerRobot {
) )
.check(matches(isCompletelyDisplayed())) .check(matches(isCompletelyDisplayed()))
onView(allOf(withId(R.id.allow_button), withText("Add"))) onView(allOf(withId(mozilla.components.feature.sitepermissions.R.id.allow_button), withText("Add")))
.check(matches(isCompletelyDisplayed())) .check(matches(isCompletelyDisplayed()))
onView(allOf(withId(R.id.deny_button), withText("Cancel"))) onView(allOf(withId(mozilla.components.feature.downloads.R.id.deny_button), withText("Cancel")))
.check(matches(isCompletelyDisplayed())) .check(matches(isCompletelyDisplayed()))
} }
@ -207,20 +207,20 @@ class SettingsSubMenuAddonsManagerRobot {
onView( onView(
allOf( allOf(
withId(R.id.add_button), withId(R.id.add_button),
isDescendantOfA(withId(R.id.add_on_item)), isDescendantOfA(withId(mozilla.components.feature.addons.R.id.add_on_item)),
hasSibling(hasDescendant(withText(addonName))) hasSibling(hasDescendant(withText(addonName)))
) )
).check(matches(withEffectiveVisibility(Visibility.GONE))) ).check(matches(withEffectiveVisibility(Visibility.GONE)))
} }
private fun cancelInstall() { private fun cancelInstall() {
onView(allOf(withId(R.id.deny_button), withText("Cancel"))) onView(allOf(withId(mozilla.components.feature.downloads.R.id.deny_button), withText("Cancel")))
.check(matches(isCompletelyDisplayed())) .check(matches(isCompletelyDisplayed()))
.perform(click()) .perform(click())
} }
private fun allowPermissionToInstall() { private fun allowPermissionToInstall() {
onView(allOf(withId(R.id.allow_button), withText("Add"))) onView(allOf(withId(mozilla.components.feature.sitepermissions.R.id.allow_button), withText("Add")))
.check(matches(isCompletelyDisplayed())) .check(matches(isCompletelyDisplayed()))
.perform(click()) .perform(click())
} }
@ -243,11 +243,11 @@ class SettingsSubMenuAddonsManagerRobot {
onView( onView(
allOf( allOf(
isAssignableFrom(RelativeLayout::class.java), isAssignableFrom(RelativeLayout::class.java),
withId(R.id.add_on_item), withId(mozilla.components.feature.addons.R.id.add_on_item),
hasDescendant(allOf(withId(R.id.add_on_icon), isCompletelyDisplayed())), hasDescendant(allOf(withId(mozilla.components.feature.addons.R.id.add_on_icon), isCompletelyDisplayed())),
hasDescendant( hasDescendant(
allOf( allOf(
withId(R.id.details_container), withId(mozilla.components.feature.addons.R.id.details_container),
hasDescendant(withText("uBlock Origin")), hasDescendant(withText("uBlock Origin")),
hasDescendant(withText("Finally, an efficient wide-spectrum content blocker. Easy on CPU and memory.")), hasDescendant(withText("Finally, an efficient wide-spectrum content blocker. Easy on CPU and memory.")),
hasDescendant(withId(R.id.rating)), hasDescendant(withId(R.id.rating)),
@ -269,7 +269,7 @@ class SettingsSubMenuAddonsManagerRobot {
hasSibling( hasSibling(
hasDescendant( hasDescendant(
allOf( allOf(
withId(R.id.add_on_name), withId(mozilla.components.feature.addons.R.id.add_on_name),
withText(addonName) withText(addonName)
) )
) )

View File

@ -83,7 +83,7 @@ class SitePermissionsRobot {
} }
fun selectRememberPermissionDecision() { fun selectRememberPermissionDecision() {
onView(withId(R.id.do_not_ask_again)) onView(withId(mozilla.components.feature.sitepermissions.R.id.do_not_ask_again))
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
.click() .click()
} }

View File

@ -613,12 +613,12 @@ private fun tabItem(title: String) =
private fun tabsCounter() = onView(withId(R.id.tab_button)) private fun tabsCounter() = onView(withId(R.id.tab_button))
private fun tabsTrayCounterBox() = onView(withId(R.id.counter_box)) private fun tabsTrayCounterBox() = onView(withId(mozilla.components.ui.tabcounter.R.id.counter_box))
private fun tabsSettingsButton() = private fun tabsSettingsButton() =
onView( onView(
allOf( allOf(
withId(R.id.simple_text), withId(mozilla.components.browser.menu2.R.id.simple_text),
withText(R.string.tab_tray_menu_tab_settings) withText(R.string.tab_tray_menu_tab_settings)
) )
) )
@ -626,7 +626,7 @@ private fun tabsSettingsButton() =
private fun recentlyClosedTabsButton() = private fun recentlyClosedTabsButton() =
onView( onView(
allOf( allOf(
withId(R.id.simple_text), withId(mozilla.components.browser.menu2.R.id.simple_text),
withText(R.string.tab_tray_menu_recently_closed) withText(R.string.tab_tray_menu_recently_closed)
) )
) )

View File

@ -61,7 +61,7 @@ class ThreeDotMenuMainRobot {
fun verifyReaderViewAppearance(visible: Boolean) = assertReaderViewAppearanceButton(visible) fun verifyReaderViewAppearance(visible: Boolean) = assertReaderViewAppearanceButton(visible)
fun expandMenu() { fun expandMenu() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeUp()) onView(withId(mozilla.components.browser.menu.R.id.mozac_browser_menu_menuView)).perform(swipeUp())
} }
fun verifyShareTabButton() = assertShareTabButton() fun verifyShareTabButton() = assertShareTabButton()
@ -399,7 +399,7 @@ class ThreeDotMenuMainRobot {
} }
} }
private fun threeDotMenuRecyclerView() = private fun threeDotMenuRecyclerView() =
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
private fun threeDotMenuRecyclerViewExists() { private fun threeDotMenuRecyclerViewExists() {
threeDotMenuRecyclerView().check(matches(isDisplayed())) threeDotMenuRecyclerView().check(matches(isDisplayed()))
@ -421,7 +421,7 @@ private fun assertCustomizeHomeButton() =
private fun addOnsButton() = onView(allOf(withText("Add-ons"))) private fun addOnsButton() = onView(allOf(withText("Add-ons")))
private fun assertAddOnsButton() { private fun assertAddOnsButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) onView(withId(mozilla.components.browser.menu.R.id.mozac_browser_menu_menuView)).perform(swipeDown())
addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) addOnsButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
@ -447,7 +447,7 @@ private fun backButton() = mDevice.findObject(UiSelector().description("Back"))
private fun addBookmarkButton() = onView(allOf(withId(R.id.checkbox), withText("Add"))) private fun addBookmarkButton() = onView(allOf(withId(R.id.checkbox), withText("Add")))
private fun assertAddBookmarkButton() { private fun assertAddBookmarkButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeUp()) onView(withId(mozilla.components.browser.menu.R.id.mozac_browser_menu_menuView)).perform(swipeUp())
addBookmarkButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE))) addBookmarkButton().check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
} }
@ -525,7 +525,7 @@ private fun removeFromShortcutsButton() =
onView(allOf(withText(R.string.browser_menu_remove_from_shortcuts))) onView(allOf(withText(R.string.browser_menu_remove_from_shortcuts)))
private fun assertAddToTopSitesButton() { private fun assertAddToTopSitesButton() {
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>( RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.browser_menu_add_to_shortcuts)) hasDescendant(withText(R.string.browser_menu_add_to_shortcuts))
@ -535,7 +535,7 @@ private fun assertAddToTopSitesButton() {
private fun assertRemoveFromShortcutsButton() { private fun assertRemoveFromShortcutsButton() {
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>( RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.browser_menu_settings)) hasDescendant(withText(R.string.browser_menu_settings))
@ -547,7 +547,7 @@ private fun addToMobileHomeButton() =
onView(allOf(withText(R.string.browser_menu_add_to_homescreen))) onView(allOf(withText(R.string.browser_menu_add_to_homescreen)))
private fun assertAddToMobileHome() { private fun assertAddToMobileHome() {
onView(withId(R.id.mozac_browser_menu_recyclerView)) onView(withId(mozilla.components.browser.menu2.R.id.mozac_browser_menu_recyclerView))
.perform( .perform(
RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>( RecyclerViewActions.scrollTo<RecyclerView.ViewHolder>(
hasDescendant(withText(R.string.browser_menu_add_to_homescreen)) hasDescendant(withText(R.string.browser_menu_add_to_homescreen))
@ -573,12 +573,12 @@ private fun openInAppButton() =
private fun downloadsButton() = onView(withText(R.string.library_downloads)) private fun downloadsButton() = onView(withText(R.string.library_downloads))
private fun assertDownloadsButton() { private fun assertDownloadsButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) onView(withId(mozilla.components.browser.menu.R.id.mozac_browser_menu_menuView)).perform(swipeDown())
downloadsButton().check(matches(isDisplayed())) downloadsButton().check(matches(isDisplayed()))
} }
private fun clickAddonsManagerButton() { private fun clickAddonsManagerButton() {
onView(withId(R.id.mozac_browser_menu_menuView)).perform(swipeDown()) onView(withId(mozilla.components.browser.menu.R.id.mozac_browser_menu_menuView)).perform(swipeDown())
addOnsButton().check(matches(isCompletelyDisplayed())).click() addOnsButton().check(matches(isCompletelyDisplayed())).click()
} }

View File

@ -3,5 +3,5 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - 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/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<resources> <resources>
<color name="ic_launcher_background">@color/photonInk20</color> <color name="ic_launcher_background">#FFFFFF</color>
</resources> </resources>

View File

@ -44,7 +44,6 @@
<application <application
android:name=".WaterfoxApplication" android:name=".WaterfoxApplication"
android:allowBackup="false" android:allowBackup="false"
android:extractNativeLibs="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="LeOSium" android:label="LeOSium"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher"
@ -333,6 +332,23 @@
android:value="This foreground service allows users to easily remove private tabs from the notification" /> android:value="This foreground service allows users to easily remove private tabs from the notification" />
</service> </service>
<service
android:name=".push.FirebasePushService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="firebase_messaging_auto_init_enabled"
android:value="true" />
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="false" />
<meta-data
android:name="firebase_analytics_collection_deactivated"
android:value="true" />
<!-- Removes the default Workmanager initialization so that we can use on-demand initializer. --> <!-- Removes the default Workmanager initialization so that we can use on-demand initializer. -->
<provider <provider
android:name="androidx.startup.InitializationProvider" android:name="androidx.startup.InitializationProvider"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 143 KiB

View File

@ -32,7 +32,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.action.MediaSessionAction import mozilla.components.browser.state.action.MediaSessionAction
import mozilla.components.browser.state.search.SearchEngine import mozilla.components.browser.state.search.SearchEngine
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
@ -55,6 +54,7 @@ import mozilla.components.support.base.log.logger.Logger
import mozilla.components.support.ktx.android.arch.lifecycle.addObservers import mozilla.components.support.ktx.android.arch.lifecycle.addObservers
import mozilla.components.support.ktx.android.content.call import mozilla.components.support.ktx.android.content.call
import mozilla.components.support.ktx.android.content.email import mozilla.components.support.ktx.android.content.email
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.content.share import mozilla.components.support.ktx.android.content.share
import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.isUrl
import mozilla.components.support.ktx.kotlin.toNormalizedUrl import mozilla.components.support.ktx.kotlin.toNormalizedUrl
@ -228,6 +228,23 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
binding = ActivityHomeBinding.inflate(layoutInflater) binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
// Enable edge-to-edge display for modern Android versions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.setDecorFitsSystemWindows(false)
// Ensure navigation bar color matches theme
window.navigationBarColor = getColorFromAttr(R.attr.layer1)
} else
@Suppress("DEPRECATION")
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.navigationBarColor = getColorFromAttr(R.attr.layer1)
}
ProfilerMarkers.addListenerForOnGlobalLayout(components.core.engine, this, binding.root) ProfilerMarkers.addListenerForOnGlobalLayout(components.core.engine, this, binding.root)
// Must be after we set the content view // Must be after we set the content view

View File

@ -17,8 +17,8 @@ import androidx.core.content.getSystemService
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration.Builder import androidx.work.Configuration.Builder
import androidx.work.Configuration.Provider import androidx.work.Configuration.Provider
import coil.Coil import coil3.SingletonImageLoader
import coil.ImageLoader import coil3.ImageLoader
import kotlinx.coroutines.* import kotlinx.coroutines.*
import mozilla.appservices.Megazord import mozilla.appservices.Megazord
import mozilla.components.browser.state.action.SystemAction import mozilla.components.browser.state.action.SystemAction
@ -62,6 +62,8 @@ import net.waterfox.android.session.VisibilityLifecycleCallback
import net.waterfox.android.utils.BrowsersCache import net.waterfox.android.utils.BrowsersCache
import net.waterfox.android.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD import net.waterfox.android.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import mozilla.appservices.init_rust_components.initialize as InitializeRustComponents
/** /**
*The main application class for Waterfox. Records data to measure initialization performance. *The main application class for Waterfox. Records data to measure initialization performance.
@ -115,11 +117,10 @@ open class WaterfoxApplication : LocaleAwareApplication(), Provider {
ProfilerMarkerFactProcessor.create { components.core.engine.profiler }.register() ProfilerMarkerFactProcessor.create { components.core.engine.profiler }.register()
// This is a workaround for https://github.com/coil-kt/coil/issues/383 // This is a workaround for https://github.com/coil-kt/coil/issues/383
Coil.setImageLoader( SingletonImageLoader.setSafe {
ImageLoader.Builder(this) ImageLoader.Builder(this@WaterfoxApplication)
.addLastModifiedToFileCacheKey(false)
.build() .build()
) }
run { run {
// Make sure the engine is initialized and ready to use. // Make sure the engine is initialized and ready to use.
@ -136,7 +137,7 @@ open class WaterfoxApplication : LocaleAwareApplication(), Provider {
val megazordSetup = finishSetupMegazord() val megazordSetup = finishSetupMegazord()
setDayNightTheme() setDayNightTheme()
components.strictMode.enableStrictMode(true) //components.strictMode.enableStrictMode(true)
warmBrowsersCache() warmBrowsersCache()
initializeWebExtensionSupport() initializeWebExtensionSupport()
@ -160,7 +161,7 @@ open class WaterfoxApplication : LocaleAwareApplication(), Provider {
} }
setupLeakCanary() setupLeakCanary()
setupPush()
visibilityLifecycleCallback = VisibilityLifecycleCallback(getSystemService()) visibilityLifecycleCallback = VisibilityLifecycleCallback(getSystemService())
registerActivityLifecycleCallbacks(visibilityLifecycleCallback) registerActivityLifecycleCallbacks(visibilityLifecycleCallback)
@ -292,7 +293,25 @@ open class WaterfoxApplication : LocaleAwareApplication(), Provider {
// no-op, LeakCanary is disabled by default // no-op, LeakCanary is disabled by default
} }
private fun setupPush() {
// Sets the PushFeature as the singleton instance for push messages to go to.
// We need the push feature setup here to deliver messages in the case where the service
// starts up the app first.
components.push.feature?.let {
Logger.info("AutoPushFeature is configured, initializing it...")
// Install the AutoPush singleton to receive messages.
PushProcessor.install(it)
WebPushEngineIntegration(components.core.engine, it).start()
// Perform a one-time initialization of the account manager if a message is received.
PushFxaIntegration(it, lazy { components.backgroundServices.accountManager }).launch()
// Initialize the service. This could potentially be done in a coroutine in the future.
it.initialize()
}
}
private fun setupCrashReporting() { private fun setupCrashReporting() {
components.analytics.crashReporter.install(this) components.analytics.crashReporter.install(this)
@ -313,6 +332,9 @@ open class WaterfoxApplication : LocaleAwareApplication(), Provider {
* thread, early in the app startup sequence. * thread, early in the app startup sequence.
*/ */
private fun beginSetupMegazord() { private fun beginSetupMegazord() {
// Rust components must be initialized at the very beginning, before any other Rust call, ...
InitializeRustComponents()
// Note: Megazord.init() must be called as soon as possible ... // Note: Megazord.init() must be called as soon as possible ...
Megazord.init() Megazord.init()

View File

@ -65,11 +65,11 @@ class AddonDetailsBindingDelegate(
addon.rating?.let { rating -> addon.rating?.let { rating ->
val resources = binding.root.resources val resources = binding.root.resources
val ratingContentDescription = val ratingContentDescription =
resources.getString(R.string.mozac_feature_addons_rating_content_description_2) resources.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_rating_content_description_2)
binding.ratingLabel.contentDescription = String.format(ratingContentDescription, rating.average) binding.ratingLabel.contentDescription = String.format(ratingContentDescription, rating.average)
binding.ratingView.rating = rating.average binding.ratingView.rating = rating.average
val reviewCount = resources.getString(R.string.mozac_feature_addons_user_rating_count_2) val reviewCount = resources.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_user_rating_count_2)
binding.reviewCount.contentDescription = String.format(reviewCount, numberFormatter.format(rating.reviews)) binding.reviewCount.contentDescription = String.format(reviewCount, numberFormatter.format(rating.reviews))
binding.reviewCount.text = numberFormatter.format(rating.reviews) binding.reviewCount.text = numberFormatter.format(rating.reviews)

View File

@ -119,7 +119,7 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
binding?.let { binding?.let {
showSnackBar( showSnackBar(
it.root, it.root,
getString(R.string.mozac_feature_addons_failed_to_query_extensions), getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_query_extensions),
) )
} }
binding?.addOnsProgressBar?.isVisible = false binding?.addOnsProgressBar?.isVisible = false

View File

@ -130,7 +130,7 @@ class InstalledAddonDetailsFragment : Fragment() {
runIfFragmentIsAttached { runIfFragmentIsAttached {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString(R.string.mozac_feature_addons_failed_to_query_extensions), getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_query_extensions),
) )
findNavController().popBackStack() findNavController().popBackStack()
} }
@ -189,7 +189,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_successfully_enabled, mozilla.components.feature.addons.R.string.mozac_feature_addons_successfully_enabled,
addon.translateName(it), addon.translateName(it),
), ),
) )
@ -205,7 +205,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_failed_to_enable, mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_enable,
addon.translateName(it), addon.translateName(it),
), ),
) )
@ -227,7 +227,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_successfully_disabled, mozilla.components.feature.addons.R.string.mozac_feature_addons_successfully_disabled,
addon.translateName(it), addon.translateName(it),
), ),
) )
@ -243,7 +243,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_failed_to_disable, mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_disable,
addon.translateName(it), addon.translateName(it),
), ),
) )
@ -285,7 +285,7 @@ class InstalledAddonDetailsFragment : Fragment() {
if (addon.incognito == Addon.Incognito.NOT_ALLOWED) { if (addon.incognito == Addon.Incognito.NOT_ALLOWED) {
switch.isChecked = false switch.isChecked = false
switch.isEnabled = false switch.isEnabled = false
switch.text = requireContext().getString(R.string.mozac_feature_addons_not_allowed_in_private_browsing) switch.text = requireContext().getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_not_allowed_in_private_browsing)
return return
} }
@ -392,7 +392,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_successfully_uninstalled, mozilla.components.feature.addons.R.string.mozac_feature_addons_successfully_uninstalled,
addon.translateName(it), addon.translateName(it),
), ),
) )
@ -407,7 +407,7 @@ class InstalledAddonDetailsFragment : Fragment() {
showSnackBar( showSnackBar(
binding.root, binding.root,
getString( getString(
R.string.mozac_feature_addons_failed_to_uninstall, mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_uninstall,
addon.translateName(it), addon.translateName(it),
), ),
) )

View File

@ -55,12 +55,12 @@ class NotYetSupportedAddonFragment :
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
showToolbar(getString(R.string.mozac_feature_addons_unavailable_section)) showToolbar(getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_unavailable_section))
} }
override fun onUninstallError(addonId: String, throwable: Throwable) { override fun onUninstallError(addonId: String, throwable: Throwable) {
this@NotYetSupportedAddonFragment.view?.let { view -> this@NotYetSupportedAddonFragment.view?.let { view ->
showSnackBar(view, getString(R.string.mozac_feature_addons_failed_to_remove, "")) showSnackBar(view, getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_remove, ""))
} }
if (unsupportedAddonsAdapter?.itemCount == 0) { if (unsupportedAddonsAdapter?.itemCount == 0) {
@ -70,7 +70,7 @@ class NotYetSupportedAddonFragment :
override fun onUninstallSuccess() { override fun onUninstallSuccess() {
this@NotYetSupportedAddonFragment.view?.let { view -> this@NotYetSupportedAddonFragment.view?.let { view ->
showSnackBar(view, getString(R.string.mozac_feature_addons_successfully_removed, "")) showSnackBar(view, getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_successfully_removed, ""))
} }
} }
} }

View File

@ -416,7 +416,7 @@ abstract class BaseBrowserFragment :
view = view view = view
) )
browserToolbarView.view.display.setOnSiteSecurityClickedListener { browserToolbarView.view.display.setOnSiteInfoClickedListener {
showQuickSettingsDialog() showQuickSettingsDialog()
} }
@ -720,7 +720,7 @@ abstract class BaseBrowserFragment :
gravity = getAppropriateLayoutGravity(), gravity = getAppropriateLayoutGravity(),
shouldWidthMatchParent = true, shouldWidthMatchParent = true,
positiveButtonBackgroundColor = accentHighContrastColor, positiveButtonBackgroundColor = accentHighContrastColor,
positiveButtonTextColor = R.color.photonWhite positiveButtonTextColor = mozilla.components.ui.colors.R.color.photonWhite
), ),
sessionId = customTabSessionId, sessionId = customTabSessionId,
onNeedToRequestPermissions = { permissions -> onNeedToRequestPermissions = { permissions ->

View File

@ -69,7 +69,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
val homeAction = BrowserToolbar.Button( val homeAction = BrowserToolbar.Button(
imageDrawable = AppCompatResources.getDrawable( imageDrawable = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_home_24 mozilla.components.ui.icons.R.drawable.mozac_ic_home_24
)!!, )!!,
contentDescription = context.getString(R.string.browser_toolbar_home), contentDescription = context.getString(R.string.browser_toolbar_home),
iconTintColorResource = ThemeManager.resolveAttribute(R.attr.textPrimary, context), iconTintColorResource = ThemeManager.resolveAttribute(R.attr.textPrimary, context),
@ -84,7 +84,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
val backAction = BrowserToolbar.TwoStateButton( val backAction = BrowserToolbar.TwoStateButton(
primaryImage = AppCompatResources.getDrawable( primaryImage = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_back_24 mozilla.components.ui.icons.R.drawable.mozac_ic_back_24
)!!, )!!,
primaryContentDescription = context.getString(R.string.browser_menu_back), primaryContentDescription = context.getString(R.string.browser_menu_back),
primaryImageTintResource = enableTint, primaryImageTintResource = enableTint,
@ -106,7 +106,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
val forwardAction = BrowserToolbar.TwoStateButton( val forwardAction = BrowserToolbar.TwoStateButton(
primaryImage = AppCompatResources.getDrawable( primaryImage = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_forward_24 mozilla.components.ui.icons.R.drawable.mozac_ic_forward_24
)!!, )!!,
primaryContentDescription = context.getString(R.string.browser_menu_forward), primaryContentDescription = context.getString(R.string.browser_menu_forward),
primaryImageTintResource = enableTint, primaryImageTintResource = enableTint,
@ -128,7 +128,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
val refreshAction = BrowserToolbar.TwoStateButton( val refreshAction = BrowserToolbar.TwoStateButton(
primaryImage = AppCompatResources.getDrawable( primaryImage = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_arrow_clockwise_24 mozilla.components.ui.icons.R.drawable.mozac_ic_arrow_clockwise_24
)!!, )!!,
primaryContentDescription = context.getString(R.string.browser_menu_refresh), primaryContentDescription = context.getString(R.string.browser_menu_refresh),
primaryImageTintResource = enableTint, primaryImageTintResource = enableTint,
@ -137,7 +137,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
}, },
secondaryImage = AppCompatResources.getDrawable( secondaryImage = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_stop mozilla.components.ui.icons.R.drawable.mozac_ic_stop
)!!, )!!,
secondaryContentDescription = context.getString(R.string.browser_menu_stop), secondaryContentDescription = context.getString(R.string.browser_menu_stop),
disableInSecondaryState = false, disableInSecondaryState = false,

View File

@ -44,8 +44,8 @@ class TabPreview @JvmOverloads constructor(
} }
// Change view properties to avoid confusing the UI tests // Change view properties to avoid confusing the UI tests
binding.tabButton.findViewById<View>(R.id.counter_box).id = View.NO_ID binding.tabButton.findViewById<View>(mozilla.components.ui.tabcounter.R.id.counter_box).id = View.NO_ID
binding.tabButton.findViewById<View>(R.id.counter_text).id = View.NO_ID binding.tabButton.findViewById<View>(mozilla.components.ui.tabcounter.R.id.counter_text).id = View.NO_ID
} }
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {

View File

@ -21,7 +21,7 @@ import mozilla.components.browser.toolbar.BrowserToolbar
* - immediately below the toolbar (toolbar fully expanded). * - immediately below the toolbar (toolbar fully expanded).
*/ */
class DynamicInfoBannerBehavior( class DynamicInfoBannerBehavior(
context: Context?, context: Context,
attrs: AttributeSet? attrs: AttributeSet?
) : CoordinatorLayout.Behavior<View>(context, attrs) { ) : CoordinatorLayout.Behavior<View>(context, attrs) {
@VisibleForTesting @VisibleForTesting

View File

@ -67,8 +67,8 @@ class DefaultReaderModeController(
private fun themeReaderViewControlsForPrivateMode(view: View) = with(view) { private fun themeReaderViewControlsForPrivateMode(view: View) = with(view) {
listOf( listOf(
R.id.mozac_feature_readerview_font_size_decrease, mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_decrease,
R.id.mozac_feature_readerview_font_size_increase, mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_size_increase,
).map { ).map {
findViewById<Button>(it) findViewById<Button>(it)
}.forEach { }.forEach {
@ -76,8 +76,8 @@ class DefaultReaderModeController(
} }
listOf( listOf(
R.id.mozac_feature_readerview_font_serif, mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_serif,
R.id.mozac_feature_readerview_font_sans_serif, mozilla.components.feature.readerview.R.id.mozac_feature_readerview_font_sans_serif,
).map { ).map {
findViewById<RadioButton>(it) findViewById<RadioButton>(it)
}.forEach { }.forEach {

View File

@ -40,7 +40,7 @@ class CollectionCreationBottomBarView(
iconButton.apply { iconButton.apply {
val drawable = context.getDrawableWithTint( val drawable = context.getDrawableWithTint(
R.drawable.ic_close, R.drawable.ic_close,
ContextCompat.getColor(context, R.color.photonWhite) ContextCompat.getColor(context, mozilla.components.ui.colors.R.color.photonWhite)
) )
setImageDrawable(drawable) setImageDrawable(drawable)
contentDescription = context.getString(R.string.create_collection_close) contentDescription = context.getString(R.string.create_collection_close)
@ -87,7 +87,7 @@ class CollectionCreationBottomBarView(
iconButton.apply { iconButton.apply {
val drawable = context.getDrawableWithTint( val drawable = context.getDrawableWithTint(
R.drawable.ic_new, R.drawable.ic_new,
ContextCompat.getColor(context, R.color.photonWhite) ContextCompat.getColor(context, mozilla.components.ui.colors.R.color.photonWhite)
) )
setImageDrawable(drawable) setImageDrawable(drawable)
contentDescription = null contentDescription = null

View File

@ -11,7 +11,7 @@ import android.os.Build
import mozilla.components.concept.base.crash.Breadcrumb import mozilla.components.concept.base.crash.Breadcrumb
import mozilla.components.lib.crash.Crash import mozilla.components.lib.crash.Crash
import mozilla.components.lib.crash.CrashReporter import mozilla.components.lib.crash.CrashReporter
import mozilla.components.lib.crash.sentry.SentryService //import mozilla.components.lib.crash.sentry.SentryService
import mozilla.components.lib.crash.service.CrashReporterService import mozilla.components.lib.crash.service.CrashReporterService
import net.waterfox.android.* import net.waterfox.android.*
import net.waterfox.android.ext.components import net.waterfox.android.ext.components
@ -27,24 +27,8 @@ class Analytics(
val crashReporter: CrashReporter by lazyMonitored { val crashReporter: CrashReporter by lazyMonitored {
val services = mutableListOf<CrashReporterService>() val services = mutableListOf<CrashReporterService>()
if (isSentryEnabled()) { if (isSentryEnabled()) {}
val shouldSendCaughtExceptions = Config.channel == ReleaseChannel.Release else {
val sentryService = SentryService(
context,
BuildConfig.SENTRY_TOKEN,
tags = mapOf(
"geckoview" to "$MOZ_APP_VERSION-$MOZ_APP_BUILDID",
"waterfox.git" to BuildConfig.GIT_HASH
),
environment = BuildConfig.BUILD_TYPE,
sendEventForNativeCrashes = false, // Do not send native crashes to Sentry
sendCaughtExceptions = shouldSendCaughtExceptions,
sentryProjectUrl = getSentryProjectUrl()
)
services.add(sentryService)
} else {
// At least one service needs to be added to the services list, // At least one service needs to be added to the services list,
// so we add a No Op implementation if Sentry is disabled (like in case of debug builds). // so we add a No Op implementation if Sentry is disabled (like in case of debug builds).
services.add(NoOpCrashReporterService) services.add(NoOpCrashReporterService)

View File

@ -58,7 +58,7 @@ private val DEFAULT_SYNCED_TABS_COMMANDS_EXTRA_FLUSH_DELAY = 5.seconds
@Suppress("LongParameterList") @Suppress("LongParameterList")
class BackgroundServices( class BackgroundServices(
private val context: Context, private val context: Context,
private val push: Push,
crashReporter: CrashReporter, crashReporter: CrashReporter,
historyStorage: Lazy<PlacesHistoryStorage>, historyStorage: Lazy<PlacesHistoryStorage>,
bookmarkStorage: Lazy<PlacesBookmarksStorage>, bookmarkStorage: Lazy<PlacesBookmarksStorage>,
@ -189,7 +189,9 @@ class BackgroundServices(
accountManager.register(AccountManagerReadyObserver(accountManagerAvailableQueue)) accountManager.register(AccountManagerReadyObserver(accountManagerAvailableQueue))
// Enable push if it's configured. // Enable push if it's configured.
push.feature?.let { autoPushFeature ->
FxaPushSupportFeature(context, accountManager, autoPushFeature, crashReporter)
}
SendTabFeature(accountManager) { device, tabs -> SendTabFeature(accountManager) { device, tabs ->
notificationManager.showReceivedTabs(context, device, tabs) notificationManager.showReceivedTabs(context, device, tabs)

View File

@ -60,6 +60,7 @@ class Components(private val context: Context) {
val backgroundServices by lazyMonitored { val backgroundServices by lazyMonitored {
BackgroundServices( BackgroundServices(
context, context,
push,
analytics.crashReporter, analytics.crashReporter,
core.lazyHistoryStorage, core.lazyHistoryStorage,
core.lazyBookmarksStorage, core.lazyBookmarksStorage,
@ -155,7 +156,7 @@ class Components(private val context: Context) {
val publicSuffixList by lazyMonitored { PublicSuffixList(context) } val publicSuffixList by lazyMonitored { PublicSuffixList(context) }
val clipboardHandler by lazyMonitored { ClipboardHandler(context) } val clipboardHandler by lazyMonitored { ClipboardHandler(context) }
val performance by lazyMonitored { PerformanceComponent() } val performance by lazyMonitored { PerformanceComponent() }
val push by lazyMonitored { Push(context, analytics.crashReporter) }
val wifiConnectionMonitor by lazyMonitored { WifiConnectionMonitor(context as Application) } val wifiConnectionMonitor by lazyMonitored { WifiConnectionMonitor(context as Application) }
val strictMode by lazyMonitored { StrictModeManager(Config, this) } val strictMode by lazyMonitored { StrictModeManager(Config, this) }

View File

@ -0,0 +1,47 @@
/* 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 net.waterfox.android.components
import android.content.Context
import mozilla.components.feature.push.AutoPushFeature
import mozilla.components.feature.push.PushConfig
import mozilla.components.lib.crash.CrashReporter
import mozilla.components.support.base.log.logger.Logger
import net.waterfox.android.R
import net.waterfox.android.perf.lazyMonitored
import net.waterfox.android.push.FirebasePushService
/**
* Component group for push services. These components use services that strongly depend on
* push messaging (e.g. WebPush, SendTab).
*/
class Push(context: Context, crashReporter: CrashReporter) {
val feature by lazyMonitored {
pushConfig?.let { config ->
AutoPushFeature(
context = context,
service = pushService,
config = config,
crashReporter = crashReporter
)
}
}
private val pushConfig: PushConfig? by lazyMonitored {
val logger = Logger("PushConfig")
val projectIdKey = context.getString(R.string.pref_key_push_project_id)
val resId = context.resources.getIdentifier(projectIdKey, "string", context.packageName)
if (resId == 0) {
logger.warn("No firebase configuration found; cannot support push service.")
return@lazyMonitored null
}
logger.debug("Creating push configuration for autopush.")
val projectId = context.resources.getString(resId)
PushConfig(projectId)
}
private val pushService by lazyMonitored { FirebasePushService() }
}

View File

@ -92,7 +92,7 @@ class BrowserToolbarCFRPresenter(
CFRPopup( CFRPopup(
text = context.getString(R.string.tcp_cfr_message), text = context.getString(R.string.tcp_cfr_message),
anchor = toolbar.findViewById( anchor = toolbar.findViewById(
R.id.mozac_browser_toolbar_security_indicator mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_site_info_indicator
), ),
properties = CFRPopupProperties( properties = CFRPopupProperties(
popupAlignment = INDICATOR_CENTERED_IN_ANCHOR, popupAlignment = INDICATOR_CENTERED_IN_ANCHOR,

View File

@ -114,8 +114,8 @@ class BrowserToolbarView(
display.colors = display.colors.copy( display.colors = display.colors.copy(
text = primaryTextColor, text = primaryTextColor,
securityIconSecure = primaryTextColor, siteInfoIconSecure = primaryTextColor,
securityIconInsecure = Color.TRANSPARENT, siteInfoIconInsecure = Color.TRANSPARENT,
menu = primaryTextColor, menu = primaryTextColor,
hint = secondaryTextColor, hint = secondaryTextColor,
separator = separatorColor, separator = separatorColor,

View File

@ -177,7 +177,7 @@ open class DefaultToolbarMenu(
private val installToHomescreen = BrowserMenuHighlightableItem( private val installToHomescreen = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_install_on_homescreen), label = context.getString(R.string.browser_menu_install_on_homescreen),
startImageResource = R.drawable.mozac_ic_add_to_homescreen_24, startImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_add_to_homescreen_24,
iconTintColorResource = primaryTextColor(), iconTintColorResource = primaryTextColor(),
highlight = BrowserMenuHighlight.LowPriority( highlight = BrowserMenuHighlight.LowPriority(
label = context.getString(R.string.browser_menu_install_on_homescreen), label = context.getString(R.string.browser_menu_install_on_homescreen),
@ -222,7 +222,7 @@ open class DefaultToolbarMenu(
private val findInPageItem = BrowserMenuImageText( private val findInPageItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_find_in_page), label = context.getString(R.string.browser_menu_find_in_page),
imageResource = R.drawable.mozac_ic_search_24, imageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_search_24,
iconTintColorResource = primaryTextColor() iconTintColorResource = primaryTextColor()
) { ) {
onItemTapped.invoke(ToolbarMenu.Item.FindInPage) onItemTapped.invoke(ToolbarMenu.Item.FindInPage)
@ -266,7 +266,7 @@ open class DefaultToolbarMenu(
private val addToHomeScreenItem = BrowserMenuImageText( private val addToHomeScreenItem = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_add_to_homescreen), label = context.getString(R.string.browser_menu_add_to_homescreen),
imageResource = R.drawable.mozac_ic_add_to_homescreen_24, imageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_add_to_homescreen_24,
iconTintColorResource = primaryTextColor(), iconTintColorResource = primaryTextColor(),
isCollapsingMenuLimit = true isCollapsingMenuLimit = true
) { ) {
@ -302,7 +302,7 @@ open class DefaultToolbarMenu(
@VisibleForTesting @VisibleForTesting
internal val settingsItem = BrowserMenuHighlightableItem( internal val settingsItem = BrowserMenuHighlightableItem(
label = context.getString(R.string.browser_menu_settings), label = context.getString(R.string.browser_menu_settings),
startImageResource = R.drawable.mozac_ic_settings_24, startImageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_settings_24,
iconTintColorResource = if (hasAccountProblem) { iconTintColorResource = if (hasAccountProblem) {
ThemeManager.resolveAttribute(R.attr.syncDisconnected, context) ThemeManager.resolveAttribute(R.attr.syncDisconnected, context)
} else { } else {
@ -342,7 +342,7 @@ open class DefaultToolbarMenu(
private val quitItem = BrowserMenuImageText( private val quitItem = BrowserMenuImageText(
label = context.getString(R.string.delete_browsing_data_on_quit_action), label = context.getString(R.string.delete_browsing_data_on_quit_action),
imageResource = R.drawable.mozac_ic_cross_circle_24, imageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_cross_circle_24,
iconTintColorResource = primaryTextColor() iconTintColorResource = primaryTextColor()
) { ) {
onItemTapped.invoke(ToolbarMenu.Item.Quit) onItemTapped.invoke(ToolbarMenu.Item.Quit)

View File

@ -67,7 +67,7 @@ fun ClearableEditText(
if (shouldShowClearButton()) { if (shouldShowClearButton()) {
IconButton(onClick = onClearClicked) { IconButton(onClick = onClearClicked) {
Image( Image(
painter = painterResource(id = R.drawable.mozac_ic_cross_circle_fill_24), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_cross_circle_fill_24),
contentDescription = null, contentDescription = null,
colorFilter = ColorFilter.tint(WaterfoxTheme.colors.textPrimary), colorFilter = ColorFilter.tint(WaterfoxTheme.colors.textPrimary),
) )
@ -120,7 +120,7 @@ fun ClearableEditTextPreview() {
onValueChanged = { value.value = it }, onValueChanged = { value.value = it },
onClearClicked = { value.value = "" }, onClearClicked = { value.value = "" },
errorMessage = stringResource(id = R.string.bookmark_invalid_url_error), errorMessage = stringResource(id = R.string.bookmark_invalid_url_error),
errorDrawable = R.drawable.mozac_ic_warning_fill_24, errorDrawable = mozilla.components.ui.icons.R.drawable.mozac_ic_warning_fill_24,
keyboardType = KeyboardType.Uri, keyboardType = KeyboardType.Uri,
) )
} }

View File

@ -28,7 +28,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import net.waterfox.android.R import net.waterfox.android.R
import net.waterfox.android.R.drawable
import net.waterfox.android.theme.WaterfoxTheme import net.waterfox.android.theme.WaterfoxTheme
/** /**
@ -124,7 +123,7 @@ fun CFRPopupContent(
.size(48.dp) .size(48.dp)
) { ) {
Icon( Icon(
painter = painterResource(drawable.mozac_ic_cross_20), painter = painterResource(mozilla.components.ui.icons.R.drawable.mozac_ic_cross_20),
contentDescription = stringResource(R.string.cfr_dismiss_button_default_content_description), contentDescription = stringResource(R.string.cfr_dismiss_button_default_content_description),
modifier = Modifier modifier = Modifier
// Following alignment and padding are necessary to visually align the middle // Following alignment and padding are necessary to visually align the middle

View File

@ -40,10 +40,10 @@ fun MediaImage(
) { ) {
val (icon, contentDescription) = when (tab.mediaSessionState?.playbackState) { val (icon, contentDescription) = when (tab.mediaSessionState?.playbackState) {
PlaybackState.PAUSED -> { PlaybackState.PAUSED -> {
R.drawable.media_state_play to R.string.mozac_feature_media_notification_action_play R.drawable.media_state_play to mozilla.components.feature.media.R.string.mozac_feature_media_notification_action_play
} }
PlaybackState.PLAYING -> { PlaybackState.PLAYING -> {
R.drawable.media_state_pause to R.string.mozac_feature_media_notification_action_pause R.drawable.media_state_pause to mozilla.components.feature.media.R.string.mozac_feature_media_notification_action_pause
} }
else -> return else -> return
} }

View File

@ -230,7 +230,7 @@ fun TabGridItem(
}, },
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.mozac_ic_cross_20), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_cross_20),
contentDescription = stringResource(id = R.string.close_tab), contentDescription = stringResource(id = R.string.close_tab),
tint = WaterfoxTheme.colors.iconPrimary, tint = WaterfoxTheme.colors.iconPrimary,
) )
@ -313,12 +313,12 @@ private fun Thumbnail(
backgroundColor = WaterfoxTheme.colors.layerAccent, backgroundColor = WaterfoxTheme.colors.layerAccent,
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.mozac_ic_checkmark_24), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_checkmark_24),
modifier = Modifier modifier = Modifier
.matchParentSize() .matchParentSize()
.padding(all = 8.dp), .padding(all = 8.dp),
contentDescription = null, contentDescription = null,
tint = colorResource(id = R.color.mozac_ui_icons_fill), tint = colorResource(id = mozilla.components.ui.icons.R.color.mozac_ui_icons_fill),
) )
} }
} }

View File

@ -187,7 +187,7 @@ fun TabListItem(
.testTag(TabsTrayTestTag.tabItemClose), .testTag(TabsTrayTestTag.tabItemClose),
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.mozac_ic_cross_24), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_cross_24),
contentDescription = stringResource( contentDescription = stringResource(
id = R.string.close_tab_title, id = R.string.close_tab_title,
tab.content.title, tab.content.title,
@ -228,7 +228,7 @@ private fun Thumbnail(
.semantics(mergeDescendants = true) { .semantics(mergeDescendants = true) {
testTag = TabsTrayTestTag.tabItemThumbnail testTag = TabsTrayTestTag.tabItemThumbnail
}, },
contentDescription = stringResource(id = R.string.mozac_browser_tabstray_open_tab), contentDescription = stringResource(id = mozilla.components.browser.tabstray.R.string.mozac_browser_tabstray_open_tab),
) )
if (isSelected) { if (isSelected) {
@ -247,12 +247,12 @@ private fun Thumbnail(
backgroundColor = WaterfoxTheme.colors.layerAccent, backgroundColor = WaterfoxTheme.colors.layerAccent,
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.mozac_ic_checkmark_24), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_checkmark_24),
modifier = Modifier modifier = Modifier
.matchParentSize() .matchParentSize()
.padding(all = 8.dp), .padding(all = 8.dp),
contentDescription = null, contentDescription = null,
tint = colorResource(id = R.color.mozac_ui_icons_fill), tint = colorResource(id = mozilla.components.ui.icons.R.color.mozac_ui_icons_fill),
) )
} }
} }

View File

@ -142,7 +142,7 @@ class CustomTabToolbarMenu(
private val findInPage = BrowserMenuImageText( private val findInPage = BrowserMenuImageText(
label = context.getString(R.string.browser_menu_find_in_page), label = context.getString(R.string.browser_menu_find_in_page),
imageResource = R.drawable.mozac_ic_search_24, imageResource = mozilla.components.ui.icons.R.drawable.mozac_ic_search_24,
iconTintColorResource = primaryTextColor() iconTintColorResource = primaryTextColor()
) { ) {
onItemTapped.invoke(ToolbarMenu.Item.FindInPage) onItemTapped.invoke(ToolbarMenu.Item.FindInPage)

View File

@ -81,7 +81,7 @@ class PoweredByNotification(
val channel = NotificationChannel( val channel = NotificationChannel(
NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
applicationContext.getString(R.string.mozac_feature_pwa_site_controls_notification_channel), applicationContext.getString(mozilla.components.feature.pwa.R.string.mozac_feature_pwa_site_controls_notification_channel),
NotificationManager.IMPORTANCE_MIN NotificationManager.IMPORTANCE_MIN
) )

View File

@ -6,6 +6,8 @@ package net.waterfox.android.downloads
import mozilla.components.browser.state.store.BrowserStore import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.feature.downloads.AbstractFetchDownloadService import mozilla.components.feature.downloads.AbstractFetchDownloadService
import mozilla.components.feature.downloads.DefaultFileSizeFormatter
import mozilla.components.feature.downloads.FileSizeFormatter
import mozilla.components.support.base.android.NotificationsDelegate import mozilla.components.support.base.android.NotificationsDelegate
import net.waterfox.android.R import net.waterfox.android.R
import net.waterfox.android.ext.components import net.waterfox.android.ext.components
@ -15,4 +17,5 @@ class DownloadService : AbstractFetchDownloadService() {
override val store: BrowserStore by lazy { components.core.store } override val store: BrowserStore by lazy { components.core.store }
override val style: Style by lazy { Style(R.color.fx_mobile_text_color_accent) } override val style: Style by lazy { Style(R.color.fx_mobile_text_color_accent) }
override val notificationsDelegate: NotificationsDelegate by lazy { components.notificationsDelegate } override val notificationsDelegate: NotificationsDelegate by lazy { components.notificationsDelegate }
override val fileSizeFormatter: FileSizeFormatter by lazy { DefaultFileSizeFormatter(this) }
} }

View File

@ -63,7 +63,7 @@ class DynamicDownloadDialog(
if (didFail) { if (didFail) {
binding.downloadDialogTitle.text = binding.downloadDialogTitle.text =
context.getString(R.string.mozac_feature_downloads_failed_notification_text2) context.getString(mozilla.components.feature.downloads.R.string.mozac_feature_downloads_failed_notification_text2)
binding.downloadDialogIcon.setImageResource( binding.downloadDialogIcon.setImageResource(
mozilla.components.feature.downloads.R.drawable.mozac_feature_download_ic_download_failed mozilla.components.feature.downloads.R.drawable.mozac_feature_download_ic_download_failed
@ -80,7 +80,7 @@ class DynamicDownloadDialog(
} }
} else { } else {
val titleText = context.getString( val titleText = context.getString(
R.string.mozac_feature_downloads_completed_notification_text2 mozilla.components.feature.downloads.R.string.mozac_feature_downloads_completed_notification_text2
) + " (${downloadState.contentLength?.toMegabyteOrKilobyteString()})" ) + " (${downloadState.contentLength?.toMegabyteOrKilobyteString()})"
binding.downloadDialogTitle.text = titleText binding.downloadDialogTitle.text = titleText
@ -96,7 +96,9 @@ class DynamicDownloadDialog(
setOnClickListener { setOnClickListener {
val fileWasOpened = AbstractFetchDownloadService.openFile( val fileWasOpened = AbstractFetchDownloadService.openFile(
applicationContext = context.applicationContext, applicationContext = context.applicationContext,
download = downloadState downloadFileName = downloadState.fileName,
downloadFilePath = downloadState.filePath,
downloadContentType = downloadState.contentType
) )
if (!fileWasOpened) { if (!fileWasOpened) {
@ -134,7 +136,7 @@ class DynamicDownloadDialog(
download.filePath download.filePath
) )
return context.getString( return context.getString(
R.string.mozac_feature_downloads_open_not_supported1, fileExt mozilla.components.feature.downloads.R.string.mozac_feature_downloads_open_not_supported1, fileExt
) )
} }
} }

View File

@ -29,7 +29,7 @@ import kotlin.math.min
private const val SNAP_ANIMATION_DURATION = 150L private const val SNAP_ANIMATION_DURATION = 150L
class DynamicDownloadDialogBehavior<V : View>( class DynamicDownloadDialogBehavior<V : View>(
context: Context?, context: Context,
attrs: AttributeSet?, attrs: AttributeSet?,
private val bottomToolbarHeight: Float = 0f private val bottomToolbarHeight: Float = 0f
) : CoordinatorLayout.Behavior<V>(context, attrs) { ) : CoordinatorLayout.Behavior<V>(context, attrs) {

View File

@ -167,17 +167,17 @@ class WebExtensionPromptFeature(
val addonName = exception.extensionName ?: "" val addonName = exception.extensionName ?: ""
val appName = context.getString(R.string.app_name) val appName = context.getString(R.string.app_name)
var title = context.getString(R.string.mozac_feature_addons_cant_install_extension) var title = context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_cant_install_extension)
var url: String? = null var url: String? = null
val message = when (exception) { val message = when (exception) {
is WebExtensionInstallException.Blocklisted -> { is WebExtensionInstallException.Blocklisted -> {
url = formatBlocklistURL(exception) url = formatBlocklistURL(exception)
context.getString(R.string.mozac_feature_addons_blocklisted_2, addonName, appName) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_blocklisted_2, addonName, appName)
} }
is WebExtensionInstallException.SoftBlocked -> { is WebExtensionInstallException.SoftBlocked -> {
url = formatBlocklistURL(exception) url = formatBlocklistURL(exception)
context.getString(R.string.mozac_feature_addons_soft_blocked_1, addonName, appName) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_soft_blocked_1, addonName, appName)
} }
is WebExtensionInstallException.UserCancelled -> { is WebExtensionInstallException.UserCancelled -> {
@ -193,34 +193,34 @@ class WebExtensionPromptFeature(
// Message = Failed to install $addonName // Message = Failed to install $addonName
title = "" title = ""
if (addonName.isNotEmpty()) { if (addonName.isNotEmpty()) {
context.getString(R.string.mozac_feature_addons_failed_to_install, addonName) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_install, addonName)
} else { } else {
context.getString(R.string.mozac_feature_addons_extension_failed_to_install) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_extension_failed_to_install)
} }
} }
is WebExtensionInstallException.AdminInstallOnly -> { is WebExtensionInstallException.AdminInstallOnly -> {
context.getString(R.string.mozac_feature_addons_admin_install_only, addonName) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_admin_install_only, addonName)
} }
is WebExtensionInstallException.NetworkFailure -> { is WebExtensionInstallException.NetworkFailure -> {
context.getString(R.string.mozac_feature_addons_extension_failed_to_install_network_error) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_extension_failed_to_install_network_error)
} }
is WebExtensionInstallException.CorruptFile -> { is WebExtensionInstallException.CorruptFile -> {
context.getString(R.string.mozac_feature_addons_extension_failed_to_install_corrupt_error) context.getString(mozilla.components.feature.addons.R.string.mozac_feature_addons_extension_failed_to_install_corrupt_error)
} }
is WebExtensionInstallException.NotSigned -> { is WebExtensionInstallException.NotSigned -> {
context.getString( context.getString(
R.string.mozac_feature_addons_extension_failed_to_install_not_signed_error, mozilla.components.feature.addons.R.string.mozac_feature_addons_extension_failed_to_install_not_signed_error,
) )
} }
is WebExtensionInstallException.Incompatible -> { is WebExtensionInstallException.Incompatible -> {
val version = context.appVersionName val version = context.appVersionName
context.getString( context.getString(
R.string.mozac_feature_addons_failed_to_install_incompatible_error, mozilla.components.feature.addons.R.string.mozac_feature_addons_failed_to_install_incompatible_error,
addonName, addonName,
appName, appName,
version, version,

View File

@ -79,7 +79,7 @@ class HomeMenu(
private val quitItem by lazy { private val quitItem by lazy {
BrowserMenuImageText( BrowserMenuImageText(
context.getString(R.string.delete_browsing_data_on_quit_action), context.getString(R.string.delete_browsing_data_on_quit_action),
R.drawable.mozac_ic_cross_circle_24, mozilla.components.ui.icons.R.drawable.mozac_ic_cross_circle_24,
primaryTextColor primaryTextColor
) { ) {
onItemTapped.invoke(Item.Quit) onItemTapped.invoke(Item.Quit)
@ -154,7 +154,7 @@ class HomeMenu(
val helpItem = BrowserMenuImageText( val helpItem = BrowserMenuImageText(
context.getString(R.string.browser_menu_help), context.getString(R.string.browser_menu_help),
R.drawable.mozac_ic_help_circle_24, mozilla.components.ui.icons.R.drawable.mozac_ic_help_circle_24,
primaryTextColor primaryTextColor
) { ) {
onItemTapped.invoke(Item.Help) onItemTapped.invoke(Item.Help)
@ -170,7 +170,7 @@ class HomeMenu(
val settingsItem = BrowserMenuImageText( val settingsItem = BrowserMenuImageText(
context.getString(R.string.browser_menu_settings), context.getString(R.string.browser_menu_settings),
R.drawable.mozac_ic_settings_24, mozilla.components.ui.icons.R.drawable.mozac_ic_settings_24,
primaryTextColor primaryTextColor
) { ) {
onItemTapped.invoke(Item.Settings) onItemTapped.invoke(Item.Settings)

View File

@ -121,7 +121,7 @@ fun <T> LibrarySiteItem(
), ),
) { ) {
Icon( Icon(
painter = painterResource(R.drawable.mozac_ic_checkmark_24), painter = painterResource(mozilla.components.ui.icons.R.drawable.mozac_ic_checkmark_24),
contentDescription = null, contentDescription = null,
modifier = Modifier modifier = Modifier
.padding(10.dp) .padding(10.dp)
@ -129,7 +129,7 @@ fun <T> LibrarySiteItem(
testTagsAsResourceId = true testTagsAsResourceId = true
testTag = "library.site.item.checkmark" testTag = "library.site.item.checkmark"
}, },
tint = colorResource(R.color.mozac_ui_icons_fill), tint = colorResource(mozilla.components.ui.icons.R.color.mozac_ui_icons_fill),
) )
} }
} }

View File

@ -230,7 +230,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
} catch (e: PlacesApiException.UrlParseFailed) { } catch (e: PlacesApiException.UrlParseFailed) {
withContext(Main) { withContext(Main) {
binding.bookmarkContent.bookmarkUrlErrorMessage = getString(R.string.bookmark_invalid_url_error) binding.bookmarkContent.bookmarkUrlErrorMessage = getString(R.string.bookmark_invalid_url_error)
binding.bookmarkContent.bookmarkUrlErrorDrawable = R.drawable.mozac_ic_warning_fill_24 binding.bookmarkContent.bookmarkUrlErrorDrawable = mozilla.components.ui.icons.R.drawable.mozac_ic_warning_fill_24
} }
} }
} }

View File

@ -48,7 +48,7 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?,
): View { ): View {
_binding = FragmentDownloadsBinding.inflate(inflater, container, false) _binding = FragmentDownloadsBinding.inflate(inflater, container, false)
@ -60,15 +60,15 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
items = items, items = items,
mode = DownloadFragmentState.Mode.Normal, mode = DownloadFragmentState.Mode.Normal,
pendingDeletionIds = emptySet(), pendingDeletionIds = emptySet(),
isDeletingItems = false isDeletingItems = false,
) ),
) )
} }
val downloadController: DownloadController = DefaultDownloadController( val downloadController: DownloadController = DefaultDownloadController(
downloadStore, downloadStore,
::openItem, ::openItem,
::invalidateOptionsMenu, ::invalidateOptionsMenu,
::deleteDownloadItems ::deleteDownloadItems,
) )
downloadInteractor = DownloadInteractor(downloadController) downloadInteractor = DownloadInteractor(downloadController)
binding.downloadContent.interactor = downloadInteractor binding.downloadContent.interactor = downloadInteractor
@ -98,7 +98,7 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
filePath = it.filePath, filePath = it.filePath,
size = it.contentLength?.toString() ?: "0", size = it.contentLength?.toString() ?: "0",
contentType = it.contentType, contentType = it.contentType,
status = it.status status = it.status,
) )
}.filter { }.filter {
it.status == DownloadState.Status.COMPLETED it.status == DownloadState.Status.COMPLETED
@ -130,7 +130,7 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
onCancel = { onCancel = {
undoPendingDeletion(items) undoPendingDeletion(items)
}, },
operation = getDeleteDownloadItemsOperation(items) operation = getDeleteDownloadItemsOperation(items),
) )
} }
@ -141,13 +141,14 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
binding.downloadContent.updateState(state) binding.downloadContent.updateState(state)
when (state.mode) { when (state.mode) {
is DownloadFragmentState.Mode.Normal -> setUiForNormalMode( is DownloadFragmentState.Mode.Normal -> setUiForNormalMode(
context?.getString(R.string.library_downloads) context?.getString(R.string.library_downloads),
) )
is DownloadFragmentState.Mode.Editing -> setUiForSelectingMode( is DownloadFragmentState.Mode.Editing -> setUiForSelectingMode(
context?.getString( context?.getString(
R.string.download_multi_select_title, R.string.download_multi_select_title,
state.mode.selectedItems.size, state.mode.selectedItems.size,
) ),
) )
} }
} }
@ -189,6 +190,7 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
} }
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@ -201,9 +203,9 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
} else { } else {
String.format( String.format(
requireContext().getString( requireContext().getString(
R.string.download_delete_single_item_snackbar R.string.download_delete_single_item_snackbar,
), ),
downloadItems.first().fileName downloadItems.first().fileName,
) )
} }
} }
@ -223,20 +225,15 @@ class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHan
} }
AbstractFetchDownloadService.openFile( AbstractFetchDownloadService.openFile(
applicationContext = it.applicationContext, applicationContext = it.applicationContext,
download = DownloadState( downloadFileName = item.fileName,
id = item.id, downloadFilePath = item.filePath,
url = item.url, downloadContentType = item.contentType,
fileName = item.fileName,
contentType = item.contentType,
status = item.status,
contentLength = contentLength
)
) )
} }
} }
private fun getDeleteDownloadItemsOperation( private fun getDeleteDownloadItemsOperation(
items: Set<DownloadItem> items: Set<DownloadItem>,
): (suspend (context: Context) -> Unit) { ): (suspend (context: Context) -> Unit) {
return { context -> return { context ->
CoroutineScope(IO).launch { CoroutineScope(IO).launch {

View File

@ -86,7 +86,7 @@ fun Onboarding(
onClick = { onDismiss() }, onClick = { onDismiss() },
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.mozac_ic_cross_20), painter = painterResource(id = mozilla.components.ui.icons.R.drawable.mozac_ic_cross_20),
contentDescription = stringResource(R.string.onboarding_home_content_description_close_button), contentDescription = stringResource(R.string.onboarding_home_content_description_close_button),
tint = WaterfoxTheme.colors.iconPrimary, tint = WaterfoxTheme.colors.iconPrimary,
) )

View File

@ -7,20 +7,42 @@ package net.waterfox.android.perf
import android.content.Context import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import mozilla.components.concept.base.profiler.Profiler import mozilla.components.concept.base.profiler.Profiler
import net.waterfox.android.HomeActivity import net.waterfox.android.HomeActivity
import net.waterfox.android.ext.components import net.waterfox.android.ext.components
import net.waterfox.android.perf.ProfilerMarkers.MEASURE_LAYOUT_DRAW_MARKER_NAME import net.waterfox.android.perf.ProfilerMarkers.MEASURE_LAYOUT_DRAW_MARKER_NAME
/** /**
* A [LinearLayout] that adds profiler markers for various methods. This is intended to be used on * A [LinearLayout] that adds profiler markers for various methods and handles system window insets.
* the root view of [HomeActivity]'s view hierarchy to understand global measure/layout events. * This is intended to be used on the root view of [HomeActivity]'s view hierarchy to understand
* global measure/layout events and properly handle system bars.
*/ */
class HomeActivityRootLinearLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { class HomeActivityRootLinearLayout(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private val profiler: Profiler? = context.components.core.engine.profiler private val profiler: Profiler? = context.components.core.engine.profiler
init {
// Handle system window insets to prevent content from going behind status bar
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updatePadding(
top = systemBars.top,
bottom = systemBars.bottom,
left = systemBars.left,
right = systemBars.right
)
insets
}
// Request that the system send us window insets
requestApplyInsets()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val profilerStartTime = profiler?.getProfilerTime() val profilerStartTime = profiler?.getProfilerTime()
super.onMeasure(widthMeasureSpec, heightMeasureSpec) super.onMeasure(widthMeasureSpec, heightMeasureSpec)

View File

@ -6,9 +6,11 @@ package net.waterfox.android.push
import android.annotation.SuppressLint import android.annotation.SuppressLint
import mozilla.components.feature.push.AutoPushFeature import mozilla.components.feature.push.AutoPushFeature
import mozilla.components.lib.push.firebase.AbstractFirebasePushService
/** /**
* A singleton instance of the FirebasePushService needed for communicating between FCM and the * A singleton instance of the FirebasePushService needed for communicating between FCM and the
* [AutoPushFeature]. * [AutoPushFeature].
*/ */
@SuppressLint("MissingFirebaseInstanceTokenRefresh") // Implemented internally.
class FirebasePushService : AbstractFirebasePushService()

View File

@ -18,7 +18,7 @@ import mozilla.components.feature.push.PushScope
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.manager.ext.withConstellation import mozilla.components.service.fxa.manager.ext.withConstellation
import net.waterfox.android.components.BackgroundServices import net.waterfox.android.components.BackgroundServices
import net.waterfox.android.components.Push
/** /**
* A lazy initializer for FxaAccountManager if it isn't already initialized. * A lazy initializer for FxaAccountManager if it isn't already initialized.

View File

@ -201,7 +201,7 @@ class SearchDialogFragment : AppCompatDialogFragment(), UserInteractionHandler {
binding.toolbar, binding.toolbar,
fromHomeFragment fromHomeFragment
).also { ).also {
inlineAutocompleteEditText = it.view.findViewById(R.id.mozac_browser_toolbar_edit_url_view) inlineAutocompleteEditText = it.view.findViewById(mozilla.components.browser.toolbar.R.id.mozac_browser_toolbar_edit_url_view)
} }
val awesomeBar = binding.awesomeBar val awesomeBar = binding.awesomeBar

View File

@ -29,7 +29,7 @@ class ShortcutsSuggestionProvider(
override val id: String = UUID.randomUUID().toString() override val id: String = UUID.randomUUID().toString()
private val settingsIcon by lazy { private val settingsIcon by lazy {
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_settings_24)?.apply { AppCompatResources.getDrawable(context, mozilla.components.ui.icons.R.drawable.mozac_ic_settings_24)?.apply {
colorFilter = createBlendModeColorFilterCompat( colorFilter = createBlendModeColorFilterCompat(
context.getColorFromAttr(R.attr.textPrimary), context.getColorFromAttr(R.attr.textPrimary),
SRC_IN SRC_IN

View File

@ -55,7 +55,7 @@ class SearchSelectorMenu(
start = DrawableMenuIcon( start = DrawableMenuIcon(
drawable = AppCompatResources.getDrawable( drawable = AppCompatResources.getDrawable(
context, context,
R.drawable.mozac_ic_settings_24 mozilla.components.ui.icons.R.drawable.mozac_ic_settings_24
), ),
tint = context.getColorFromAttr(R.attr.textPrimary) tint = context.getColorFromAttr(R.attr.textPrimary)
) )

View File

@ -27,7 +27,7 @@ import net.waterfox.android.ext.settings
class PreferenceBackedRadioButton @JvmOverloads constructor( class PreferenceBackedRadioButton @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.radioButtonStyle, defStyleAttr: Int = androidx.appcompat.R.attr.radioButtonStyle,
) : AppCompatRadioButton(context, attrs, defStyleAttr) { ) : AppCompatRadioButton(context, attrs, defStyleAttr) {
@VisibleForTesting @VisibleForTesting
internal var externalOnCheckedChangeListener: OnCheckedChangeListener? = null internal var externalOnCheckedChangeListener: OnCheckedChangeListener? = null

View File

@ -125,7 +125,7 @@ fun FontSizePreference(
Text( Text(
text = stringResource(R.string.accessibility_text_size_sample_text_1), text = stringResource(R.string.accessibility_text_size_sample_text_1),
modifier = Modifier modifier = Modifier
.background(colorResource(R.color.photonViolet05)) .background(colorResource(mozilla.components.ui.colors.R.color.photonViolet05))
.padding(16.dp), .padding(16.dp),
color = colorResource(R.color.text_scale_example_text_color).copy( color = colorResource(R.color.text_scale_example_text_color).copy(
alpha = if (enabled) 1f else 0.5f, alpha = if (enabled) 1f else 0.5f,

View File

@ -112,7 +112,7 @@ class LocaleSettingsComposeView @JvmOverloads constructor(
) { ) {
if (selected) { if (selected) {
Image( Image(
painterResource(R.drawable.mozac_ic_checkmark_24), painterResource(mozilla.components.ui.icons.R.drawable.mozac_ic_checkmark_24),
contentDescription = stringResource(R.string.a11y_selected_locale_content_description), contentDescription = stringResource(R.string.a11y_selected_locale_content_description),
modifier = Modifier modifier = Modifier
.align(Alignment.CenterVertically) .align(Alignment.CenterVertically)

View File

@ -18,7 +18,7 @@ fun togglePasswordReveal(passwordText: TextView, revealPasswordButton: ImageButt
) { ) {
passwordText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD passwordText.inputType = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
revealPasswordButton.setImageDrawable( revealPasswordButton.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_eye_slash_24) AppCompatResources.getDrawable(context, mozilla.components.ui.icons.R.drawable.mozac_ic_eye_slash_24)
) )
revealPasswordButton.contentDescription = revealPasswordButton.contentDescription =
context.getString(R.string.saved_login_hide_password) context.getString(R.string.saved_login_hide_password)
@ -26,7 +26,7 @@ fun togglePasswordReveal(passwordText: TextView, revealPasswordButton: ImageButt
passwordText.inputType = passwordText.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
revealPasswordButton.setImageDrawable( revealPasswordButton.setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_eye_24) AppCompatResources.getDrawable(context, mozilla.components.ui.icons.R.drawable.mozac_ic_eye_24)
) )
revealPasswordButton.contentDescription = revealPasswordButton.contentDescription =
context.getString(R.string.saved_login_reveal_password) context.getString(R.string.saved_login_reveal_password)

View File

@ -40,7 +40,7 @@ class SavedLoginsSortingStrategyMenu(
) )
val highlight = HighPriorityHighlightEffect( val highlight = HighPriorityHighlightEffect(
backgroundTint = context.getColorFromAttr(R.attr.colorControlHighlight) backgroundTint = context.getColorFromAttr(androidx.appcompat.R.attr.colorControlHighlight)
) )
return listOf( return listOf(

View File

@ -33,7 +33,7 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage import coil3.compose.AsyncImage
import net.waterfox.android.R import net.waterfox.android.R
import net.waterfox.android.compose.button.Button import net.waterfox.android.compose.button.Button
import net.waterfox.android.compose.ext.dashedBorder import net.waterfox.android.compose.ext.dashedBorder

View File

@ -52,7 +52,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage import coil3.compose.AsyncImage
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.waterfox.android.R import net.waterfox.android.R
import net.waterfox.android.compose.button.TextButton import net.waterfox.android.compose.button.TextButton

View File

@ -69,38 +69,38 @@ class AccountDeviceViewHolder(
when (option) { when (option) {
SyncShareOption.SignIn -> Triple( SyncShareOption.SignIn -> Triple(
context.getText(R.string.sync_sign_in), context.getText(R.string.sync_sign_in),
R.drawable.mozac_ic_sync_24, mozilla.components.ui.icons.R.drawable.mozac_ic_sync_24,
R.color.default_share_background R.color.default_share_background
) )
SyncShareOption.Reconnect -> Triple( SyncShareOption.Reconnect -> Triple(
context.getText(R.string.sync_reconnect), context.getText(R.string.sync_reconnect),
R.drawable.mozac_ic_warning_fill_24, mozilla.components.ui.icons.R.drawable.mozac_ic_warning_fill_24,
R.color.default_share_background R.color.default_share_background
) )
SyncShareOption.Offline -> Triple( SyncShareOption.Offline -> Triple(
context.getText(R.string.sync_offline), context.getText(R.string.sync_offline),
R.drawable.mozac_ic_warning_fill_24, mozilla.components.ui.icons.R.drawable.mozac_ic_warning_fill_24,
R.color.default_share_background R.color.default_share_background
) )
SyncShareOption.AddNewDevice -> Triple( SyncShareOption.AddNewDevice -> Triple(
context.getText(R.string.sync_connect_device), context.getText(R.string.sync_connect_device),
R.drawable.mozac_ic_plus_24, mozilla.components.ui.icons.R.drawable.mozac_ic_plus_24,
R.color.default_share_background R.color.default_share_background
) )
is SyncShareOption.SendAll -> Triple( is SyncShareOption.SendAll -> Triple(
context.getText(R.string.sync_send_to_all), context.getText(R.string.sync_send_to_all),
R.drawable.mozac_ic_select_all, mozilla.components.ui.icons.R.drawable.mozac_ic_select_all,
R.color.default_share_background R.color.default_share_background
) )
is SyncShareOption.SingleDevice -> when (option.device.deviceType) { is SyncShareOption.SingleDevice -> when (option.device.deviceType) {
DeviceType.MOBILE -> Triple( DeviceType.MOBILE -> Triple(
option.device.displayName, option.device.displayName,
R.drawable.mozac_ic_device_mobile_24, mozilla.components.ui.icons.R.drawable.mozac_ic_device_mobile_24,
R.color.device_type_mobile_background R.color.device_type_mobile_background
) )
else -> Triple( else -> Triple(
option.device.displayName, option.device.displayName,
R.drawable.mozac_ic_device_desktop_24, mozilla.components.ui.icons.R.drawable.mozac_ic_device_desktop_24,
R.color.device_type_desktop_background R.color.device_type_desktop_background
) )
} }

View File

@ -160,7 +160,7 @@ abstract class AbstractBrowserTabViewHolder(
MediaSession.PlaybackState.PAUSED -> { MediaSession.PlaybackState.PAUSED -> {
showAndEnable() showAndEnable()
contentDescription = contentDescription =
context.getString(R.string.mozac_feature_media_notification_action_play) context.getString(mozilla.components.feature.media.R.string.mozac_feature_media_notification_action_play)
setImageDrawable( setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.media_state_play), AppCompatResources.getDrawable(context, R.drawable.media_state_play),
) )
@ -169,7 +169,7 @@ abstract class AbstractBrowserTabViewHolder(
MediaSession.PlaybackState.PLAYING -> { MediaSession.PlaybackState.PLAYING -> {
showAndEnable() showAndEnable()
contentDescription = contentDescription =
context.getString(R.string.mozac_feature_media_notification_action_pause) context.getString(mozilla.components.feature.media.R.string.mozac_feature_media_notification_action_pause)
setImageDrawable( setImageDrawable(
AppCompatResources.getDrawable(context, R.drawable.media_state_pause), AppCompatResources.getDrawable(context, R.drawable.media_state_pause),
) )

View File

@ -9,7 +9,6 @@ import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.VectorConverter import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.VisibilityThreshold import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.detectDragGestures import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
@ -241,7 +240,7 @@ fun LazyGridItemScope.DragItemContainer(
else -> { else -> {
Modifier Modifier
.zIndex(0f) .zIndex(0f)
.animateItemPlacement(tween()) .animateItem()
} }
} }

View File

@ -7,7 +7,6 @@ package net.waterfox.android.tabstray.browser.compose
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.gestures.scrollBy
@ -235,7 +234,7 @@ fun LazyItemScope.DragItemContainer(
else -> { else -> {
Modifier Modifier
.zIndex(0f) .zIndex(0f)
.animateItemPlacement(tween()) .animateItem()
} }
} }
Box(modifier = modifier, propagateMinConstraints = true) { Box(modifier = modifier, propagateMinConstraints = true) {

View File

@ -114,7 +114,7 @@ fun InactiveTabsList(
faviconPainter = faviconPainter, faviconPainter = faviconPainter,
onClick = { onTabClick(tab) }, onClick = { onTabClick(tab) },
url = tabUrl, url = tabUrl,
iconPainter = painterResource(R.drawable.mozac_ic_cross_24), iconPainter = painterResource(mozilla.components.ui.icons.R.drawable.mozac_ic_cross_24),
iconDescription = stringResource(R.string.content_description_close_button), iconDescription = stringResource(R.string.content_description_close_button),
onIconClick = { onTabCloseClick(tab) }, onIconClick = { onTabCloseClick(tab) },
) )
@ -202,7 +202,7 @@ private fun InactiveTabsAutoClosePrompt(
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
) { ) {
Icon( Icon(
painter = painterResource(R.drawable.mozac_ic_cross_20), painter = painterResource(mozilla.components.ui.icons.R.drawable.mozac_ic_cross_20),
contentDescription = contentDescription =
stringResource(R.string.tab_tray_inactive_auto_close_button_content_description), stringResource(R.string.tab_tray_inactive_auto_close_button_content_description),
tint = WaterfoxTheme.colors.iconPrimary, tint = WaterfoxTheme.colors.iconPrimary,

View File

@ -23,7 +23,7 @@ import net.waterfox.android.R
class ClearableEditText @JvmOverloads constructor( class ClearableEditText @JvmOverloads constructor(
context: Context, context: Context,
attrs: AttributeSet? = null, attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.editTextStyle defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle
) : ) :
AppCompatEditText(context, attrs, defStyleAttr) { AppCompatEditText(context, attrs, defStyleAttr) {
@ -53,7 +53,7 @@ class ClearableEditText @JvmOverloads constructor(
// lengthAfter has inconsistent behaviour when there are spaces in the entered text, so we'll use text.length. // lengthAfter has inconsistent behaviour when there are spaces in the entered text, so we'll use text.length.
val textLength = text?.length ?: 0 val textLength = text?.length ?: 0
val drawable = if (shouldShowClearButton(textLength)) { val drawable = if (shouldShowClearButton(textLength)) {
AppCompatResources.getDrawable(context, R.drawable.mozac_ic_cross_circle_fill_24)?.apply { AppCompatResources.getDrawable(context, mozilla.components.ui.icons.R.drawable.mozac_ic_cross_circle_fill_24)?.apply {
colorFilter = createBlendModeColorFilterCompat(context.getColorFromAttr(R.attr.textPrimary), SRC_IN) colorFilter = createBlendModeColorFilterCompat(context.getColorFromAttr(R.attr.textPrimary), SRC_IN)
} }
} else { } else {

View File

@ -48,7 +48,7 @@ object ToolbarPopupWindow {
true true
) )
popupWindow.elevation = popupWindow.elevation =
context.resources.getDimension(R.dimen.mozac_browser_menu_elevation) context.resources.getDimension(mozilla.components.browser.menu.R.dimen.mozac_browser_menu_elevation)
// This is a workaround for SDK<23 to allow popup dismissal on outside or back button press // This is a workaround for SDK<23 to allow popup dismissal on outside or back button press
// See: https://github.com/mozilla-mobile/fenix/issues/10027 // See: https://github.com/mozilla-mobile/fenix/issues/10027

View File

@ -16,7 +16,7 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import coil.load import coil3.load
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.components.support.base.log.logger.Logger import mozilla.components.support.base.log.logger.Logger

View File

@ -0,0 +1,91 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="1419"
android:viewportHeight="1419">
<group android:scaleX="0.46"
android:scaleY="0.46"
android:translateX="383.13"
android:translateY="383.13">
<path
android:pathData="M614.7,191.6c5.8,-6.1 12.9,-11.4 19.7,-16.3 29,-21 63.1,-35.8 99.3,-36.6 29.9,-0.6 60.6,9.3 82.3,30.2 9.6,9.2 17.8,21 22.1,33.6 3.2,7.1 4.6,15.9 5,23.6 1,18.6 -4.5,36.8 -14.1,52.7 -19.8,32.8 -54.8,55.2 -89.2,70.5 -16,7.1 -32.5,13.2 -48.5,20.3 -20.3,8.9 -39.9,19.4 -58.6,31.3 -18,11.6 -36,25.4 -49.3,42.2 -5.8,7.3 -10.5,16.2 -16.8,23 -1.4,1.5 -4.5,4.5 -6.8,4.2 -2.8,-0.3 -5.5,-3.5 -7.1,-5.6 -4.4,-6.1 -7,-14.4 -9.1,-21.6 -10.7,-36 -11.4,-76.6 -5.1,-113.4 7.2,-43.9 26.6,-84.9 56,-118.3 6,-6.9 12.6,-14.6 20.1,-19.8"
android:fillColor="#68edfc"/>
<path
android:pathData="M420,382.1c2.8,-0 5.8,0.2 8.6,0.5 14.1,1.4 27.7,9 36.6,19.9 13.5,16.4 14,38 6.8,57.3 -3.5,9.5 -8.6,18.4 -12.6,27.7 -4.9,11.5 -8.9,23.4 -11.8,35.6 -3.4,14.2 -4.8,29.2 -5.3,43.7 -0.2,7.2 0.1,14.7 -0.7,21.9 -0.3,2.9 -0.4,6 -2.8,7.9 -6.8,0.3 -15.4,-5.2 -21.3,-8.3 -7.1,-4 -13.7,-8.8 -19.9,-14.1 -27.3,-23.8 -44.6,-59.6 -46.9,-95.7 -1.7,-26.3 5.3,-53.8 23,-73.9 12.3,-13.9 27.7,-21.2 46.2,-22.5">
<aapt:attr name="android:fillColor">
<gradient
android:startX="427.1"
android:startY="596.2"
android:endX="406.3"
android:endY="384.1"
android:type="linear">
<item android:offset="0" android:color="#FF00DFFE"/>
<item android:offset="1" android:color="#FF62FEFA"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M988.3,98.9c36.8,-6.2 71.7,18.7 77.9,55.5 6.1,36.9 -18.8,71.7 -55.7,77.8 -36.8,6.1 -71.5,-18.8 -77.6,-55.6 -6.1,-36.8 18.7,-71.5 55.4,-77.7"
android:fillColor="#68edfc"/>
<path
android:pathData="M713.8,445.8c14.1,-11.1 31.8,-20.1 47.8,-28.1 60.9,-30.3 130.8,-50.7 199.4,-42.6 37.9,4.5 76.2,19.3 100.4,50.1 7.6,9.6 15.7,21.9 14.2,34.8 -0.9,8 -5.4,14.9 -10.6,20.9 -10.1,11.6 -22.4,21.5 -34.1,31.4 -15.5,13 -30.7,26.2 -45.7,39.8 -11.5,10.6 -22.7,21.6 -33.7,32.8 -5.5,5.6 -10.9,12.5 -16.9,17.4 -14.2,15.8 -28.4,31.7 -41.6,48.3 -74.4,88.3 -127.7,191.6 -183.5,292l-119.4,213.3 -32,56.9c-11.3,20 -21.6,40.7 -37.1,57.8 -19.2,20.9 -43.8,35.9 -71.2,43.4 -4.4,1.2 -8.9,2.3 -13.4,3.3 -1.5,0.1 -2.7,0.3 -4.2,0.7 -7.4,2.4 -35.6,2.9 -42.7,0.6 -2.1,-0.7 -3.9,-1.1 -6.1,-1.3l-0.8,-0.1c-6.8,-1.6 -13.4,-3.1 -20.1,-5.2 -28.2,-9 -53.1,-26.2 -71.6,-49.4 -18.5,-23.3 -29,-53.1 -41,-80.1l-44.5,-100.6c-7.9,-18 -15.3,-36.6 -24.2,-54.1 -2.9,-10 -9.1,-19.6 -12.6,-29.6 2.9,3 5.3,6.8 8,10.1 6.8,8.3 14.3,15.2 23.4,20.9 21.9,13.6 48.3,18 73.3,12 17.6,-4.2 33.7,-13.3 46.3,-26.3 15.7,-16.2 28.5,-43.2 40,-63.2l40.8,-70.8c8.9,-15.5 17.4,-31.2 26.7,-46.4l79.3,-137.7c21.5,-37.1 42,-75.7 66,-111.2 25.6,-38 56.2,-72.3 91,-102.2 15.6,-13.4 32.6,-27.4 50.4,-37.7">
<aapt:attr name="android:fillColor">
<gradient
android:startX="729.8"
android:startY="1172"
android:endX="432.8"
android:endY="592"
android:type="linear">
<item android:offset="0" android:color="#FF10B8F7"/>
<item android:offset="1" android:color="#FF2BFFFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M713.8,445.8c14.1,-11.1 31.8,-20.1 47.8,-28.1 60.9,-30.3 130.8,-50.7 199.4,-42.6 37.9,4.5 76.2,19.3 100.4,50.1 7.6,9.6 15.7,21.9 14.2,34.8 -0.9,8 -5.4,14.9 -10.6,20.9 -10.1,11.6 -22.4,21.5 -34.1,31.4 -15.5,13 -30.7,26.2 -45.7,39.8 -11.5,10.6 -22.7,21.6 -33.7,32.8 -5.5,5.6 -10.9,12.5 -16.9,17.4 -20.9,9.7 -40.3,20.1 -63.2,25.1 -15.9,3.4 -34.8,4.5 -48.9,-5 -10.4,-7 -14.4,-17.1 -16.9,-28.9 -21.5,20.2 -50.9,43.4 -80.6,47.8 -12.5,1.9 -25,0 -35.2,-7.8 -14.2,-10.8 -20.5,-30.1 -22.7,-47.1 -4.9,-37.8 5.8,-78.1 25.2,-110.5 6.3,-10.6 13.8,-20.3 21.4,-30"
android:fillColor="#bafafc"/>
<path
android:pathData="M709.5,942.6c55.8,-100.3 109.2,-203.6 183.5,-292 12.3,20.3 23.4,41.5 35,62.3l65.7,118.3 61,109.7L1075.5,978.2c7,12.6 13.4,25.5 23.1,36.2 10.8,11.9 26.6,21 42,25.6 24.7,7.4 51.3,4.5 73.9,-8 15,-8.3 25.1,-19.4 35.1,-33.1l0.6,0.3c-3.8,9.4 -9.8,19.2 -12.5,28.8 -9.1,17.5 -16.4,36.3 -24.4,54.4l-45.9,103.6c-8.3,18.8 -15.8,39.3 -26.4,57 -9.4,15.7 -21.8,30.6 -35.9,42.2 -20.9,18.3 -48.8,29.3 -76.2,33.4l-3.5,0.5c-15.4,1.2 -29.6,0.2 -44.9,-1.8 -5.2,-1.3 -10.3,-2.7 -15.5,-4.1 -26.8,-7.9 -50.9,-23.2 -69.4,-44.1 -15.1,-17.1 -25.2,-37.7 -36.2,-57.5l-33.4,-60.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="782.1"
android:startY="1081.2"
android:endX="1178.1"
android:endY="878.1"
android:type="linear">
<item android:offset="0" android:color="#FF08A9F8"/>
<item android:offset="1" android:color="#FF0CDBFE"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M3.2,560.7c7.2,-32.5 21.8,-61.3 46.6,-84 24.5,-22.3 55.5,-36 88.5,-39.1 9.7,-0.8 19.4,-0.3 29.1,0.1 42.5,6 79,24.6 105.3,59.3 13.9,18.3 22.1,40 31.4,60.9l27.3,61.6 95.6,215.3c-9.3,15.2 -17.9,30.9 -26.7,46.4l-40.8,70.8c-11.4,19.9 -24.2,46.9 -40,63.2 -12.7,12.9 -28.7,22.1 -46.3,26.3 -25.1,6 -51.5,1.7 -73.3,-12 -9.1,-5.7 -16.6,-12.6 -23.4,-20.9 -2.7,-3.3 -5.1,-7 -8,-10.1 -3.1,-6.4 -5.7,-13.3 -8.6,-19.9l-20.3,-45.8L76.5,790.5l-43.9,-98.7C24.5,673.4 15.1,654.9 8.6,635.8c-5.3,-15.7 -7.6,-31.8 -7.9,-48.3 -0,-9 1.3,-18 2.5,-26.9">
<aapt:attr name="android:fillColor">
<gradient
android:startX="369.8"
android:startY="984.8"
android:endX="49.9"
android:endY="474.8"
android:type="linear">
<item android:offset="0" android:color="#FF008AED"/>
<item android:offset="1" android:color="#FF05D1EA"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m993.7,831.2 l96.4,-217.3 26.2,-58.9c8.7,-19.5 16.6,-39.5 29.3,-56.8 17.1,-23.1 40.5,-40.9 67.3,-51.1 37.7,-14.5 79.7,-13.2 116.5,3.5 36.6,16.5 65.1,47 79.1,84.7 10.1,26.8 12.3,55.9 6.4,83.9 -5,23.3 -16.3,45.1 -25.9,66.8l-37.4,84.3 -68.3,154.1c-11,24.8 -21.3,50.1 -32.9,74.5 -0.1,0.2 -0.2,0.3 -0.3,0.5l-0.6,-0.3c-10,13.7 -20.1,24.8 -35.1,33.1 -22.6,12.5 -49.2,15.4 -73.9,8 -15.4,-4.6 -31.2,-13.7 -42,-25.6 -9.8,-10.8 -16.1,-23.6 -23.1,-36.2l-20.8,-37.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="1082.2"
android:startY="1014.3"
android:endX="1323.2"
android:endY="449"
android:type="linear">
<item android:offset="0" android:color="#FF2F76EB"/>
<item android:offset="1" android:color="#FF7E94F3"/>
</gradient>
</aapt:attr>
</path>
</group>
</vector>

View File

@ -1,663 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="208"
android:viewportHeight="208">
<path
android:pathData="M136,129.9c-1.1,-0.4 -2.2,-1 -3,-2 -1.2,-1.1 -8,-13.3 -8,-14.1 0,-0.5 0.2,-0.7 0.5,-0.6 0.2,0 1,-1.4 2.4,-4.7 2.4,-5.4 2.4,-5.4 4.4,-4a28.7,28.7 0,0 0,15.2 6.7c2,0.2 2.6,0.5 2.6,1.2 0,0.3 1,-1 1,-0.9 0.2,0 -2,5.2 -4,9.5 -3.3,7.5 -3.6,8 -4.5,8.5a15,15 0,0 1,-6.5 0.4Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="130.7"
android:startY="124.8"
android:endX="152.9"
android:endY="86.6"
android:type="linear">
<item android:offset="0" android:color="#FF1964E7"/>
<item android:offset="1" android:color="#FF6884F2"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M65.8,129.7c-1.3,-0.5 -1.3,-0.6 -3,-4.5l-2.9,-6.5 -1.7,-4.1 1.9,1.6a28,28 0,0 0,7.5 -1.9l3.2,-1c1,-0.3 1.4,-0.5 1.4,-0.9 0,-0.2 0.3,-0.5 0.7,-0.6 0.3,0 1.8,-0.7 3.2,-1.3 1.4,-0.7 2.8,-1.2 3,-1.2 0.2,0 0.4,0 0.4,-0.2s0.2,-0.3 0.4,-0.3 0.8,1 1.3,2.3c1,2.4 1.3,2.8 1.7,2.2 0.2,-0.3 0.3,-0.2 0.3,0.4 0,1 -6.6,12.7 -8,14.1 -1.5,1.7 -2.8,2.2 -5.7,2.3a9,9 0,0 1,-3.7 -0.4Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M136.3,129.9c0,-0.2 -0.3,-0.3 -0.8,-0.3 -0.7,0 -0.8,-0.1 -0.8,-0.7s-0.2,-0.7 -1,-0.7c-1,0 -1,0 -1,-1v-1l1,1a7.3,7.3 0,0 0,3.7 2c1.3,0.2 1.2,1 0,1 -0.6,0 -1,-0.2 -1,-0.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M138,129.4c0,-0.2 1.8,-0.1 2.5,-0.4 0.6,-0.2 1.6,-0.6 2.2,-1 1.2,-0.8 1.4,-0.7 1.1,0.3 -0.1,0.5 -0.3,0.7 -0.8,0.7s-0.8,0.2 -0.8,0.4c0,0.4 -0.8,0.8 -2,0.8 -0.5,0 -2.2,-0.5 -2.2,-0.8ZM105.2,123.5c-0.6,-1.2 -1.1,-1.8 -1.4,-1.7 -0.3,0.1 -0.4,0 -0.4,-0.6 0,-1.3 6.3,-12 10.3,-17.7 2.3,-3.2 2.7,-3.6 3.5,-3.7 0.7,0 0.9,0 1,0.7v1.1a47.8,47.8 0,0 0,-4.9 8.2,200.2 200.2,0 0,0 -6,14.5l1.2,4.3c0,1 -2.3,-3.3 -3.3,-5ZM130.7,124.1c0,-1.2 0.4,-1.3 1,-0.1 0.6,1 0.5,1 -0.3,1 -0.6,0 -0.7,0 -0.7,-0.9Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M129.3,121.6c0,-1.2 0.4,-1.3 1,-0.1 0.6,1 1.5,2.3 0.6,2.3 -0.6,0 -1.6,-1.3 -1.6,-2.2ZM128,119c0,-0.7 -0.1,-1 -0.5,-1 -0.6,0 -0.9,-0.5 -0.9,-1.7 0,-0.6 -0.1,-0.8 -0.6,-0.8 -0.3,0 -0.6,-0.2 -0.7,-0.6 -0.2,-1 -0.3,-2 0.1,-1.8 0.4,0.1 4,6.5 4,6.8l-0.7,0.1c-0.6,0 -0.7,0 -0.7,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M135.2,129.6c0,-0.1 -0.2,-0.3 -0.5,-0.3 -0.4,0 -0.6,-0.2 -0.6,-0.4s-0.2,-0.4 -0.5,-0.4c-0.7,0 -1.2,-0.8 -1.2,-1.7 0,-1 0.2,-1 0.8,-0.2a9,9 0,0 0,3.2 2.3c1.2,0.3 1,1 -0.2,1 -0.5,0 -1,-0.1 -1,-0.3ZM106.6,125.4c-0.3,-0.8 -0.5,-1.7 -0.2,-2a266,266 0,0 1,8 -18.5,53.2 53.2,0 0,0 -2,2.6 26.2,26.2 0,0 1,-2.3 3.3l-0.2,-1c0,-0.9 0,-1 0.7,-1 0.5,0 0.7,-0.2 1,-1l0.3,-1.6c0,-0.3 0.1,-0.5 0.3,-0.5 0.4,0 1,-0.9 1,-1.5 0,-0.3 0.2,-0.5 0.4,-0.5l0.2,-0.4c0,-0.2 0.2,-0.4 0.5,-0.5 0.2,-0.1 0.4,-0.4 0.4,-0.6 0,-0.2 0.2,-0.5 0.4,-0.6 0.2,0 0.4,-0.2 0.4,-0.4 0,-0.3 1.6,-2 2,-2 0.2,0 1.6,2.8 1.9,3.4 0,0.2 -0.6,0 -0.7,0l-0.7,1 -3,5.9a69.3,69.3 0,0 0,-2.7 5.9c-0.3,1 -2.2,5.8 -3.2,8s-1.5,2.8 -2,2.8c-0.3,0 -0.3,-0.4 -0.5,-0.8ZM129.6,122.1c0,-1.2 0.3,-1.2 1,-0.1 0.5,1 0.5,1.1 -0.3,1.1 -0.6,0 -0.7,0 -0.7,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M128.2,119.6c0,-1.2 0.3,-1.3 1,-0.2 1.1,2.1 0.8,1.7 -0.3,1.2 -0.6,-0.3 -0.7,-0.1 -0.7,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M59.6,117.3c-0.3,-0.4 -1.2,-2 -1.9,-3.5l-1.6,-3.9 1.8,1c3.4,-0.3 17.7,-7.2 17.7,-8.4 0,-0.4 1,-1.6 1.2,-1.3l2,4.4c1.8,4.1 2,5 1.3,4.7 -1,0.1 -2,0.4 -2.8,0.9l-3.4,1.4 -1,0.4 1.3,-0.1c1.6,-0.2 1,0.2 -2,1l-3.8,1.3 -7.4,2.1c-0.3,0 -0.5,0.2 -0.6,0.4 0,0.2 -0.4,0 -0.8,-0.4Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M57.6,112.4c0,-0.3 -0.2,-0.5 -0.4,-0.5 -0.3,0 -1,-1.4 -2.2,-4.5 -0.1,-0.1 1.1,0 2.5,-0.6 4.6,-1.6 8.7,-3.9 12.6,-6.8 2.4,-2 3,-2.4 3,-2.9 0,-0.2 0.2,-0.4 0.4,-0.4s0.4,-0.1 0.4,-0.3c0,-0.1 0.2,-0.3 0.4,-0.3a28,28 0,0 1,3 7c0.3,0.7 0.2,0.7 -0.1,0.3 -0.5,-0.6 -0.8,-0.7 -0.8,-0.1 0,1 -10.9,6.5 -16.8,8.4l-1.8,0.8c-0.1,0.2 -0.2,0.2 -0.2,-0.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m72,129 l0.8,-0.6 1.8,-1.5 1,-1v0.9c0,1 -0.5,1.7 -1.2,1.7 -0.3,0 -0.5,0.2 -0.5,0.4 0,0.3 -0.3,0.4 -1,0.4l-1,-0.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m54.3,106.1 l-1.1,-2.5 0.7,-0.2c2.5,-0.5 8,-3.4 11,-5.8a32.7,32.7 0,0 0,6.8 -7.1c0.2,0 0.3,0.1 0.7,0.7l2.4,5.7 0.7,1.6c0.2,0.4 -0.3,-0.1 -0.5,-0.1 -0.1,0 -0.3,-0.2 -0.3,-0.4 0,-0.3 -0.1,-0.5 -0.4,-0.5 -0.2,0 -0.4,0.2 -0.4,0.5a48,48 0,0 1,-14.7 9.4l-2.3,0.8 -1.2,0.4c-0.1,0.1 -0.8,-1 -1.4,-2.5Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M124.1,149.8c-3.2,-0.8 -5.9,-3 -7.5,-6 -1.5,-2.6 -1.6,-2.7 -0.6,-2.7 0.5,0 1.8,-0.4 2.8,-0.9 2,-1 4.4,-1.3 6.7,-0.8 2.2,1.4 4.2,3.1 5.8,5.2l1.2,1.6 1.6,-0.2 4.4,-6a22,22 0,0 1,-3.8 6.8,12 12,0 0,1 -10.6,3ZM136.1,129.6c0,-0.6 0.2,-0.7 1.3,-0.4 1,0.3 0.8,1 -0.4,1 -0.7,0 -1,-0.2 -1,-0.6Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M107.2,127.1c-0.8,-1.6 -0.8,-1.6 -0.3,-2.1 0.7,-0.8 4,-8.3 4.5,-10.4a110.8,110.8 0,0 1,6.5 -13.1c-0.2,0 -0.3,-0.2 -0.3,-0.5 0,-0.8 0.7,-0.3 1.5,1.1 0.9,1.4 1,2.5 0.4,2.5 -0.4,0 -6.2,11.8 -6.4,13 -0.4,2.4 -1.3,4.7 -2.5,6.8 -1,2 5.6,18.7 5.7,18.9ZM133.2,127.9v-0.9l0.9,0.6c1.2,0.9 1.3,1.2 0.2,1.2 -1,0 -1,-0.1 -1,-1ZM142.6,128.1s0.7,-0.3 1.2,-0.9l1,-1 -0.5,1.1c-0.3,0.8 -0.6,1.2 -1,1.2 -0.3,0 -0.7,-0.3 -0.7,-0.4ZM131,124.7c0,-1.3 0.3,-1.3 1,0l0.7,1h-0.9c-0.7,0 -0.8,-0.1 -0.8,-1ZM127,117.7c0,-1.3 0.3,-1.3 1.1,0l0.7,1h-0.9c-0.8,0 -0.8,-0.2 -0.8,-1ZM125.7,115.1c0,-1.2 0.2,-1.2 1,0l0.8,1.3 -1,-0.3c-0.8,0 -0.8,0 -0.8,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="m77.4,103.8 l-0.3,-0.8 0.6,0.7c0.5,1 0.4,1.1 -0.3,0.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M71.9,145.1c-0.2,0 -0.2,-0.5 -0.2,-1 0,-0.6 0,-0.7 1,-0.7 0.9,0 1,0 1,1 0,0.9 -0.2,1 -0.9,1 -0.4,0 -0.9,-0.1 -1,-0.3Z"
android:fillColor="#00b0e7"/>
<path
android:pathData="M53.8,104.6c0,-0.1 0,-0.2 -0.2,-0.2 -0.2,-0.1 -2.3,-4.6 -2.1,-4.8a115.4,115.4 0,0 1,6.4 -2.7l2,-1.5c3.4,-2.6 7.2,-6.6 7.7,-8.3 0.3,-1.6 0.6,-1.6 2,-0.3 1.3,1.4 2.3,3 2.8,4.9 0.1,0.6 0,0.7 -0.3,0.6a31.7,31.7 0,0 1,-14.4 10.9c-1.5,0.6 -2.4,1.1 -2.4,1.4 0,0.3 0,0.3 -0.2,0s-0.4,-0.3 -0.5,-0.2c-0.3,0.4 -1,0.6 -0.8,0.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M78.6,149.8c-1.4,-0.3 -3.8,-1.6 -3.8,-2 0,0 0.4,-0.2 1,-0.2 0.5,0 1,0 1,0.2 0,0.1 1.2,0.2 2.6,0.2 2,-0.1 3,0 3.6,0.3l1.2,0.4c0.6,0 0.5,0.8 0,1 -1,0.3 -4.5,0.4 -5.6,0.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M133.3,147.5c0,-0.4 -0.2,-0.4 -0.7,-0.3 -0.5,0.1 -0.9,-0.2 -2.1,-1.7 -1.6,-2 -3.5,-3.8 -5.7,-5.2 -0.5,-0.2 -1.5,-0.3 -2.1,-0.2 -1.4,0.1 -4.5,1.5 -5.3,2.3 -0.6,0.6 -1.2,0.8 -1.2,0.3 0,-0.2 0,-0.3 -0.2,-0.4 -0.2,0 -1,-1.4 -3.6,-6l-1.1,-2h0.9c0.5,0 0.8,0.2 0.8,0.5 0,0.4 0.5,0.6 0.6,0.2a25,25 0,0 1,2.5 -2.1c2.3,-2 2.4,-2 2.3,-3 0,-1.1 0,-1.2 0.8,-1.2 1,0 1,0.2 2.5,2.5a27,27 0,0 0,3.4 4.2c2.4,2.2 3.9,2.7 6.4,2.5 1.2,-0.2 1.8,-0.1 1.8,0.1s0,0.3 0.3,0.3c0.2,0 1,0.5 1.6,1.1a5,5 0,0 0,2 1.2l1,0.1c-0.4,0.9 -2.2,4.6 -3.5,6 -1.6,1.7 -1.4,1.4 -1.4,0.8ZM108.8,129.8c-1,-1.7 -1.2,-2.7 -0.7,-3.2 1.7,-2.9 3,-6 4,-9.2l1.6,-4.1c0.6,-1.4 1.1,-2.6 1,-2.7l0.2,-0.1a46.7,46.7 0,0 1,4 -7.7c0.5,-0.6 0.5,0 1.4,1.4 0.8,1.3 0.8,1.3 0.3,2.2 -1.6,2.7 -3,5.5 -4.5,8.3 -1.2,2.4 -1.5,3.2 -1.4,4.3 0,1.5 -0.6,3.5 -2,6.7 -0.6,1.2 -1.1,2.5 -1.2,3 -0.1,0.4 -0.3,0.9 -0.6,1.2 -0.3,0.2 -0.4,0.6 -0.4,1 0,1.1 -0.7,0.7 -1.7,-1ZM139.8,129.8c0,-0.3 0.4,-0.6 0.7,-0.7a2,2 0,0 0,1 -0.3c0.2,-0.2 0.5,-0.2 0.6,-0.1 0,0 0.2,0 0.2,-0.2s0,-0.3 0.3,-0.3c0.2,0 0.4,-0.3 0.7,-0.5 0.5,-0.4 0.3,-0.4 0.4,0.4 0,0.7 -0.2,1 -0.5,1.1 -0.3,0.1 -0.6,0.3 -0.7,0.5l-1.5,0.4c-1.2,0.1 -1.3,0 -1.3,-0.4ZM132.1,127.3 L131.7,126.6c-0.4,-0.4 -0.6,-2.3 -0.2,-2.3 0.2,0 0.7,0.7 1.9,2.6l0.4,0.7h-0.8c-0.5,0 -0.9,-0.1 -0.9,-0.3ZM129.9,122.7c0,-1.2 0.2,-1.2 1,0l0.7,1.2 -0.9,-0.2c-0.8,0 -0.8,-0.1 -0.8,-1ZM128.5,120.2c0,-0.8 -0.1,-1 -0.6,-1 -0.4,0 -0.6,-0.2 -0.6,-1l0.2,-1c0.3,0 1.2,1.3 1.3,1.6l0.7,1.3 0.8,1.3 -1,-0.2c-0.8,0 -0.8,-0.1 -0.8,-1ZM125.9,115.7c0,-1.2 0.2,-1.2 1,-0.4 0.6,1 0.6,1.4 -0.3,1.4 -0.6,0 -0.7,-0.2 -0.7,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M131.7,126.6a5,5 0,0 1,-0.1 -1.3c0,-0.6 -0.2,-0.8 -0.6,-0.8 -0.4,0 -0.6,-0.2 -0.6,-1 0,-0.9 0,-1 0.5,-0.6l0.9,1.4c0.2,0.6 0.1,1.1 0.3,1.1 0.1,0 0.5,0.1 0.4,0.3l0.1,0.2c0.2,0 0.4,0.3 0.5,0.6 0,0.5 0,0.6 -0.6,0.6 -0.3,0 -0.7,-0.2 -0.8,-0.5ZM129,121c0,-1 0,-1 0.6,-0.6l0.6,1c0.2,0.5 0,0.6 -0.5,0.6 -0.6,0 -0.7,-0.1 -0.7,-1ZM127.6,118.4c0,-1 0,-1 0.5,-0.4 0.3,0.2 0.6,0.7 0.7,1 0.2,0.4 0,0.5 -0.5,0.5 -0.6,0 -0.7,-0.1 -0.7,-1ZM126.2,115.9c0,-1 0,-1 0.5,-0.5l0.7,1c0.2,0.4 0,0.5 -0.5,0.5 -0.6,0 -0.7,0 -0.7,-1ZM124.8,113.6c0,-0.8 -0.4,-2 0.5,-0.6l0.7,1c0,0.3 0,0.4 -0.5,0.4 -0.6,0 -0.7,-0.1 -0.7,-0.8Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M149.2,114c-0.1,-0.2 -0.1,-0.6 0,-0.8 0.2,-0.7 -0.5,-1 -2.6,-1.2 -5,-0.4 -9.8,-2.5 -15.2,-6.6l-1,-0.9 -1,1.5 -0.9,1.2 3.2,-7.2c2.5,-5.6 3.2,-7 3.6,-7 0.3,0 1.3,0.8 2.2,1.9 2.3,2.4 5,4.2 8.2,5.3 2,0.7 4.2,1 6.3,0.8h4l-0.5,1.1c-1.7,4 -3.5,8 -5.5,12 -0.5,0.4 -0.6,0.4 -0.8,-0.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="130.7"
android:startY="124.8"
android:endX="152.9"
android:endY="86.6"
android:type="linear">
<item android:offset="0" android:color="#FF1964E7"/>
<item android:offset="1" android:color="#FF6884F2"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M52.4,100.7c0,-0.2 -0.3,-0.3 -0.4,-0.2 -0.3,0.1 -1,-1.7 -1.4,-3.5 -0.5,-2 -0.4,-2.3 0.4,-2.3 1,0 3.5,-1.1 3.5,-1.5 0,-0.2 0.6,-0.8 1.3,-1.3 1.8,-1.2 3.4,-2.6 4.7,-4.3 0.8,-0.9 1,-1.6 1.2,-2.7l0.2,-1.4c0.6,-0.1 2.8,0.3 2.6,0.4 -1,-0.4 1.3,0.4 2.8,1.2l1.4,1c0.6,0.5 0.4,0.8 0,1.2 -0.3,0.2 -0.4,0.6 -0.3,0.7 0.3,0.4 -2.2,3.4 -4.3,5.3 -3.4,3.2 -4.3,4 -4,3.6 0.1,-0.4 -0.7,0.2 -1.2,0.8l-1,0.5c-4.2,1.6 -5,2 -5.1,2.4 -0.1,0.4 -0.2,0.4 -0.4,0Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M83.3,149.6c-0.3,0 -0.6,-0.2 -0.8,-0.3 -0.5,-0.4 -3.8,-0.6 -4.8,-0.3 -1.5,0.4 -4.4,-1.6 -6,-4.2l-0.7,-1.5 1,-0.4 2.5,-1.8 1.6,-1.1c0.2,0 0.3,-0.2 0.3,-0.4 0,-0.3 0.3,-0.4 1.2,-0.4 3,0 6.3,-2.8 9.2,-7.4 1.5,-2.3 1.7,-2.5 2.5,-2.5 0.5,0 1,0.2 1,0.4 0.2,0.5 0,7.3 -0.4,10.5 -0.4,3 -0.2,3.7 1,3.7 0.4,0 0.4,0.2 -0.4,1.2 -1.8,2.7 -5.3,5 -7.2,4.5Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M137.2,141.8c0,-0.3 -0.1,-0.4 -0.5,-0.1 -0.4,0.2 -0.8,0 -2,-1.2a7.1,7.1 0,0 0,-2 -1.3l-0.3,-0.2c0,-0.2 -0.8,-0.2 -1.7,-0.2 -2,0.2 -4,-0.5 -5.5,-1.8l-1,-1h1a17.8,17.8 0,0 0,9.5 -0.7c1.4,-0.4 2.8,-0.7 4.2,-0.8l2.4,-0.7 -0.5,1.4c-2.5,5.7 -3.6,7.8 -3.6,6.6ZM112.7,136.6c-0.2,-0.1 -0.3,-0.3 -0.2,-0.3 0.2,0 0,-0.2 -0.2,-0.4 -0.3,-0.2 -0.4,-0.4 -0.3,-0.4 0.2,0 0.2,0 0,-0.2 -1.1,-1.5 -2,-3.1 -2.5,-4.9 -0.1,-0.7 0,-1 0.4,-1.3 0.3,-0.2 0.6,-0.7 0.7,-1.2l1.2,-3c1.5,-3.3 2,-5 1.8,-6.4 0,-1 0.1,-1.6 1.2,-3.8a86,86 0,0 1,5.4 -10.5c0.5,0.7 1,1.4 1.3,2.2 0.8,1.4 1.4,2 1,2.5a97.7,97.7 0,0 0,-5 7.5c-0.7,1.4 -1.2,2.9 -1.3,4.5 0,0.4 1,2.2 2,4a224.4,224.4 0,0 1,3.5 6.2c0.3,0.2 0.7,0.8 0.9,1.3l0.7,1c0.2,0 0.4,0.6 0.4,1.2 0,1 0,1 -0.6,0.4 -0.3,-0.2 -1.2,-1.5 -2,-2.7 -1.4,-2.1 -1.5,-2.2 -1.6,-1.4 -0.1,0.7 -0.7,1.3 -2.6,2.8l-3,2.6c-0.7,0.7 -0.6,0.7 -1.2,0.3ZM136.7,130.2c-0.8,0 -1,-0.2 -1,-0.7 0,-0.7 0.2,-0.7 0.8,-0.5 0.4,0.2 1.5,0.3 2.4,0.3 0.9,0 2,-0.1 2.3,-0.3 0.7,-0.2 0.8,-0.2 0.8,0.4 0,0.6 -0.2,0.7 -1.3,0.9h-4ZM133.5,128.2c0,-0.8 0,-0.9 -0.8,-0.9s-0.9,0 -0.9,-1c0,-1.2 0.3,-1.2 1.1,0 0.4,0.7 1,1.2 1.6,1.7 1.3,0.8 1.3,1 0,1 -0.9,0 -1,0 -1,-0.8Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M75,126.6c0,-0.3 1,-1.8 1.2,-1.8l0.2,1c0,0.9 0,1 -0.7,1 -0.4,0 -0.7,-0.1 -0.7,-0.2Z"
android:fillColor="#00b2f7"/>
<path
android:pathData="M130.3,124.4a5,5 0,0 1,-0.1 -1.3c0,-0.6 -0.2,-0.8 -0.6,-0.8 -0.6,0 -0.8,-0.6 -0.8,-1.7 0,-0.7 -0.2,-0.8 -0.6,-0.8 -0.5,0 -0.6,-0.2 -0.6,-1 0,-0.6 0.1,-1 0.2,-1 0.3,0 4,6.5 4,6.8 0,0.4 -1.3,0.2 -1.5,-0.2ZM126.3,116.2c0,-1.2 0.2,-1.2 0.8,-0.1 0.7,1 0.7,1.1 -0.2,1.1 -0.6,0 -0.7,0 -0.7,-1ZM124.8,113.6v-1l0.7,0.8c1,1 0.9,1.3 0,1.3 -0.6,0 -0.7,-0.1 -0.7,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M72.2,92.4c-0.7,-0.6 -0.7,-0.8 -0.1,-0.8 0.1,0 0.4,0.3 0.5,0.6 0.2,0.8 0.2,0.9 -0.4,0.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M75,126.4c0.9,-1.3 1.2,-1.3 1.2,0 0,0.9 -0.1,1 -0.9,1h-0.8ZM81,116.5c0,-0.4 0.8,-1.8 1,-1.8 0.2,0 0.3,0.4 0.3,1 0,0.8 0,1 -0.7,1 -0.4,0 -0.7,-0.1 -0.7,-0.2Z"
android:fillColor="#00c8e6"/>
<path
android:pathData="M50.3,95.2a12,12 0,0 1,6.2 -10.4c1.9,-0.9 6.2,-1.7 6.4,-1.1 0,0.2 0.2,0.6 0.4,0.5 0.7,-0.3 0.5,0.1 -0.2,1 -0.4,0.5 -0.6,1 -0.5,1.3 0.2,0.7 -3.4,4.6 -5.7,6.1 -0.8,0.6 -1.4,1.1 -1.4,1.3 0,0.5 -4,2.3 -4.3,2 0,-0.3 -0.1,0.2 -0.4,0.5 -0.3,0.2 -0.5,-0.4 -0.5,-1.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="55.1"
android:startY="86.8"
android:endX="77.3"
android:endY="125.1"
android:type="linear">
<item android:offset="0" android:color="#FF00CCE6"/>
<item android:offset="1" android:color="#FF0082E7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M89,144.3c-0.2,-0.4 -0.2,-1.3 0,-3l0.2,-6.1c0,-2 0.1,-3.7 0.3,-3.8 0.3,-0.3 0.2,-0.7 -0.2,-0.7 -0.2,0 -1.1,1.1 -2,2.5 -2.7,4.2 -6,6.8 -8.8,6.8 -1,0 -1.2,0 -1,0.4 0,0.3 0,0.4 -0.4,0.4 -0.2,0 -1,0.5 -1.8,1.1 -0.6,0.6 -1.4,1.1 -2.2,1.6 -0.4,0.3 -0.8,0.7 -0.7,0.9 0.1,0.3 0,0.3 -0.5,0 -0.6,-0.2 -1.1,-1.1 -2.2,-3.4l-3.5,-8.5c5,0.8 11.7,0.3 11.7,0.3 2.2,-0.3 0.5,-1.8 2.6,-1.1 2.3,0.8 -0.7,2.8 1.4,1.4 0.6,-0.4 1.4,-0.3 1.7,-0.4 0.3,-0.2 0.7,0.6 0.7,0.4 0,-0.2 1,0.7 1.3,0.5 0.8,-0.6 1.1,-1.8 5.6,-9.5 2.3,-4 4.6,-7.9 7,-11.7 2.5,-4 2.6,-4.2 3.5,-4.2 0.8,0 0.9,0 0.9,1 0,0.4 -0.3,1.4 -0.7,2 -0.4,0.6 -0.7,1.4 -0.7,1.7 0,0.3 -0.3,1.3 -0.7,2.1a6,6 0,0 0,-0.7 2,83.7 83.7,0 0,0 -4.3,12.7c-0.7,2.2 -1.1,4.4 -1.2,6.6v2.4l-1.8,3.2c-1.5,2.5 -1.9,3 -2.4,3 -0.4,0 -0.8,-0.2 -1,-0.6Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M125,136.8a29.8,29.8 0,0 1,-6.2 -8.4,29 29,0 0,1 -3.7,-7.6 17,17 0,0 1,1.6 -5.3c1.1,-2.3 4.3,-7.8 4.6,-8.2 0.5,-0.4 0.6,-0.3 1.8,1.8 0.6,1.1 1.2,2 1,2a26,26 0,0 0,-4.5 7.8c-0.5,1.2 -1,2.5 -1.2,3.8 -0.3,1.5 -0.3,1.8 0.4,3.2l1.2,2 0.3,0.7c0,0.4 1.6,1 2.5,1 0.2,0 0.3,0.1 0.3,0.2 0,0.2 1.1,0 2.5,-0.2a42,42 0,0 1,5.2 -0.7c2.3,-0.2 2.8,-0.3 3,-0.7 0,-0.4 0.1,-0.1 1.6,0.4 2.6,0.8 6,1 8.4,-1 0.8,-0.6 0.8,-0.7 -1.6,4.3 -1.5,3.4 -2.2,4.6 -2.2,3.6 0,-0.4 -2.2,0 -4.6,0.7 -2.1,0.9 -4.3,1.2 -6.6,1.1 -0.7,0 -1.2,0 -1,0.1 0,0.2 -0.3,0.3 -0.7,0.3 -0.6,0 -1.3,-0.3 -2,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M131.2,126a4,4 0,0 1,-0.5 -1.8c0,-0.6 -0.1,-0.8 -0.5,-0.8 -0.6,0 -0.9,-0.5 -0.9,-1.7 0,-0.6 -0.1,-0.8 -0.5,-0.8 -0.6,0 -0.9,-0.6 -0.9,-1.7 0,-0.7 -0.1,-0.9 -0.5,-0.9 -0.6,0 -0.9,-0.5 -0.9,-1.7 0,-0.6 -0.1,-0.8 -0.5,-0.8 -0.3,0 -0.7,-0.2 -0.7,-0.4 -0.3,-0.7 -0.2,-2.1 0,-2.1s2,3 4,6.9c3.8,6.7 3.9,6.9 3.1,6.9 -0.6,0 -0.8,-0.3 -1.2,-1Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M81.3,115.9c1,-2 1.3,-2.3 1.3,-0.8 0,0.9 0,1 -0.7,1 -0.4,0 -0.7,0 -0.6,-0.2Z"
android:fillColor="#00bff9"/>
<path
android:pathData="m119.8,129.8 l-2.3,-4c-1,-1.7 -1,-1.8 -0.5,-2.3 0.3,-0.4 0.5,-0.7 0.4,-0.9a15,15 0,0 1,1.6 -5l0.8,-1.8c0,-0.5 2.9,-6.4 3.2,-6.4 0.2,0 0.6,0.6 1,1.3 8.1,14.9 9.5,17 11.5,18 0.5,0.4 0.9,0.6 0.7,0.6l0.1,0.3a35.1,35.1 0,0 0,-12 1.2c-1.4,0.4 -1.6,0.4 -2,0 -0.1,-0.3 -0.4,-0.4 -0.5,-0.3l-0.6,-0.1c-0.4,-0.3 -0.4,-0.3 -0.2,0 0.3,0.5 0.5,1.7 0.3,1.7l-1.5,-2.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M66.8,130.2c-0.6,0 -0.8,-0.2 -0.8,-0.7 0,-0.7 0,-0.7 0.9,-0.4l2.8,0.2a6,6 0,0 0,3.3 -1l1.5,-1v0.9c0,0.6 -0.2,0.8 -0.5,0.8 -0.2,0 -0.4,0.1 -0.4,0.3 0,0.7 -4.2,1.3 -6.8,1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M137.2,129.9c0.2,-0.1 0.2,-0.3 0.1,-0.4h0.9c0.2,0 0.4,0.2 0.4,0.4 0,0.1 -0.4,0.3 -1,0.3s-0.7,-0.1 -0.4,-0.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:centerX="136.6"
android:centerY="119.2"
android:gradientRadius="32.3"
android:type="radial">
<item android:offset="0.2" android:color="#FF00CDFF"/>
<item android:offset="0.5" android:color="#FF00BCFA"/>
<item android:offset="0.8" android:color="#FF00ABF8"/>
<item android:offset="1" android:color="#FF0098F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M154.8,102.6c0.3,-0.5 -0.7,-0.7 -4.1,-0.7 -2,0 -4,-0.2 -5.8,-0.8a20,20 0,0 1,-8.2 -5.4l-1.7,-1.8 -0.6,0.7 -0.8,1.4 0.5,-1.3c0.9,-2.6 2.9,-6.3 4,-7.5 2.6,-2.7 6.3,-4 10,-3.5 6.1,1 10.3,6.8 9.4,12.9 -0.4,2 -1.7,5.2 -2,5.2 -0.3,0 -0.3,0.1 -0.2,0.3 0,0.3 0,0.5 -0.3,0.6h-0.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="130.7"
android:startY="124.8"
android:endX="152.9"
android:endY="86.6"
android:type="linear">
<item android:offset="0" android:color="#FF1964E7"/>
<item android:offset="1" android:color="#FF6884F2"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M82,135c-1.9,-0.3 -3.9,-0.4 -5.8,-0.5a58.4,58.4 0,0 1,-8.7 -0.7c-0.2,0 -0.5,-0.2 -0.6,-0.6 -0.2,-0.3 0.4,1.4 0.3,1.4 -0.2,0 -3.2,-6.8 -3.4,-7 0,0 0.7,0.2 1.5,0.7a7,7 0,0 0,5.9 0.9c2.5,-0.7 3.6,-2 7.7,-9.2 4.1,-7.3 4.6,-7.9 4.6,-6.3 0,1 -0.3,1.5 -0.9,1.5 -0.4,0 -0.5,0.2 -0.5,1 0,0.7 -0.2,1 -0.5,1 -0.2,0 -0.4,0.3 -0.4,0.6 0,0.8 -0.3,1.4 -0.7,1.4 -0.2,0 -0.4,0.2 -0.4,0.5 0,0.9 -0.3,1.5 -0.7,1.5 -0.3,0 -0.4,0.2 -0.4,0.5 0,0.8 -0.3,1.4 -0.8,1.4 -0.2,0 -0.4,0.3 -0.4,0.7 0,0.6 0.2,0.7 2.5,0.8l5.1,0.6c1.5,0.3 3.2,0.4 3.8,0.3 1,-0.2 1.1,-0.4 2.7,-3.2a39.2,39.2 0,0 1,2.4 -3.9c0,-0.3 0.3,-0.6 0.4,-0.6 0.2,0 0.3,-0.2 0.3,-0.4l0.4,-0.8 0.6,-1c0,-0.3 0.3,-0.6 0.4,-0.6 0.2,0 0.3,-0.2 0.3,-0.4 0,-0.3 0.2,-0.6 0.4,-0.8 0.2,-0.2 0.5,-0.7 0.5,-1 0.2,-0.4 0.4,-0.6 0.5,-0.6 0.2,0 0.3,-0.2 0.3,-0.5 0,-0.2 0.1,-0.4 0.3,-0.4l0.2,-0.4 0.4,-0.8 0.9,-1.4 1,-1.6 0.5,-0.8c0,-0.2 0.2,-0.3 0.3,-0.3 0.2,0 0.3,-0.2 0.3,-0.5 0,-0.2 0.2,-0.4 0.3,-0.4 0.2,0 0.3,-0.2 0.3,-0.4s0.1,-0.4 0.3,-0.4l0.2,-0.4c0,-0.3 0.2,-0.5 0.3,-0.5 0.2,0 0.3,-0.2 0.3,-0.4s0.2,-0.5 0.4,-0.6c0.2,0 0.4,-0.3 0.4,-0.5 0,-0.3 0.2,-0.4 0.3,-0.4 0.2,0 0.3,-0.2 0.3,-0.5 0,-0.2 0.2,-0.5 0.4,-0.5 0.3,-0.2 0.5,-0.4 0.5,-0.6 0,-0.2 0,-0.4 0.2,-0.4s0.3,-0.2 0.3,-0.4 0.2,-0.6 0.5,-0.8l0.9,-1c0.8,-1.7 2,-2.6 3.3,-2.6 0.6,0 0.9,0.2 1.2,0.8a2.4,2.4 0,0 0,3 1.4l2.3,-0.4c1.2,-0.2 1.2,-0.2 1.2,0.7 0,0.5 -0.3,1 -0.6,1.4a114,114 0,0 0,-11.8 18c-7.3,13 -13,23.4 -13.4,23.4 -0.1,0 -2.2,-7 -2,-7.3 0.1,-0.3 2,-2.3 1.9,-2.6 -0.2,-0.6 -3,1.1 -2.4,0.4 0.2,-0.3 4,-7.2 4.2,-8 1.4,-3.7 3,-7.4 4.9,-11 1.1,-2.1 7.4,-4 7.4,-4.1 0,-0.2 0.1,-0.3 0.3,-0.3l0.2,-0.6c0,-0.3 0.1,-0.5 0.3,-0.5 1,-1.4 1.8,-3 2.3,-4.6 0,-0.3 0.1,-0.5 0.3,-0.5 0.1,0 0.2,-0.2 0,-0.6 0,-0.3 0,-0.5 0.2,-0.5s0.3,-0.3 0.3,-0.6c0,-1 2,0.5 2.5,0.7 0.4,0.2 0.3,9.8 -1.2,0.3 0,-0.5 -1.5,1.4 -1.6,1 -0.2,-0.4 3,0.3 1.5,2 -4.2,5.2 -12.2,7.3 -19.8,20.3 -5.7,10 -6.6,11.2 -7.3,11 -0.3,0 -0.5,0 -0.5,0.2s-0.1,0.2 -0.3,0.1l-0.3,0.1c0,0.3 -0.4,0.3 -2.2,0Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M82,94.7c-1.6,-1 -3,-2.3 -3.8,-3.9l-0.8,-1.8 3.3,0.7H84l-0.2,1.3 -0.2,2.8c0,0.8 -0.1,1.5 -0.2,1.5a9,9 0,0 1,-1.3 -0.6Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="80.7"
android:endX="81.5"
android:endY="93.8"
android:type="linear">
<item android:offset="0" android:color="#FF40FAFD"/>
<item android:offset="1" android:color="#FF00E0FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M74.2,127.6c0.5,-0.6 2.6,-3.8 4.5,-7.2 7.8,-13.5 14,-24 15.3,-26a55,55 0,0 1,9 -9.2l2.1,-1.3 -0.8,1.2c-0.2,0.9 -0.5,1.8 -1,2.6 -1.1,2 -1.7,4.2 -1.7,6.5 0.3,1.4 1.2,3 2.1,3.4 0.9,0.5 1,0.5 2.6,-0.3 2.2,-1 2.8,-1.5 3.3,-2 0.2,-0.4 0.7,-0.6 1.3,-0.6 1,0 1,0 1,1 0,0.4 -0.1,0.6 -0.2,0.3 0,-0.2 -0.2,-0.4 -0.4,-0.4 -1.1,0 -8.4,10.6 -15.9,23.2 -4.8,8 -5.7,9.6 -5.3,8.5 0.3,-0.7 -0.1,-1.2 -0.6,-0.8 -0.3,0.3 -1,0.2 -3,-0.1a79,79 0,0 0,-8.5 -1c-0.5,0 -1,0.3 -1.8,1.2l-1.4,1.2 -0.9,0.4c-0.5,0.2 -0.4,0.1 0.3,-0.6ZM106,117.2c0.1,-0.4 0.4,-0.8 0.7,-1.1 0,0 -0.1,0.5 -0.5,1.1 -0.1,0.4 -0.4,0.8 -0.7,1.1l0.5,-1ZM107.4,114.7 L108.1,113.6 107.7,114.6 107,115.8c-0.1,0 0,-0.5 0.4,-1.1ZM108.5,112.7a117.6,117.6 0,0 1,6.5 -10.2,5 5,0 0,0 1,-2c0,-0.2 0.2,-0.4 0.4,-0.3 0.2,0.2 0.4,-0.3 0.3,-1.2 0,-0.2 0.2,-0.3 0.3,-0.3 0.4,0 1,-0.8 0.9,-1 -0.3,-0.3 -0.7,-0.2 -0.5,0.1 0,0.2 -0.2,0.2 -0.8,0.1 -0.6,-0.1 -0.8,0 -0.7,0.1 0.1,0.2 0,0.3 -0.4,0.2 -0.7,-0.2 -0.7,-1 0,-1 0.3,0 0.6,0 0.6,-0.2s0.1,-0.3 0.3,-0.3l2,-0.7a56,56 0,0 0,4.3 -2.2c0.4,-0.5 4,-4 -2.3,2.7 -0.3,0.3 -2.8,3.4 -3.2,3.7 -1,1.2 0,-0.2 0,-0.2l-1.8,2.6a94.5,94.5 0,0 0,-7 10.7c-0.2,0 0,-0.3 0.1,-0.6Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="98.9"
android:endX="104"
android:endY="137.8"
android:type="linear">
<item android:offset="0" android:color="#FF0CF4FF"/>
<item android:offset="0.3" android:color="#FF04EEFE"/>
<item android:offset="1" android:color="#FF00B1F7"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M83.3,91c0.1,-0.5 -2.5,-0.6 -3,-0.2 -0.4,0.3 -0.5,0.2 -0.5,0 0,-0.4 0,-0.4 -0.2,-0.1 -0.2,0.3 -0.4,0.3 -1,0 -1,-0.4 -1.7,-2.4 -1.6,-4.7 0.2,-4 2.9,-6.2 4.6,-6.3 1.4,-0.1 2.5,0 3.3,0.9 0.9,1 1.1,1.3 1.1,2.6 0,1 -0.3,2 -0.8,3.2 -0.5,1.1 -0.9,2.2 -1.2,3.4 -0.2,0.8 -0.5,1.5 -0.6,1.5 -0.2,0 -0.2,-0.1 -0.1,-0.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="81.5"
android:startY="80.7"
android:endX="81.5"
android:endY="93.8"
android:type="linear">
<item android:offset="0" android:color="#FF40FAFD"/>
<item android:offset="1" android:color="#FF00E0FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M92.2,85.4A14,14 0,0 1,91 79a17.5,17.5 0,0 1,4.6 -12.7l0.2,1c0,0.8 0,1 -0.6,1 -0.5,0 -0.5,0 -0.3,0.3 0.2,0.2 0.4,0.6 0.4,0.9 0,1.2 5.6,3.9 9.4,4.4 2.1,0.3 2.2,0.3 3.4,-0.4a5,5 0,0 1,2 -0.7c0.9,0 1,-0.1 1,-1 0,-0.6 0,-1 0.3,-1 0.2,0 0.5,-0.4 0.6,-0.8 0.1,-0.7 0.3,-0.9 1,-0.9 0.5,0 0.2,-2.9 0.2,-2.7 1.2,-0.2 -0.7,5 -3.6,7 -0.3,0 1.5,-0.5 1.5,-0.2 -0.2,0.7 -3.3,2.7 -6,3.8 -5.7,2.4 -10,5.2 -11.5,7.7 -0.7,1.1 -1,1.2 -1.4,0.7Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="102.3"
android:startY="62.1"
android:endX="102.3"
android:endY="84.3"
android:type="linear">
<item android:offset="0" android:color="#FF8EF6FD"/>
<item android:offset="1" android:color="#FF2BE8FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M111.6,96c0,-0.5 -0.6,-0.6 -1,-0.1 -0.3,0.3 -0.4,0.1 -0.4,-0.6 0,-0.8 0,-0.9 1,-0.9 0.9,0 1,0 1,1 0,0.6 -0.2,1 -0.3,1 -0.2,0 -0.3,-0.2 -0.3,-0.4Z"
android:fillColor="#59e9fe"/>
<path
android:pathData="M104.4,74.8c-1.5,-0.2 -3,-0.6 -4.5,-1 -2.7,-1 -5.4,-2.8 -5.5,-3.6 0,-0.4 -0.2,-0.7 -0.4,-0.7s-0.5,0.6 -0.6,0.5c-0.1,-0.1 0,-0.8 0.2,-0.9l0.2,-0.2 0.5,-1 0.7,-1c0.2,-0.2 1,-1.2 1.5,-1.2 0.3,0 1,0.4 1.8,1 2,1.3 4.2,2.2 6.6,2.7 1.5,0.3 2.1,0.2 4.5,-0.4 1.2,-0.3 2.3,-0.6 3.5,-0.7 0.6,0 0.7,0 0.7,1 0,0.6 -0.1,1 -0.3,0.8h-0.3l-0.1,1c0,0.3 -0.8,1.3 -1.6,2 -0.8,0.9 -1.4,1.3 -1.3,1 0.2,-0.5 0.1,-0.5 -0.7,0 -1.6,1 -2.2,1.1 -4.9,0.7Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="102.3"
android:startY="62.1"
android:endX="102.3"
android:endY="84.3"
android:type="linear">
<item android:offset="0" android:color="#FF8EF6FD"/>
<item android:offset="1" android:color="#FF2BE8FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M123.8,67.2c-3,-1.6 -3.7,-6.1 -0.9,-8.2 1,-0.7 3.3,-1.5 4,-1 0.7,0.8 0.5,1.2 2.2,1 0,0 1.4,1 1.5,2a4.9,4.9 0,0 1,-6.8 6.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="125.9"
android:startY="58.7"
android:endX="125.9"
android:endY="66.3"
android:type="linear">
<item android:offset="0" android:color="#FF92EEFE"/>
<item android:offset="1" android:color="#FF59E5FE"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M103.6,70.3a20,20 0,0 1,-6.2 -2.9c-1.1,-0.7 -1.4,-0.8 -1.9,-0.6 -1,0.7 -0.4,-0.2 1.3,-1.8 2.3,-2 5.1,-3.5 8.2,-4 5,-0.4 8.2,2.6 8.8,6.9 0.1,1 -0.6,3.2 -1.1,3.5 -0.6,0.4 -0.5,-0.1 -0.5,-0.3l0.2,-0.5c-0.2,0.4 0.3,-0.1 0.3,-0.7v-0.7l-2.5,0.7c-2.1,0.6 -4.4,0.8 -6.6,0.3Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="102.3"
android:startY="62.1"
android:endX="102.3"
android:endY="84.3"
android:type="linear">
<item android:offset="0" android:color="#FF8EF6FD"/>
<item android:offset="1" android:color="#FF2BE8FF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M130,61c-0.7,-0.2 -1.6,-0.2 -2.4,-0.2 -2,0 -2.2,0 -3,-0.7 -0.3,-0.5 -1,-0.8 -1.3,-0.8 -0.8,0 0,-0.7 1.2,-1.2 1.2,-0.4 2.5,-0.3 3.6,0.3 1.3,0.7 2,1.4 2.2,2.3 0.1,0.6 0,0.7 -0.3,0.4Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="125.9"
android:startY="58.7"
android:endX="125.9"
android:endY="66.3"
android:type="linear">
<item android:offset="0" android:color="#FF92EEFE"/>
<item android:offset="1" android:color="#FF59E5FE"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M112.5,97.3a4,4 0,0 1,-1 -1.4c-0.2,-0.6 -1.6,0.1 -1.9,0.4 -0.4,0.3 0.9,-0.5 0.9,-1.2 0,-0.6 0.5,-1.4 2.6,-3.6 3.5,-3.8 5,-5 6.4,-5 1,0 1,0.1 1.2,1.1 0.4,2.6 -0.1,6.2 -1,7.2 -0.3,0.2 -0.4,0.7 -0.3,1 0.1,0.7 0,0.9 -1.1,1.3 -0.7,0.3 -2,0.5 -3.2,0.6 -1.7,0.1 -2,0 -2.6,-0.5Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="111.6"
android:startY="80.9"
android:endX="120"
android:endY="95.3"
android:type="linear">
<item android:offset="0" android:color="#FFA6FEFF"/>
<item android:offset="0.5" android:color="#FFBFFDFE"/>
<item android:offset="1" android:color="#FF97EDFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M118.5,96.6c0.2,-0.2 0,-0.2 -0.2,-0.1 -0.3,0.1 -0.4,0 -0.4,-0.2l0.3,-1.1c0,-0.4 0.3,-1 0.5,-1.2 1,-1 1.7,-5 1,-5.4 -0.1,0 -0.2,-0.4 -0.1,-0.7l-0.1,-0.5c-0.5,0 -3.1,2.3 -5.6,5l-2.6,2.7v-1c0,-1.1 0.4,-1.6 1.3,-1.6 0.5,0 0.7,-0.2 0.7,-0.8 0,-0.6 0.4,-1.2 1.5,-2.3l1.6,-1.4 1.4,-1.2a18,18 0,0 1,10 -4.6c2,-0.2 2,-0.2 2.8,0.5a3,3 0,0 1,0.8 2.8c-0.6,1.1 -1.4,2 -2.4,2.8l-5.3,5a22,22 0,0 1,-4 3.2c-1.4,0.6 -1.4,0.6 -1.2,0.1Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="111.6"
android:startY="80.9"
android:endX="120"
android:endY="95.3"
android:type="linear">
<item android:offset="0" android:color="#FFA6FEFF"/>
<item android:offset="0.5" android:color="#FFBFFDFE"/>
<item android:offset="1" android:color="#FF97EDFF"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M103.5,98.7c-1.2,-0.3 -2.3,-2 -2.6,-3.8 -0.3,-3.6 0.8,-7.1 3,-10 1.4,-1.7 7.2,-4.5 11.4,-5.5 6,-1.4 11.5,-0.5 14.4,2.3 1.2,1.2 1.9,2.3 1.9,3.3 0,0.7 -0.7,1.6 -1.2,1.6 -0.2,0 -0.1,-0.3 0.3,-0.6 0.7,-0.6 0.7,-1.4 0,-2.3 -0.4,-0.5 -0.8,-0.6 -2,-0.6 -4.5,0 -10,3.5 -15.5,9.8 -2.7,3.2 -5,5 -7.2,5.6 -1.4,0.5 -1.5,0.5 -2.5,0.2Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="111.6"
android:startY="80.9"
android:endX="120"
android:endY="95.3"
android:type="linear">
<item android:offset="0" android:color="#FFA6FEFF"/>
<item android:offset="0.5" android:color="#FFBFFDFE"/>
<item android:offset="1" android:color="#FF97EDFF"/>
</gradient>
</aapt:attr>
</path>
</vector>

View File

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.71"
android:scaleY="0.71"
android:translateX="15.66"
android:translateY="15.66">
<path
android:pathData="M34.42,62.63C33.17,62.63 32.11,62.15 31.5,61.3L22.61,41.39C21.85,39.67 21.8,37.76 22.47,36.01C23.14,34.26 24.45,32.87 26.16,32.11C27.07,31.71 28.03,31.5 29.02,31.5C31.79,31.5 34.31,33.13 35.44,35.66L42.09,50.55L38.14,59.35C37.04,61.8 36.11,62.63 34.42,62.63H34.42Z"
android:fillColor="#005320"/>
<path
android:pathData="M73.59,62.63C71.9,62.63 70.96,61.8 69.87,59.35L65.92,50.54L72.57,35.66C73.69,33.13 76.21,31.5 78.98,31.5C79.97,31.5 80.93,31.71 81.84,32.11C83.55,32.88 84.86,34.26 85.53,36.01C86.2,37.76 86.15,39.67 85.39,41.39L76.5,61.3C75.89,62.15 74.83,62.63 73.59,62.63Z"
android:fillColor="#005320"/>
<path
android:pathData="M69.36,72.38C67.68,72.38 66.74,71.55 65.64,69.1L58.45,53.04C57.88,51.77 56.7,49.11 54,49.11C51.31,49.11 50.08,51.87 49.55,53.04L42.36,69.09C41.27,71.55 40.33,72.38 38.65,72.38C37.43,72.38 36.26,71.85 35.64,71.04C35.58,70.92 35.53,70.81 35.47,70.68C34.25,68.08 33.09,65.25 32.31,63.29C32.94,63.57 33.65,63.72 34.42,63.72C36.89,63.72 38.05,62.22 39.13,59.79L47.55,41.01C48.68,38.48 51.2,36.85 53.97,36.85H54.03C56.8,36.85 59.32,38.48 60.45,41.01L68.88,59.8C69.96,62.22 71.13,63.72 73.59,63.72C74.36,63.72 75.07,63.57 75.7,63.29C74.92,65.25 73.76,68.08 72.54,70.69C72.48,70.81 72.43,70.92 72.37,71.04C71.75,71.86 70.58,72.38 69.36,72.38H69.36Z"
android:fillColor="#005320"/>
<path
android:pathData="M65.27,76.3C63.24,76.26 61.24,75.34 59.93,73.84C59.51,73.34 59.13,72.74 58.82,72.08C58.82,72.08 56.53,66.88 54.5,62.29L54.37,61.99L54.01,61.13L54,61.16L53.99,61.13L53.63,61.99L53.5,62.29C51.46,66.88 49.17,72.1 49.17,72.1C48.86,72.74 48.49,73.33 48.06,73.85C46.76,75.34 44.77,76.26 42.73,76.3H42.69C40.89,76.23 39.39,75.65 38.1,74.52C37.69,74.14 37.3,73.69 36.92,73.18C37.46,73.36 38.04,73.46 38.64,73.46C41.1,73.46 42.26,71.96 43.34,69.53L50.53,53.48C51.04,52.33 52,50.19 54,50.19C56,50.19 56.95,52.33 57.47,53.48L64.65,69.54C65.73,71.96 66.9,73.46 69.36,73.46C69.96,73.46 70.54,73.36 71.08,73.18C70.7,73.69 70.3,74.15 69.89,74.53C68.61,75.65 67.11,76.23 65.31,76.3H65.27V76.3Z"
android:fillColor="#005320"/>
</group>
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Some files were not shown because too many files have changed in this diff Show More