diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 0000000..c76712e
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,26 @@
+name: Android CI
+
+on:
+ push:
+ branches: [ "develop" ]
+ pull_request:
+ branches: [ "develop" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: "17"
+ distribution: "temurin"
+ cache: gradle
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+ - name: Build with Gradle
+ run: ./gradlew ktlintCheck buildDebug
diff --git a/.gitignore b/.gitignore
index 347e252..a001ee5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
+# Created by https://www.toptal.com/developers/gitignore/api/android,androidstudio,macos,windows,intellij,java,kotlin
+# Edit at https://www.toptal.com/developers/gitignore?templates=android,androidstudio,macos,windows,intellij,java,kotlin
+
+### Android ###
# Gradle files
.gradle/
build/
@@ -31,3 +35,330 @@ google-services.json
# Android Profiling
*.hprof
+
+### Android Patch ###
+gen-external-apklibs
+
+# Replacement of .externalNativeBuild directories introduced
+# with Android Studio 3.5.
+
+### Intellij ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Intellij Patch ###
+# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
+
+# *.iml
+# modules.xml
+# .idea/misc.xml
+# *.ipr
+
+# Sonarlint plugin
+# https://plugins.jetbrains.com/plugin/7973-sonarlint
+.idea/**/sonarlint/
+
+# SonarQube Plugin
+# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
+.idea/**/sonarIssues.xml
+
+# Markdown Navigator plugin
+# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
+.idea/**/markdown-navigator.xml
+.idea/**/markdown-navigator-enh.xml
+.idea/**/markdown-navigator/
+
+# Cache file creation bug
+# See https://youtrack.jetbrains.com/issue/JBR-2257
+.idea/$CACHE_FILE$
+
+# CodeStream plugin
+# https://plugins.jetbrains.com/plugin/12206-codestream
+.idea/codestream.xml
+
+# Azure Toolkit for IntelliJ plugin
+# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
+.idea/**/azureSettings.xml
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
+
+### Kotlin ###
+# Compiled class file
+
+# Log file
+
+# BlueJ files
+
+# Mobile Tools for Java (J2ME)
+
+# Package Files #
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### macOS Patch ###
+# iCloud generated files
+*.icloud
+
+### Windows ###
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+### AndroidStudio ###
+# Covers files to be ignored for android development using Android Studio.
+
+# Built application files
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle
+
+# Signing files
+.signing/
+
+# Local configuration file (sdk path, etc)
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+
+# Android Studio
+/*/build/
+/*/local.properties
+/*/out
+/*/*/build
+/*/*/production
+.navigation/
+*.ipr
+*~
+*.swp
+
+# Keystore files
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Android Patch
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# NDK
+obj/
+
+# IntelliJ IDEA
+/out/
+
+# User-specific configurations
+.idea/caches/
+.idea/libraries/
+.idea/shelf/
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/.name
+.idea/compiler.xml
+.idea/copyright/profiles_settings.xml
+.idea/encodings.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/scopes/scope_settings.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+.idea/datasources.xml
+.idea/dataSources.ids
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+.idea/assetWizardSettings.xml
+.idea/gradle.xml
+.idea/jarRepositories.xml
+.idea/navEditor.xml
+
+# Legacy Eclipse project files
+.classpath
+.project
+.cproject
+.settings/
+
+# Mobile Tools for Java (J2ME)
+
+# Package Files #
+
+# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)
+
+## Plugin-specific files:
+
+# mpeltonen/sbt-idea plugin
+
+# JIRA plugin
+
+# Mongo Explorer plugin
+.idea/mongoSettings.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+
+### AndroidStudio Patch ###
+
+!/gradle/wrapper/gradle-wrapper.jar
+
+# End of https://www.toptal.com/developers/gitignore/api/android,androidstudio,macos,windows,intellij,java,kotlin
\ No newline at end of file
diff --git a/.media/brand_image.png b/.media/brand_image.png
new file mode 100644
index 0000000..fcfe238
Binary files /dev/null and b/.media/brand_image.png differ
diff --git a/.media/brand_image.psd b/.media/brand_image.psd
new file mode 100644
index 0000000..195dcf3
Binary files /dev/null and b/.media/brand_image.psd differ
diff --git a/.media/icon.png b/.media/icon.png
new file mode 100644
index 0000000..1f9f350
Binary files /dev/null and b/.media/icon.png differ
diff --git a/.media/icon.psd b/.media/icon.psd
new file mode 100644
index 0000000..e5189a1
Binary files /dev/null and b/.media/icon.psd differ
diff --git a/LICENSE b/LICENSE
index 261eeb9..cc1e2c6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2023 Florian Schuster
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 8b88771..d55aa84 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
# hydro
+
simple hydration reminder app
+
+![logo](.media/icon.png)
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..769ab73
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,102 @@
+plugins {
+ id "com.android.application"
+ id "org.jetbrains.kotlin.android"
+ id "kotlin-parcelize"
+ id "org.jlleitschuh.gradle.ktlint"
+ id "kotlinx-serialization"
+ id "com.google.devtools.ksp"
+}
+
+android {
+ namespace "at.florianschuster.hydro"
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "at.florianschuster.hydro"
+ minSdk 28
+ targetSdk 34
+ versionCode 1
+ versionName "0.1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary true
+ }
+ ksp {
+ arg("room.schemaLocation", "$projectDir/schemas")
+ }
+ }
+
+ buildTypes {
+ debug {
+ debuggable true
+ }
+ release {
+ debuggable false
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
+ }
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+ buildFeatures {
+ compose true
+ buildConfig true
+ }
+ composeOptions {
+ kotlinCompilerExtensionVersion "1.5.1"
+ }
+ packagingOptions {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ exclude("META-INF/versions/9/previous-compilation-data.bin")
+ }
+}
+
+dependencies {
+ implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.9.0"))
+ implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0-RC"
+
+ implementation("androidx.core:core-ktx:1.10.1")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
+ implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.1")
+ implementation("androidx.lifecycle:lifecycle-process:2.6.1")
+ implementation("androidx.activity:activity-compose:1.7.2")
+ implementation("androidx.core:core-splashscreen:1.0.1")
+
+ implementation("androidx.browser:browser:1.6.0")
+ implementation("androidx.datastore:datastore-preferences:1.0.0")
+
+ implementation(platform("androidx.compose:compose-bom:2023.06.01"))
+ implementation("androidx.compose.animation:animation")
+ implementation("androidx.compose.ui:ui")
+ implementation("androidx.compose.ui:ui-graphics")
+ implementation("androidx.compose.ui:ui-tooling-preview")
+ implementation("androidx.compose.material3:material3")
+ implementation("androidx.compose.material:material-icons-extended")
+ implementation("androidx.constraintlayout:constraintlayout-compose:1.0.1")
+
+ def room_version = "2.5.2"
+ implementation("androidx.room:room-runtime:$room_version")
+ implementation("androidx.room:room-ktx:$room_version")
+ ksp("androidx.room:room-compiler:$room_version")
+
+ implementation("dev.olshevski.navigation:reimagined:1.4.0")
+ implementation("dev.olshevski.navigation:reimagined-material3:1.4.0")
+ implementation("com.airbnb.android:lottie-compose:6.0.1")
+
+ debugImplementation("androidx.compose.ui:ui-tooling")
+ debugImplementation("androidx.compose.ui:ui-test-manifest")
+
+ implementation("androidx.work:work-runtime-ktx:2.8.1")
+ implementation("androidx.health.connect:connect-client:1.1.0-alpha03")
+
+ testImplementation("junit:junit:4.13.2")
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/schemas/at.florianschuster.hydro.service.DayDatabase/1.json b/app/schemas/at.florianschuster.hydro.service.DayDatabase/1.json
new file mode 100644
index 0000000..64da49a
--- /dev/null
+++ b/app/schemas/at.florianschuster.hydro.service.DayDatabase/1.json
@@ -0,0 +1,62 @@
+{
+ "formatVersion": 1,
+ "database": {
+ "version": 1,
+ "identityHash": "19bad9520ed04230a868077de3e49ddd",
+ "entities": [
+ {
+ "tableName": "day",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`date` INTEGER NOT NULL, `hydration` TEXT NOT NULL, `goalMilliliters` INTEGER NOT NULL, `id` TEXT NOT NULL, PRIMARY KEY(`id`))",
+ "fields": [
+ {
+ "fieldPath": "date",
+ "columnName": "date",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "hydration",
+ "columnName": "hydration",
+ "affinity": "TEXT",
+ "notNull": true
+ },
+ {
+ "fieldPath": "goalMilliliters",
+ "columnName": "goalMilliliters",
+ "affinity": "INTEGER",
+ "notNull": true
+ },
+ {
+ "fieldPath": "id",
+ "columnName": "id",
+ "affinity": "TEXT",
+ "notNull": true
+ }
+ ],
+ "primaryKey": {
+ "autoGenerate": false,
+ "columnNames": [
+ "id"
+ ]
+ },
+ "indices": [
+ {
+ "name": "index_day_date",
+ "unique": true,
+ "columnNames": [
+ "date"
+ ],
+ "orders": [],
+ "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_day_date` ON `${TABLE_NAME}` (`date`)"
+ }
+ ],
+ "foreignKeys": []
+ }
+ ],
+ "views": [],
+ "setupQueries": [
+ "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '19bad9520ed04230a868077de3e49ddd')"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f067524
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/at/florianschuster/hydro/App.kt b/app/src/main/java/at/florianschuster/hydro/App.kt
new file mode 100644
index 0000000..db95a75
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/App.kt
@@ -0,0 +1,74 @@
+package at.florianschuster.hydro
+
+import android.app.Application
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.ProcessLifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import at.florianschuster.hydro.service.AndroidLocaleChangedService
+import at.florianschuster.hydro.service.Channel
+import at.florianschuster.hydro.service.HydrationHistoryStore
+import at.florianschuster.hydro.service.NotificationService
+import at.florianschuster.hydro.service.PreferencesStore
+import at.florianschuster.hydro.service.ReminderAlarmService
+import at.florianschuster.hydro.service.SqliteHydrationHistoryStore
+
+class App : Application() {
+
+ lateinit var store: AppStore
+ lateinit var hydrationHistoryStore: HydrationHistoryStore
+
+ override fun onCreate() {
+ super.onCreate()
+
+ instance = this
+
+ Channel.registerAll(this)
+
+ val processLifecycleOwner = ProcessLifecycleOwner.get()
+ hydrationHistoryStore = SqliteHydrationHistoryStore(
+ context = applicationContext,
+ isDebug = isDebug
+ )
+ val preferencesStore = PreferencesStore(
+ context = applicationContext
+ )
+ val notificationService = NotificationService(
+ context = applicationContext
+ )
+ val reminderAlarmService = ReminderAlarmService(
+ context = applicationContext,
+ preferencesStore = preferencesStore,
+ processLifecycleOwner.lifecycleScope
+ )
+ val localeChangedService = AndroidLocaleChangedService(
+ context = applicationContext
+ )
+ store = AppStore(
+ isDebug = isDebug,
+ scope = processLifecycleOwner.lifecycleScope,
+ preferencesStore = preferencesStore,
+ hydrationHistoryStore = hydrationHistoryStore,
+ reminderAlarmService = reminderAlarmService,
+ notificationService = notificationService,
+ localeChangedService = localeChangedService
+ )
+
+ processLifecycleOwner.lifecycle.addObserver(
+ object : DefaultLifecycleObserver {
+ override fun onResume(owner: LifecycleOwner) {
+ store.dispatch(AppAction.SetAppInForeground(true))
+ }
+
+ override fun onPause(owner: LifecycleOwner) {
+ store.dispatch(AppAction.SetAppInForeground(false))
+ }
+ }
+ )
+ }
+
+ companion object {
+ private val isDebug = BuildConfig.DEBUG
+ lateinit var instance: App
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/AppStore.kt b/app/src/main/java/at/florianschuster/hydro/AppStore.kt
new file mode 100644
index 0000000..0389a50
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/AppStore.kt
@@ -0,0 +1,264 @@
+package at.florianschuster.hydro
+
+import at.florianschuster.hydro.model.Cup
+import at.florianschuster.hydro.model.Day
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.Now
+import at.florianschuster.hydro.model.NowInstant
+import at.florianschuster.hydro.model.Percent
+import at.florianschuster.hydro.model.Reminder
+import at.florianschuster.hydro.model.Theme
+import at.florianschuster.hydro.model.Today
+import at.florianschuster.hydro.model.defaultCups
+import at.florianschuster.hydro.model.defaultSelectedCups
+import at.florianschuster.hydro.model.reachedGoal
+import at.florianschuster.hydro.model.sumOfMilliliters
+import at.florianschuster.hydro.model.times
+import at.florianschuster.hydro.service.HydrationHistoryStore
+import at.florianschuster.hydro.service.LocaleChangedService
+import at.florianschuster.hydro.service.NotificationService
+import at.florianschuster.hydro.service.PreferencesStore
+import at.florianschuster.hydro.service.ReminderAlarmService
+import at.florianschuster.hydro.service.hasCelebratedGoalToday
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.update
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.datetime.Instant
+
+data class AppState(
+ val isDebug: Boolean,
+ val dailyGoal: Milliliters,
+ val todayHydration: Milliliters,
+ val reminder: Reminder?,
+ val theme: Theme,
+ val canScheduleAlarms: Boolean,
+ val defaultCups: List,
+ val selectedCups: List,
+ val appInForeground: Boolean,
+ val liquidUnit: LiquidUnit,
+ val onboardingShown: Boolean
+) {
+ val hydrationProgress: Percent = Percent(
+ todayHydration.value / dailyGoal.value.toFloat()
+ )
+ val dailyGoalReached: Boolean = hydrationProgress.value >= 1f
+ val allCups = (defaultCups + selectedCups).distinct().sorted()
+}
+
+sealed interface AppAction {
+ data class SetDailyGoal(val value: Milliliters) : AppAction
+ data class AddHydration(val value: Milliliters) : AppAction
+ data class SetReminder(val value: Reminder?) : AppAction
+ data object RestartReminder : AppAction
+ data class ShowHydrationReminderNotification(val forced: Boolean = false) : AppAction
+ data class SetTheme(val value: Theme) : AppAction
+ data class SetSelectedCups(val value: List) : AppAction
+ data class SetAppInForeground(val value: Boolean) : AppAction
+ data class SetLiquidUnit(val value: LiquidUnit) : AppAction
+ data object SetHydrationForOnboarding : AppAction
+ data object SetOnboardingShown : AppAction
+ data object DeleteAll : AppAction
+ data object ResetToday : AppAction
+}
+
+class AppStore(
+ private val hydrationHistoryStore: HydrationHistoryStore,
+ isDebug: Boolean,
+ localeChangedService: LocaleChangedService,
+ private val notificationService: NotificationService,
+ private val preferencesStore: PreferencesStore,
+ private val reminderAlarmService: ReminderAlarmService,
+ private val scope: CoroutineScope
+) {
+ private val _state = MutableStateFlow(
+ AppState(
+ isDebug = isDebug,
+ dailyGoal = runBlocking {
+ preferencesStore.dailyGoal.first() ?: Milliliters.DAILY_GOAL_DEFAULT
+ },
+ todayHydration = runBlocking {
+ hydrationHistoryStore.day(Today).first()?.hydration?.sumOfMilliliters()
+ ?: Milliliters.ZERO
+ },
+ reminder = runBlocking { preferencesStore.reminder.first() },
+ theme = runBlocking { preferencesStore.theme.first() },
+ canScheduleAlarms = reminderAlarmService.canScheduleAlarms.value,
+ defaultCups = defaultCups(),
+ selectedCups = runBlocking {
+ preferencesStore.selectedCups.first().sorted()
+ .ifEmpty { defaultSelectedCups() }
+ },
+ appInForeground = true,
+ liquidUnit = runBlocking { preferencesStore.liquidUnit.first() },
+ onboardingShown = runBlocking { preferencesStore.onboardingShown.first() }
+ )
+ )
+ val state: StateFlow = _state.asStateFlow()
+
+ init {
+ preferencesStore.dailyGoal.onEach { milliliters ->
+ _state.update { it.copy(dailyGoal = milliliters ?: Milliliters.DAILY_GOAL_DEFAULT) }
+ }.launchIn(scope)
+ preferencesStore.reminder.onEach { reminder ->
+ _state.update { it.copy(reminder = reminder) }
+ }.launchIn(scope)
+ preferencesStore.theme.onEach { theme ->
+ _state.update { it.copy(theme = theme) }
+ }.launchIn(scope)
+ preferencesStore.selectedCups.onEach { selectedCups ->
+ _state.update {
+ it.copy(
+ selectedCups = selectedCups.sorted()
+ .ifEmpty { defaultSelectedCups() }
+ )
+ }
+ }.launchIn(scope)
+ preferencesStore.liquidUnit.onEach { liquidUnit ->
+ _state.update { it.copy(liquidUnit = liquidUnit) }
+ }.launchIn(scope)
+ preferencesStore.onboardingShown.onEach { onboardingShown ->
+ _state.update { it.copy(onboardingShown = onboardingShown) }
+ }.launchIn(scope)
+
+ hydrationHistoryStore.day(Today).onEach { day ->
+ val todayHydration = day?.hydration?.sumOfMilliliters()
+ ?: Milliliters.ZERO
+ _state.update { it.copy(todayHydration = todayHydration) }
+ }.launchIn(scope)
+
+ reminderAlarmService.canScheduleAlarms.onEach { canScheduleAlarms ->
+ _state.update { it.copy(canScheduleAlarms = canScheduleAlarms) }
+ }.launchIn(scope)
+
+ localeChangedService.onChanged.onEach { locale ->
+ _state.update { it.copy(defaultCups = defaultCups(locale)) }
+ }.launchIn(scope)
+ }
+
+ fun dispatch(action: AppAction) {
+ when (action) {
+ is AppAction.SetDailyGoal -> scope.launch {
+ preferencesStore.setDailyGoal(action.value)
+ val day = hydrationHistoryStore.day(Today).first()
+ if (day != null) {
+ hydrationHistoryStore.setDay(day.copy(goal = action.value))
+ }
+ }
+
+ is AppAction.AddHydration -> scope.launch {
+ notificationService.cancelHydrationReminderNotification()
+ val currentState = _state.value
+ val storedDay = hydrationHistoryStore.day(Today).first()
+ if (storedDay != null) {
+ val updatedDay = storedDay.copy(
+ hydration = storedDay.hydration + Day.Hydration(action.value, Now),
+ goal = currentState.dailyGoal
+ )
+ val goalReachedOnUpdatedDay = updatedDay.reachedGoal()
+ if (goalReachedOnUpdatedDay && !preferencesStore.hasCelebratedGoalToday()) {
+ if (!currentState.appInForeground) {
+ notificationService.showDailyGoalReachedNotification()
+ }
+ preferencesStore.setLastGoalCelebration(NowInstant)
+ }
+ hydrationHistoryStore.setDay(updatedDay)
+ } else {
+ hydrationHistoryStore.setDay(
+ Day(
+ date = Today,
+ hydration = listOf(Day.Hydration(action.value, Now)),
+ goal = currentState.dailyGoal
+ )
+ )
+ }
+ }
+
+ is AppAction.SetReminder -> scope.launch {
+ if (action.value != null) {
+ reminderAlarmService.setAlarm(action.value)
+ } else {
+ reminderAlarmService.clear()
+ }
+ preferencesStore.setReminder(action.value)
+ }
+
+ is AppAction.RestartReminder -> scope.launch {
+ val reminder = preferencesStore.reminder.first()
+ if (reminder != null) {
+ reminderAlarmService.setAlarm(reminder)
+ }
+ }
+
+ is AppAction.ShowHydrationReminderNotification -> scope.launch {
+ if (action.forced || !preferencesStore.hasCelebratedGoalToday()) {
+ val todayMilliliters = hydrationHistoryStore.day(Today).first()
+ ?.hydration
+ ?.sumOfMilliliters()
+ ?: Milliliters.ZERO
+ val selectedCups = preferencesStore.selectedCups.first()
+ .ifEmpty { defaultSelectedCups() }
+ .sorted()
+ notificationService.showHydrationReminderNotification(
+ todayMilliliters = todayMilliliters,
+ todayProgress = _state.value.hydrationProgress,
+ selectedCups = selectedCups,
+ liquidUnit = preferencesStore.liquidUnit.first()
+ )
+ }
+ }
+
+ is AppAction.SetTheme -> scope.launch {
+ preferencesStore.setTheme(action.value)
+ }
+
+ is AppAction.SetSelectedCups -> scope.launch {
+ preferencesStore.setSelectedCups(action.value)
+ }
+
+ is AppAction.DeleteAll -> scope.launch {
+ preferencesStore.clear()
+ hydrationHistoryStore.clear()
+ reminderAlarmService.clear()
+ notificationService.clear()
+ }
+
+ is AppAction.SetAppInForeground -> _state.update {
+ it.copy(appInForeground = action.value)
+ }
+
+ is AppAction.ResetToday -> scope.launch {
+ val today = hydrationHistoryStore.day(Today).first() ?: return@launch
+ hydrationHistoryStore.setDay(today.copy(hydration = emptyList()))
+ preferencesStore.setLastGoalCelebration(Instant.DISTANT_PAST)
+ }
+
+ is AppAction.SetLiquidUnit -> scope.launch {
+ preferencesStore.setLiquidUnit(action.value)
+ }
+
+ is AppAction.SetHydrationForOnboarding -> scope.launch {
+ val goal = _state.value.dailyGoal
+ hydrationHistoryStore.setDay(
+ Day(
+ date = Today,
+ hydration = listOf(Day.Hydration(goal * 0.55f, Now)),
+ goal = goal
+ )
+ )
+ }
+
+ is AppAction.SetOnboardingShown -> scope.launch {
+ preferencesStore.setOnboardingShown(true)
+ dispatch(AppAction.ResetToday)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/DeveloperInfo.kt b/app/src/main/java/at/florianschuster/hydro/DeveloperInfo.kt
new file mode 100644
index 0000000..b555d9b
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/DeveloperInfo.kt
@@ -0,0 +1,41 @@
+package at.florianschuster.hydro
+
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.net.Uri
+import android.widget.Toast
+import androidx.browser.customtabs.CustomTabsIntent
+
+private const val DEV_URL = "https://florianschuster.at/"
+private const val DEV_EMAIL = "hydro.mobileapp@gmail.com"
+
+fun Activity.openInfoCustomTab() {
+ val customTab = CustomTabsIntent.Builder().apply {
+ setShowTitle(true)
+ setInstantAppsEnabled(true)
+ }.build()
+ runCatching {
+ customTab.launchUrl(this, Uri.parse(DEV_URL))
+ }.onFailure {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(DEV_URL))
+ startActivity(intent)
+ }
+}
+
+fun Activity.openFeedback() {
+ try {
+ startActivity(
+ Intent(Intent.ACTION_SEND).apply {
+ data = Uri.parse("mailto:$DEV_EMAIL")
+ putExtra(Intent.EXTRA_SUBJECT, "Feedback hydro app")
+ }
+ )
+ } catch (ex: ActivityNotFoundException) {
+ Toast.makeText(
+ this,
+ "No email client installed.",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/MainActivity.kt b/app/src/main/java/at/florianschuster/hydro/MainActivity.kt
new file mode 100644
index 0000000..476d122
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/MainActivity.kt
@@ -0,0 +1,204 @@
+package at.florianschuster.hydro
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.BackHandler
+import androidx.activity.compose.setContent
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
+import androidx.compose.animation.with
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.core.view.WindowCompat
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import at.florianschuster.hydro.model.Theme
+import at.florianschuster.hydro.model.isDarkTheme
+import at.florianschuster.hydro.ui.GoalOfTheDayBottomSheet
+import at.florianschuster.hydro.ui.HistoryScreen
+import at.florianschuster.hydro.ui.HistoryScreenToolbar
+import at.florianschuster.hydro.ui.OnboardingScreen
+import at.florianschuster.hydro.ui.SetIntervalBottomSheet
+import at.florianschuster.hydro.ui.SetLiquidUnitBottomSheet
+import at.florianschuster.hydro.ui.SettingsScreen
+import at.florianschuster.hydro.ui.SettingsToolbar
+import at.florianschuster.hydro.ui.ThemeBottomSheet
+import at.florianschuster.hydro.ui.TodayScreen
+import at.florianschuster.hydro.ui.TodayToolbar
+import at.florianschuster.hydro.ui.base.HydrationBackground
+import at.florianschuster.hydro.ui.base.HydroTheme
+import dev.olshevski.navigation.reimagined.AnimatedNavHost
+import dev.olshevski.navigation.reimagined.NavAction
+import dev.olshevski.navigation.reimagined.NavBackHandler
+import dev.olshevski.navigation.reimagined.material3.BottomSheetNavHost
+import dev.olshevski.navigation.reimagined.navigate
+import dev.olshevski.navigation.reimagined.pop
+import dev.olshevski.navigation.reimagined.rememberNavController
+
+class MainActivity : ComponentActivity() {
+
+ @OptIn(ExperimentalAnimationApi::class)
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ val store = App.instance.store
+
+ setContent {
+ val state by store.state.collectAsStateWithLifecycle()
+
+ HydroTheme(
+ darkTheme = state.theme.isDarkTheme(),
+ dynamicColor = state.theme == Theme.Dynamic
+ ) {
+ Surface(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ HydrationBackground(
+ isSystemInDarkTheme = state.theme.isDarkTheme(),
+ hydrationProgress = state.hydrationProgress
+ )
+
+ val navController = rememberNavController(
+ startDestination = if (state.onboardingShown) {
+ Screen.Today
+ } else {
+ Screen.Onboarding
+ }
+ )
+ val sheetController = rememberNavController(
+ initialBackstack = emptyList()
+ )
+
+ NavBackHandler(navController)
+ AnimatedNavHost(
+ controller = navController,
+ transitionSpec = { action, _, _ ->
+ when (action) {
+ is NavAction.Pop -> {
+ fadeIn() with slideOutVertically(
+ targetOffsetY = { fullHeight -> fullHeight }
+ ) + fadeOut()
+ }
+
+ is NavAction.Navigate -> {
+ slideInVertically(
+ initialOffsetY = { fullHeight -> fullHeight }
+ ) + fadeIn() with fadeOut()
+ }
+
+ else -> error("no transition defined for $action")
+ }
+ }
+ ) { screen ->
+ Scaffold(
+ topBar = {
+ when (screen) {
+ is Screen.Onboarding -> {
+ // no toolbar
+ }
+
+ is Screen.Today -> TodayToolbar(
+ isDebug = state.isDebug,
+ onGoToSettings = {
+ navController.navigate(Screen.Settings)
+ },
+ onGoToHistory = {
+ navController.navigate(Screen.History)
+ }
+ )
+
+ is Screen.Settings -> SettingsToolbar(
+ onGoBack = navController::pop
+ )
+
+ is Screen.History -> HistoryScreenToolbar(
+ onGoBack = navController::pop
+ )
+ }
+ },
+ containerColor = Color.Transparent
+ ) { contentPadding ->
+ when (screen) {
+ is Screen.Onboarding -> OnboardingScreen(
+ contentPadding = contentPadding,
+ dispatch = store::dispatch,
+ onOnboardingFinished = {
+ navController.navigate(
+ listOf(Screen.Today, Screen.Settings)
+ )
+ }
+ )
+
+ is Screen.Today -> TodayScreen(
+ contentPadding = contentPadding,
+ state = state,
+ dispatch = store::dispatch
+ )
+
+ is Screen.Settings -> SettingsScreen(
+ contentPadding = contentPadding,
+ state = state,
+ dispatch = store::dispatch,
+ onSetGoalOfTheDay = { sheetController.navigate(Sheet.GoalOfTheDay) },
+ onSetLiquidUnit = { sheetController.navigate(Sheet.LiquidUnit) },
+ onSetTheme = { sheetController.navigate(Sheet.SetTheme) },
+ onShowDeveloperInfo = { openInfoCustomTab() },
+ onWriteDeveloper = { openFeedback() },
+ onSetInterval = { sheetController.navigate(Sheet.SetInterval) }
+ )
+
+ is Screen.History -> HistoryScreen(
+ contentPadding = contentPadding,
+ appState = state
+ )
+ }
+ }
+ }
+
+ BackHandler(
+ enabled = sheetController.backstack.entries.isNotEmpty(),
+ onBack = sheetController::pop
+ )
+ BottomSheetNavHost(
+ controller = sheetController,
+ onDismissRequest = sheetController::pop,
+ scrimColor = Color.Black.copy(alpha = 0.75f)
+ ) { sheet ->
+ when (sheet) {
+ is Sheet.GoalOfTheDay -> GoalOfTheDayBottomSheet(
+ state = state,
+ dispatch = store::dispatch
+ )
+
+ is Sheet.SetTheme -> ThemeBottomSheet(
+ state = state,
+ dispatch = store::dispatch,
+ onClose = sheetController::pop
+ )
+
+ is Sheet.SetInterval -> SetIntervalBottomSheet(
+ state = state,
+ dispatch = store::dispatch,
+ onClose = sheetController::pop
+ )
+
+ is Sheet.LiquidUnit -> SetLiquidUnitBottomSheet(
+ state = state,
+ dispatch = store::dispatch,
+ onClose = sheetController::pop
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/Screen.kt b/app/src/main/java/at/florianschuster/hydro/Screen.kt
new file mode 100644
index 0000000..24ba1af
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/Screen.kt
@@ -0,0 +1,33 @@
+package at.florianschuster.hydro
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+sealed interface Screen : Parcelable {
+ @Parcelize
+ data object Onboarding : Screen
+
+ @Parcelize
+ data object Today : Screen
+
+ @Parcelize
+ data object Settings : Screen
+
+ @Parcelize
+ data object History : Screen
+}
+
+sealed interface Sheet : Parcelable {
+
+ @Parcelize
+ data object GoalOfTheDay : Sheet
+
+ @Parcelize
+ data object LiquidUnit : Sheet
+
+ @Parcelize
+ data object SetTheme : Sheet
+
+ @Parcelize
+ data object SetInterval : Sheet
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Cup.kt b/app/src/main/java/at/florianschuster/hydro/model/Cup.kt
new file mode 100644
index 0000000..615203c
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Cup.kt
@@ -0,0 +1,43 @@
+package at.florianschuster.hydro.model
+
+import kotlinx.serialization.Serializable
+import java.util.Locale
+
+@Serializable
+data class Cup(
+ val milliliters: Milliliters
+) : Comparable {
+ override fun compareTo(other: Cup): Int = milliliters compareTo other.milliliters
+}
+
+fun defaultCups(
+ locale: Locale = Locale.getDefault()
+): List = defaultSelectedCups(locale) + when (locale) {
+ Locale.US,
+ Locale.UK -> listOf(
+ Cup(Milliliters(355)), // 12 oz
+ Cup(Milliliters(591)), // 20 oz
+ Cup(Milliliters(946)), // 32 oz
+ Cup(Milliliters(1183)) // 40 oz
+ )
+
+ else -> listOf(
+ Cup(Milliliters(330)),
+ Cup(Milliliters(500)),
+ Cup(Milliliters(1_000)),
+ Cup(Milliliters(2_000))
+ )
+}.sorted()
+
+fun defaultSelectedCups(
+ locale: Locale = Locale.getDefault()
+) = when (locale) {
+ Locale.US,
+ Locale.UK -> listOf(
+ Cup(Milliliters(236)) // 8 oz
+ )
+
+ else -> listOf(
+ Cup(Milliliters(250))
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/DateTime.kt b/app/src/main/java/at/florianschuster/hydro/model/DateTime.kt
new file mode 100644
index 0000000..8b62352
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/DateTime.kt
@@ -0,0 +1,143 @@
+package at.florianschuster.hydro.model
+
+import android.icu.text.MeasureFormat
+import android.icu.util.MeasureUnit
+import kotlinx.datetime.Clock
+import kotlinx.datetime.Instant
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.LocalDateTime
+import kotlinx.datetime.LocalTime
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.toJavaLocalDate
+import kotlinx.datetime.toJavaLocalTime
+import kotlinx.datetime.toLocalDateTime
+import java.text.NumberFormat
+import java.time.format.DateTimeFormatter
+import java.util.Locale
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.Duration.Companion.seconds
+
+val UserTimeZone: TimeZone
+ get() = TimeZone.currentSystemDefault()
+
+val NowInstant: Instant
+ get() = Clock.System.now()
+
+val TodayNow: LocalDateTime
+ get() = NowInstant.toLocalDateTime(UserTimeZone)
+
+val Today: LocalDate
+ get() = TodayNow.date
+
+val Now: LocalTime
+ get() = TodayNow.time
+
+operator fun LocalTime.plus(
+ duration: Duration
+): LocalTime {
+ return LocalTime.fromMillisecondOfDay(
+ toMillisecondOfDay() + duration.inWholeMilliseconds.toInt()
+ )
+}
+
+private val usDateFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy")
+private val euDateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
+
+fun LocalDate.format(
+ locale: Locale = Locale.getDefault()
+): String = when (locale) {
+ Locale.US,
+ Locale.UK -> toJavaLocalDate().format(usDateFormatter)
+
+ else -> toJavaLocalDate().format(euDateFormatter)
+}
+
+private val usTimeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
+private val euTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")
+fun LocalTime.format(
+ locale: Locale = Locale.getDefault()
+): String = when (locale) {
+ Locale.US,
+ Locale.UK -> toJavaLocalTime().format(usTimeFormatter)
+
+ else -> toJavaLocalTime().format(euTimeFormatter)
+}
+
+fun Duration.format(
+ locale: Locale = Locale.getDefault()
+): String {
+ return DurationFormat(locale).format(this, DurationFormat.DurationUnit.MINUTE)
+}
+
+// https://gist.github.com/Jeehut/78534c27b24d78f14a3cbd3eebead861
+class DurationFormat(
+ private val locale: Locale = Locale.getDefault()
+) {
+
+ enum class DurationUnit {
+ DAY, HOUR, MINUTE, SECOND, MILLISECOND
+ }
+
+ fun format(
+ duration: Duration,
+ smallestUnit: DurationUnit = DurationUnit.SECOND
+ ): String {
+ val formattedStringComponents = mutableListOf()
+ var remainder = duration
+
+ for (unit in DurationUnit.entries) {
+ val component = calculateComponent(unit, remainder)
+
+ remainder = when (unit) {
+ DurationUnit.DAY -> remainder - component.days
+ DurationUnit.HOUR -> remainder - component.hours
+ DurationUnit.MINUTE -> remainder - component.minutes
+ DurationUnit.SECOND -> remainder - component.seconds
+ DurationUnit.MILLISECOND -> remainder - component.milliseconds
+ }
+
+ val unitDisplayName = unitDisplayName(unit)
+
+ if (component > 0) {
+ val formattedComponent = NumberFormat.getInstance(locale).format(component)
+ formattedStringComponents.add("$formattedComponent$unitDisplayName")
+ }
+
+ if (unit == smallestUnit) {
+ val formattedZero = NumberFormat.getInstance(locale).format(0)
+ if (formattedStringComponents.isEmpty()) {
+ formattedStringComponents.add("$formattedZero$unitDisplayName")
+ }
+ break
+ }
+ }
+
+ return formattedStringComponents.joinToString(" ")
+ }
+
+ private fun calculateComponent(unit: DurationUnit, remainder: Duration) = when (unit) {
+ DurationUnit.DAY -> remainder.inWholeDays
+ DurationUnit.HOUR -> remainder.inWholeHours
+ DurationUnit.MINUTE -> remainder.inWholeMinutes
+ DurationUnit.SECOND -> remainder.inWholeSeconds
+ DurationUnit.MILLISECOND -> remainder.inWholeMilliseconds
+ }
+
+ private fun unitDisplayName(unit: DurationUnit): String {
+ val measureFormat = MeasureFormat.getInstance(
+ locale,
+ MeasureFormat.FormatWidth.NARROW
+ )
+ return when (unit) {
+ DurationUnit.DAY -> measureFormat.getUnitDisplayName(MeasureUnit.DAY)
+ DurationUnit.HOUR -> measureFormat.getUnitDisplayName(MeasureUnit.HOUR)
+ DurationUnit.MINUTE -> measureFormat.getUnitDisplayName(MeasureUnit.MINUTE)
+ DurationUnit.SECOND -> measureFormat.getUnitDisplayName(MeasureUnit.SECOND)
+ DurationUnit.MILLISECOND -> measureFormat.getUnitDisplayName(MeasureUnit.MILLISECOND)
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Day.kt b/app/src/main/java/at/florianschuster/hydro/model/Day.kt
new file mode 100644
index 0000000..081480a
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Day.kt
@@ -0,0 +1,31 @@
+package at.florianschuster.hydro.model
+
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.LocalTime
+import kotlinx.serialization.Serializable
+import java.util.UUID
+
+data class Day(
+ val date: LocalDate,
+ val hydration: List,
+ val goal: Milliliters,
+ val id: String = UUID.randomUUID().toString()
+) : Comparable {
+
+ @Serializable
+ data class Hydration(
+ val milliliters: Milliliters,
+ val time: LocalTime,
+ val id: String = UUID.randomUUID().toString()
+ ) : Comparable {
+ override fun compareTo(other: Hydration): Int = time compareTo other.time
+ }
+
+ override fun compareTo(other: Day): Int = date compareTo other.date
+}
+
+fun List.sumOfMilliliters(): Milliliters {
+ return Milliliters(sumOf { it.milliliters.value })
+}
+
+fun Day.reachedGoal(): Boolean = hydration.sumOfMilliliters() >= goal
diff --git a/app/src/main/java/at/florianschuster/hydro/model/LiquidUnit.kt b/app/src/main/java/at/florianschuster/hydro/model/LiquidUnit.kt
new file mode 100644
index 0000000..2631cac
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/LiquidUnit.kt
@@ -0,0 +1,53 @@
+package at.florianschuster.hydro.model
+
+enum class LiquidUnit(
+ val baseUnitMultiplier: Double,
+ val serialized: String
+) {
+ Milliliter(
+ baseUnitMultiplier = 1.0,
+ serialized = "ml"
+ ),
+ USFluidOunce(
+ baseUnitMultiplier = 0.033814, // 1 milliliter = 0.033814 oz
+ serialized = "oz_us"
+ ),
+ UKFluidOunce(
+ baseUnitMultiplier = 0.035195, // 1 milliliter = 0.035195 oz
+ serialized = "oz_uk"
+ );
+
+ fun convertValue(
+ milliliters: Milliliters
+ ): Double = milliliters.value * baseUnitMultiplier
+
+ companion object {
+ fun of(serialized: String?): LiquidUnit = if (serialized == null) {
+ Milliliter
+ } else {
+ entries.firstOrNull { it.serialized == serialized } ?: Milliliter
+ }
+ }
+}
+
+fun LiquidUnit.format() = when (this) {
+ LiquidUnit.Milliliter -> "Milliliters (ml)"
+ LiquidUnit.USFluidOunce -> "US Ounces (fl oz US)"
+ LiquidUnit.UKFluidOunce -> "UK Ounces (fl oz UK)"
+}
+
+fun LiquidUnit.formatMoreInfo() = when (this) {
+ LiquidUnit.Milliliter ->
+ "Milliliters are a standard metric unit of liquid volume. " +
+ "They provide a precise way to measure fluids, making them ideal for accurate " +
+ "hydration monitoring."
+
+ LiquidUnit.USFluidOunce ->
+ "US ounces serve as a customary unit for liquid volume " +
+ "predominantly in the United States."
+
+ LiquidUnit.UKFluidOunce ->
+ "UK ounces, also referred to as Imperial ounces, are a " +
+ "volume measurement commonly utilized in the United Kingdom and certain other " +
+ "regions."
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Milliliters.kt b/app/src/main/java/at/florianschuster/hydro/model/Milliliters.kt
new file mode 100644
index 0000000..1d8a86e
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Milliliters.kt
@@ -0,0 +1,55 @@
+package at.florianschuster.hydro.model
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.painter.Painter
+import androidx.compose.ui.res.painterResource
+import at.florianschuster.hydro.R
+import kotlinx.serialization.Serializable
+import kotlin.math.roundToInt
+
+@Serializable
+@JvmInline
+value class Milliliters(val value: Int) : Comparable {
+ override fun compareTo(other: Milliliters): Int = value compareTo other.value
+
+ companion object {
+ val ZERO: Milliliters = Milliliters(0)
+
+ val DAILY_GOAL_DEFAULT: Milliliters = Milliliters(2_000)
+ val DAILY_GOAL_MIN: Milliliters = Milliliters(500)
+ val DAILY_GOAL_MAX: Milliliters = Milliliters(5_000)
+ val DAILY_GOAL_STEPS: Milliliters = Milliliters(100)
+ }
+}
+
+operator fun Milliliters?.plus(
+ other: Milliliters
+): Milliliters = Milliliters((this?.value ?: 0) + other.value)
+
+operator fun Milliliters.minus(
+ other: Milliliters
+): Milliliters = Milliliters(maxOf(0, value - other.value))
+
+operator fun Milliliters.times(
+ other: Float
+): Milliliters = Milliliters(maxOf(0f, value * other).roundToInt())
+
+fun Milliliters.format(
+ unit: LiquidUnit
+): String {
+ val actualValue = unit.convertValue(this).roundToInt()
+ return when (unit) {
+ LiquidUnit.Milliliter -> "$actualValue ml"
+ LiquidUnit.USFluidOunce -> "$actualValue oz."
+ LiquidUnit.UKFluidOunce -> "$actualValue oz."
+ }
+}
+
+@Composable
+fun Milliliters.icon(): Painter = when (value) {
+ in 0..250 -> painterResource(R.drawable.ic_water_less)
+ in 251..330 -> painterResource(R.drawable.ic_water_medium)
+ in 331..750 -> painterResource(R.drawable.ic_water_full)
+ in 751..1_000 -> painterResource(R.drawable.ic_water_bottle)
+ else -> painterResource(R.drawable.ic_water_bottle_large)
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Percent.kt b/app/src/main/java/at/florianschuster/hydro/model/Percent.kt
new file mode 100644
index 0000000..1db0320
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Percent.kt
@@ -0,0 +1,16 @@
+package at.florianschuster.hydro.model
+
+import androidx.annotation.FloatRange
+import kotlin.math.roundToInt
+
+@JvmInline
+value class Percent(
+ // 0.0f = 0%, 1.0f = 100%
+ @FloatRange(from = 0.0, to = Double.MAX_VALUE) val value: Float
+) {
+ init {
+ require(value >= 0f)
+ }
+}
+
+fun Percent.format(): String = "${(value * 100).roundToInt()}%"
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Reminder.kt b/app/src/main/java/at/florianschuster/hydro/model/Reminder.kt
new file mode 100644
index 0000000..496cfcc
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Reminder.kt
@@ -0,0 +1,34 @@
+package at.florianschuster.hydro.model
+
+import kotlinx.datetime.LocalTime
+import kotlinx.serialization.Serializable
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.minutes
+
+@Serializable
+data class Reminder(
+ val start: LocalTime,
+ val end: LocalTime,
+ val interval: Duration
+) {
+ init {
+ require(start < end) { "$start cannot be before $end" }
+ }
+
+ companion object {
+ val DEFAULT = Reminder(
+ start = LocalTime(9, 0, 0, 0),
+ end = LocalTime(18, 0, 0, 0),
+ interval = 30.minutes
+ )
+ }
+}
+
+fun Reminder.calculateReminderTimes(): List = buildList {
+ var current = start
+ while (current <= end) {
+ add(current)
+ current += interval
+ }
+ if (!contains(end)) add(end)
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/model/Theme.kt b/app/src/main/java/at/florianschuster/hydro/model/Theme.kt
new file mode 100644
index 0000000..3a4f785
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/model/Theme.kt
@@ -0,0 +1,56 @@
+package at.florianschuster.hydro.model
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.ColorLens
+import androidx.compose.material.icons.outlined.DarkMode
+import androidx.compose.material.icons.outlined.InvertColors
+import androidx.compose.material.icons.outlined.LightMode
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.vector.ImageVector
+
+enum class Theme(
+ val serialized: String
+) {
+ System("system"),
+ Dynamic("dynamic"),
+ Dark("dark"),
+ Light("light");
+
+ companion object {
+ fun of(serialized: String?) = if (serialized == null) {
+ System
+ } else {
+ entries.firstOrNull { it.serialized == serialized } ?: System
+ }
+ }
+}
+
+@Composable
+fun Theme.isDarkTheme(): Boolean {
+ return when (this) {
+ Theme.Dark -> true
+ Theme.Light -> false
+ Theme.System,
+ Theme.Dynamic -> isSystemInDarkTheme()
+ }
+}
+
+fun Theme.format(): String {
+ return when (this) {
+ Theme.Dark -> "Dark"
+ Theme.Light -> "Light"
+ Theme.System -> "System"
+ Theme.Dynamic -> "Dynamic"
+ }
+}
+
+@Composable
+fun Theme.icon(): ImageVector {
+ return when (this) {
+ Theme.Dark -> Icons.Outlined.DarkMode
+ Theme.Light -> Icons.Outlined.LightMode
+ Theme.System -> Icons.Outlined.InvertColors
+ Theme.Dynamic -> Icons.Outlined.ColorLens
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/service/HydrationHistoryStore.kt b/app/src/main/java/at/florianschuster/hydro/service/HydrationHistoryStore.kt
new file mode 100644
index 0000000..5b01ef8
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/service/HydrationHistoryStore.kt
@@ -0,0 +1,195 @@
+package at.florianschuster.hydro.service
+
+import android.content.Context
+import androidx.lifecycle.ProcessLifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.room.Dao
+import androidx.room.Database
+import androidx.room.Delete
+import androidx.room.Entity
+import androidx.room.Index
+import androidx.room.Insert
+import androidx.room.OnConflictStrategy
+import androidx.room.PrimaryKey
+import androidx.room.Query
+import androidx.room.Room
+import androidx.room.RoomDatabase
+import androidx.room.TypeConverter
+import androidx.room.TypeConverters
+import at.florianschuster.hydro.model.Day
+import at.florianschuster.hydro.model.Milliliters
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import kotlinx.datetime.DatePeriod
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.LocalTime
+import kotlinx.datetime.minus
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+
+interface HydrationHistoryStore {
+ suspend fun setDay(day: Day)
+ fun day(date: LocalDate): Flow
+ suspend fun days(
+ startDateExclusive: LocalDate,
+ pageSize: Int = 20
+ ): List
+
+ suspend fun delete(date: LocalDate)
+ suspend fun clear()
+}
+
+class SqliteHydrationHistoryStore(
+ context: Context,
+ isDebug: Boolean,
+ private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
+) : HydrationHistoryStore {
+
+ private val database: DayDatabase = Room.databaseBuilder(
+ context = context.applicationContext,
+ klass = DayDatabase::class.java,
+ name = databaseName
+ ).apply {
+ if (isDebug) fallbackToDestructiveMigration()
+ }.build()
+
+ init {
+ // insert test data
+ if (isDebug) {
+ ProcessLifecycleOwner.get().lifecycleScope.launch(ioDispatcher) {
+ if (day(debugStartDate).firstOrNull() == null) {
+ generateTestHydrationData().forEach { setDay(it) }
+ }
+ }
+ }
+ }
+
+ override suspend fun setDay(day: Day) {
+ database.dayDao().upsert(day.toDTO())
+ }
+
+ override fun day(date: LocalDate): Flow {
+ return database.dayDao().get(date).map { it?.fromDTO() }
+ }
+
+ override suspend fun days(
+ startDateExclusive: LocalDate,
+ pageSize: Int
+ ): List = withContext(ioDispatcher) {
+ database.dayDao().getDescending(startDateExclusive, pageSize).map(DayDTO::fromDTO)
+ }
+
+ override suspend fun delete(date: LocalDate) = withContext(ioDispatcher) {
+ val day = database.dayDao().get(date).firstOrNull() ?: return@withContext
+ database.dayDao().delete(day)
+ }
+
+ override suspend fun clear() = withContext(ioDispatcher) {
+ database.clearAllTables()
+ }
+
+ companion object {
+ private const val databaseName = "day-database"
+ }
+}
+
+@Entity(
+ tableName = "day",
+ indices = [Index("date", unique = true)]
+)
+data class DayDTO(
+ val date: LocalDate,
+ val hydration: List,
+ val goalMilliliters: Int,
+ @PrimaryKey val id: String
+) : Comparable {
+ override fun compareTo(other: DayDTO): Int = date compareTo other.date
+}
+
+private fun DayDTO.fromDTO(): Day = Day(
+ date = date,
+ hydration = hydration,
+ goal = Milliliters(goalMilliliters),
+ id = id
+)
+
+private fun Day.toDTO(): DayDTO = DayDTO(
+ date = date,
+ hydration = hydration,
+ goalMilliliters = goal.value,
+ id = id
+)
+
+@Dao
+interface DayDao {
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun upsert(vararg days: DayDTO)
+
+ @Query("SELECT * FROM day WHERE date = :date LIMIT 1")
+ fun get(date: LocalDate): Flow
+
+ @Query(
+ "SELECT * FROM day WHERE date < :startDateExclusive ORDER BY date desc LIMIT :limit "
+ )
+ fun getDescending(startDateExclusive: LocalDate, limit: Int): List
+
+ @Delete
+ suspend fun delete(day: DayDTO)
+}
+
+@Database(entities = [DayDTO::class], version = 1)
+@TypeConverters(LocalDateConverter::class, DayHydrationConverter::class)
+abstract class DayDatabase : RoomDatabase() {
+ abstract fun dayDao(): DayDao
+}
+
+class LocalDateConverter {
+ @TypeConverter
+ fun fromLocalDate(date: LocalDate): Int = date.toEpochDays()
+
+ @TypeConverter
+ fun toLocalDate(epochDays: Int): LocalDate = LocalDate.fromEpochDays(epochDays)
+}
+
+class DayHydrationConverter {
+ @TypeConverter
+ fun fromDayHydration(dayHydration: List): String {
+ return json.encodeToString(dayHydration)
+ }
+
+ @TypeConverter
+ fun toDayHydration(serialized: String): List {
+ return json.decodeFromString(serialized)
+ }
+
+ companion object {
+ val json = Json
+ }
+}
+
+private val debugStartDate = LocalDate.fromEpochDays(19000)
+
+private fun generateTestHydrationData(): List = buildList {
+ for (i in 1..100) {
+ val date = debugStartDate.minus(DatePeriod(days = i))
+ val hydrationList = generateTestHydrationList()
+ val goal = Milliliters((1500..2500).random())
+ add(Day(date, hydrationList, goal))
+ }
+}
+
+private fun generateTestHydrationList(): List = buildList {
+ // Random number of hydration instances (1 to 5)
+ val numHydrations = (1..5).random()
+ for (i in 0 until numHydrations) {
+ val milliliters = Milliliters((100..500).random())
+ val time = LocalTime((0..23).random(), (0..59).random())
+ add(Day.Hydration(milliliters, time))
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/service/LocaleChangedService.kt b/app/src/main/java/at/florianschuster/hydro/service/LocaleChangedService.kt
new file mode 100644
index 0000000..7514585
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/service/LocaleChangedService.kt
@@ -0,0 +1,40 @@
+package at.florianschuster.hydro.service
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import androidx.core.content.ContextCompat
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import java.util.Locale
+
+interface LocaleChangedService {
+ val onChanged: Flow
+}
+
+class AndroidLocaleChangedService(
+ context: Context
+) : LocaleChangedService {
+
+ override val onChanged: Flow = callbackFlow {
+ trySend(context.getMainLocale())
+ val receiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == Intent.ACTION_LOCALE_CHANGED) {
+ trySend(context.getMainLocale())
+ }
+ }
+ }
+ ContextCompat.registerReceiver(
+ context,
+ receiver,
+ IntentFilter(Intent.ACTION_LOCALE_CHANGED),
+ ContextCompat.RECEIVER_NOT_EXPORTED
+ )
+ awaitClose { context.unregisterReceiver(receiver) }
+ }
+
+ private fun Context.getMainLocale(): Locale = resources.configuration.locales.get(0)
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/service/NotificationService.kt b/app/src/main/java/at/florianschuster/hydro/service/NotificationService.kt
new file mode 100644
index 0000000..c59bffc
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/service/NotificationService.kt
@@ -0,0 +1,184 @@
+package at.florianschuster.hydro.service
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import androidx.annotation.IntRange
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
+import androidx.core.content.getSystemService
+import at.florianschuster.hydro.App
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.MainActivity
+import at.florianschuster.hydro.R
+import at.florianschuster.hydro.model.Cup
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.Percent
+import at.florianschuster.hydro.model.format
+
+class NotificationService(
+ private val context: Context
+) {
+
+ private val notificationManager: NotificationManager = checkNotNull(context.getSystemService())
+
+ private val openAppPendingIntent = PendingIntent.getActivity(
+ context,
+ 1,
+ Intent(context, MainActivity::class.java),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+
+ fun showHydrationReminderNotification(
+ todayMilliliters: Milliliters,
+ todayProgress: Percent,
+ selectedCups: List,
+ liquidUnit: LiquidUnit
+ ) {
+ notificationManager.notify(
+ hydrationReminderId,
+ Notification.Builder(
+ context,
+ Channel.Hydrate.id
+ ).apply {
+ setSmallIcon(R.drawable.ic_notification)
+ setContentTitle("Hydration Reminder")
+ setContentText(todayMilliliters.asReminderMessage())
+ setSubText("${todayMilliliters.format(liquidUnit)} (${todayProgress.format()})")
+ setColor(NOTIFICATION_COLOR)
+ setContentIntent(openAppPendingIntent)
+ selectedCups.forEach { cup ->
+ addAction(
+ Notification.Action.Builder(
+ null,
+ cup.milliliters.format(liquidUnit),
+ addCupPendingIntent(cup.milliliters)
+ ).build()
+ )
+ }
+ setShowWhen(true)
+ setAutoCancel(true)
+ }.build()
+ )
+ }
+
+ private fun Milliliters.asReminderMessage(): String = when (value) {
+ in 0..199 -> "Time to Hydrate! Take a Sip of Water and Stay Refreshed."
+ in 200..299 -> "Stay Hydrated! Your Body Needs Water. Take a Break and Drink Up!"
+ in 300..399 -> "Hydration Alert! Grab a Glass of Water and Rehydrate."
+ in 400..499 -> "Don't Forget to Drink Water! Your Body Thanks You."
+ in 500..599 -> "Quench Your Thirst! It's Hydration O'Clock."
+ in 600..699 -> "Stay Healthy and Hydrated! Time for a Water Break."
+ in 700..799 -> "Water Time! Hydrate Yourself for Optimal Wellness."
+ in 800..899 -> "Hydration Check: Have You Had Your Glass of Water Yet?"
+ in 900..999 -> "A Little H2O Never Hurt! Stay Hydrated for a Productive Day."
+ in 1000..1099 -> "Refill Your Cup! Hydration Is the Key to Feeling Great."
+ in 1100..1199 -> "Stay Hydrated! Another Glass of Water Brings You Closer to Wellness."
+ in 1200..1299 -> "Hydration Alert! Keep Sipping Water for a Healthy You."
+ in 1300..1399 -> "Don't Forget to Stay Hydrated! Your Body Loves Water."
+ in 1400..1499 -> "Quench Your Thirst! It's Time for More Hydration."
+ in 1500..1599 -> "Stay Healthy and Hydrated! Keep Up the Water Intake."
+ in 1600..1699 -> "Water Time! Hydrate to Energize Your Body."
+ in 1700..1799 -> "Hydration Check: Keep the Water Coming for a Productive Day."
+ in 1800..1899 -> "Stay Hydrated! Your Body Will Thank You."
+ in 1900..1999 -> "A Little H2O Never Hurt! Keep Hydrating for Optimal Wellness."
+ else -> "Keep Hydrating! Your Body Will Thank You."
+ }
+
+ private fun addCupPendingIntent(
+ milliliters: Milliliters
+ ) = PendingIntent.getBroadcast(
+ context,
+ milliliters.value,
+ Intent(context, AddCupFromNotification::class.java).apply {
+ putExtra(AddCupFromNotification.EXTRA_MILLILITERS_VALUE, milliliters.value)
+ },
+ PendingIntent.FLAG_IMMUTABLE
+ )
+
+ fun cancelHydrationReminderNotification() {
+ notificationManager.cancel(hydrationReminderId)
+ }
+
+ fun showDailyGoalReachedNotification() {
+ notificationManager.notify(
+ goalReachedId,
+ Notification.Builder(
+ context,
+ Channel.GoalReached.id
+ ).apply {
+ setSmallIcon(R.drawable.ic_notification)
+ setContentTitle("You reached your goal today!")
+ setContentText("\uD83D\uDCA7\uD83C\uDF89\uD83C\uDF8A\uD83E\uDD73")
+ setContentIntent(openAppPendingIntent)
+ setColor(NOTIFICATION_COLOR)
+ setShowWhen(true)
+ setAutoCancel(true)
+ }.build()
+ )
+ }
+
+ fun clear() {
+ notificationManager.cancelAll()
+ }
+
+ companion object {
+ private const val hydrationReminderId = 1357
+ private const val goalReachedId = 1358
+ private val NOTIFICATION_COLOR = Color(0xFF00A3F8).toArgb()
+ }
+}
+
+class AddCupFromNotification : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val millilitersValue = intent.getIntExtra(EXTRA_MILLILITERS_VALUE, -1)
+ if (millilitersValue == -1) return
+ App.instance.store.dispatch(
+ AppAction.AddHydration(Milliliters(millilitersValue))
+ )
+ }
+
+ companion object {
+ const val EXTRA_MILLILITERS_VALUE = "EXTRA_MILLILITERS_VALUE"
+ }
+}
+
+enum class Channel(
+ val id: String,
+ private val displayName: String,
+ private val description: String,
+ @IntRange(from = 0, to = 4) private val importance: Int
+) {
+ Hydrate(
+ id = "HydroReminder",
+ displayName = "Hydration Reminder",
+ description = "Notifications for hydration reminders set in the application.",
+ importance = NotificationManager.IMPORTANCE_HIGH
+ ),
+ GoalReached(
+ id = "GoalReached",
+ displayName = "Hydration Goal Reached",
+ description = "Notifications for when you reach your hydration goal for the day.",
+ importance = NotificationManager.IMPORTANCE_DEFAULT
+ );
+
+ companion object {
+ fun registerAll(context: Context) {
+ checkNotNull(context.getSystemService())
+ .createNotificationChannels(
+ entries.map { channel ->
+ NotificationChannel(
+ channel.id,
+ channel.displayName,
+ channel.importance
+ ).also { it.description = channel.description }
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/service/PreferencesStore.kt b/app/src/main/java/at/florianschuster/hydro/service/PreferencesStore.kt
new file mode 100644
index 0000000..4df6bf5
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/service/PreferencesStore.kt
@@ -0,0 +1,128 @@
+package at.florianschuster.hydro.service
+
+import android.content.Context
+import androidx.datastore.preferences.core.MutablePreferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.intPreferencesKey
+import androidx.datastore.preferences.core.longPreferencesKey
+import androidx.datastore.preferences.core.stringPreferencesKey
+import androidx.datastore.preferences.preferencesDataStore
+import at.florianschuster.hydro.model.Cup
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.Reminder
+import at.florianschuster.hydro.model.Theme
+import at.florianschuster.hydro.model.Today
+import at.florianschuster.hydro.model.UserTimeZone
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.map
+import kotlinx.datetime.Instant
+import kotlinx.datetime.toLocalDateTime
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+
+class PreferencesStore(
+ private val context: Context
+) {
+
+ val dailyGoal: Flow = context.dataStore.data.map { preferences ->
+ val persisted = preferences[dailyTargetMillilitersKey]
+ if (persisted != null) Milliliters(persisted) else null
+ }
+
+ suspend fun setDailyGoal(milliliters: Milliliters) {
+ context.dataStore.edit { it[dailyTargetMillilitersKey] = milliliters.value }
+ }
+
+ val reminder: Flow = context.dataStore.data.map { preferences ->
+ val persisted = preferences[reminderKey] ?: return@map null
+ json.decodeFromString(persisted)
+ }
+
+ suspend fun setReminder(reminder: Reminder?) {
+ context.dataStore.edit { preferences ->
+ if (reminder == null) {
+ preferences.remove(reminderKey)
+ } else {
+ preferences[reminderKey] = json.encodeToString(reminder)
+ }
+ }
+ }
+
+ val theme: Flow = context.dataStore.data.map { preferences ->
+ val persisted = preferences[themeKey]
+ Theme.of(persisted)
+ }
+
+ suspend fun setTheme(theme: Theme) {
+ context.dataStore.edit { preferences ->
+ preferences[themeKey] = theme.serialized
+ }
+ }
+
+ val lastGoalCelebration: Flow = context.dataStore.data.map { preferences ->
+ val persisted = preferences[lastGoalCelebrationKey] ?: return@map Instant.DISTANT_PAST
+ Instant.fromEpochMilliseconds(persisted)
+ }
+
+ suspend fun setLastGoalCelebration(instant: Instant) {
+ context.dataStore.edit { preferences ->
+ preferences[lastGoalCelebrationKey] = instant.toEpochMilliseconds()
+ }
+ }
+
+ val selectedCups: Flow> = context.dataStore.data.map { preferences ->
+ val persisted = preferences[selectedCupsKey] ?: return@map emptyList()
+ json.decodeFromString(persisted)
+ }
+
+ suspend fun setSelectedCups(cups: List) {
+ context.dataStore.edit { preferences ->
+ preferences[selectedCupsKey] = json.encodeToString(cups)
+ }
+ }
+
+ val liquidUnit: Flow = context.dataStore.data.map { preferences ->
+ val persisted = preferences[liquidUnitKey]
+ LiquidUnit.of(persisted)
+ }
+
+ suspend fun setLiquidUnit(unit: LiquidUnit) {
+ context.dataStore.edit { it[liquidUnitKey] = unit.serialized }
+ }
+
+ val onboardingShown: Flow = context.dataStore.data.map { preferences ->
+ preferences[onboardingShownKey] ?: false
+ }
+
+ suspend fun setOnboardingShown(shown: Boolean) {
+ context.dataStore.edit { it[onboardingShownKey] = shown }
+ }
+
+ suspend fun clear() {
+ context.dataStore.edit(MutablePreferences::clear)
+ }
+
+ companion object {
+ private val json = Json
+
+ private val Context.dataStore by preferencesDataStore("user_preferences")
+ private val dailyTargetMillilitersKey = intPreferencesKey("dailyTargetMilliliters")
+ private val reminderKey = stringPreferencesKey("reminder")
+ private val themeKey = stringPreferencesKey("theme")
+ private val lastGoalCelebrationKey = longPreferencesKey("lastGoalCelebration")
+ private val selectedCupsKey = stringPreferencesKey("selectedCups")
+ private val liquidUnitKey = stringPreferencesKey("liquidUnit")
+ private val onboardingShownKey = booleanPreferencesKey("onboardingShown")
+ }
+}
+
+suspend fun PreferencesStore.hasCelebratedGoalToday(): Boolean {
+ val lastCelebrationDate = lastGoalCelebration
+ .first()
+ .toLocalDateTime(UserTimeZone)
+ .date
+ return lastCelebrationDate == Today
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/service/ReminderAlarmService.kt b/app/src/main/java/at/florianschuster/hydro/service/ReminderAlarmService.kt
new file mode 100644
index 0000000..8baaa13
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/service/ReminderAlarmService.kt
@@ -0,0 +1,110 @@
+package at.florianschuster.hydro.service
+
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Build
+import androidx.core.content.getSystemService
+import at.florianschuster.hydro.App
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.model.Now
+import at.florianschuster.hydro.model.Reminder
+import at.florianschuster.hydro.model.Today
+import at.florianschuster.hydro.model.UserTimeZone
+import at.florianschuster.hydro.model.calculateReminderTimes
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.datetime.DatePeriod
+import kotlinx.datetime.LocalDateTime
+import kotlinx.datetime.LocalTime
+import kotlinx.datetime.plus
+import kotlinx.datetime.toInstant
+
+class ReminderAlarmService(
+ private val context: Context,
+ private val preferencesStore: PreferencesStore,
+ scope: CoroutineScope
+) {
+
+ private val alarmManager: AlarmManager = checkNotNull(context.getSystemService())
+
+ private val canScheduleAlarmsNow: Boolean
+ get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ alarmManager.canScheduleExactAlarms()
+ } else {
+ true
+ }
+
+ val canScheduleAlarms: StateFlow = callbackFlow {
+ send(canScheduleAlarmsNow)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val receiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ trySend(canScheduleAlarmsNow)
+ }
+ }
+ context.registerReceiver(
+ receiver,
+ IntentFilter(AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED)
+ )
+ awaitClose { context.unregisterReceiver(receiver) }
+ } else {
+ awaitClose()
+ }
+ }.stateIn(scope, SharingStarted.Eagerly, canScheduleAlarmsNow)
+
+ suspend fun setAlarm(reminder: Reminder) {
+ clear()
+ check(canScheduleAlarms.value) { "cannot schedule exact reminders without permission." }
+ reminder.calculateReminderTimes().forEach { time ->
+ val alarmTime = if (time <= Now) {
+ LocalDateTime(Today + DatePeriod(days = 1), time)
+ } else {
+ LocalDateTime(Today, time)
+ }.toInstant(UserTimeZone)
+ alarmManager.setRepeating(
+ AlarmManager.RTC_WAKEUP,
+ alarmTime.toEpochMilliseconds(),
+ AlarmManager.INTERVAL_DAY,
+ alarmPendingIntent(time)
+ )
+ }
+ }
+
+ suspend fun clear() {
+ val reminder = preferencesStore.reminder.first() ?: return
+ reminder.calculateReminderTimes().forEach { time ->
+ alarmManager.cancel(alarmPendingIntent(time))
+ }
+ }
+
+ private fun alarmPendingIntent(time: LocalTime): PendingIntent {
+ return PendingIntent.getBroadcast(
+ context,
+ time.toMillisecondOfDay(),
+ Intent(context, ReminderShowNotificationReceiver::class.java),
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+}
+
+class ReminderShowNotificationReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ App.instance.store.dispatch(AppAction.ShowHydrationReminderNotification())
+ }
+}
+
+class ReminderBootCompleteReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action != Intent.ACTION_BOOT_COMPLETED) return
+ App.instance.store.dispatch(AppAction.RestartReminder)
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/CupCarouselSelection.kt b/app/src/main/java/at/florianschuster/hydro/ui/CupCarouselSelection.kt
new file mode 100644
index 0000000..d08212a
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/CupCarouselSelection.kt
@@ -0,0 +1,80 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.Cup
+import at.florianschuster.hydro.ui.base.HydrationCarousel
+
+@Composable
+fun CupCarouselSelection(
+ modifier: Modifier = Modifier,
+ state: AppState,
+ dispatch: (AppAction) -> Unit
+) {
+ Column(modifier = modifier) {
+ var showCanOnlySelectThreeAlert by remember { mutableStateOf(false) }
+ Text(
+ modifier = Modifier.padding(horizontal = 24.dp),
+ text = "Cups",
+ style = MaterialTheme.typography.titleLarge
+ )
+ Text(
+ modifier = Modifier.padding(horizontal = 24.dp),
+ text = "Cups are displayed on your Main screen and in you Reminder notification",
+ style = MaterialTheme.typography.labelSmall,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Spacer(modifier = Modifier.height(16.dp))
+ val allCupsAsMilliliters = remember(state.allCups) {
+ state.allCups.map(Cup::milliliters)
+ }
+ val selectedCupsAsMilliliters = remember(state.selectedCups) {
+ state.selectedCups.map(Cup::milliliters)
+ }
+ HydrationCarousel(
+ contentPadding = PaddingValues(horizontal = 36.dp),
+ milliliterItems = allCupsAsMilliliters,
+ liquidUnit = state.liquidUnit,
+ selected = selectedCupsAsMilliliters,
+ onClick = { index, _ ->
+ val cup = state.allCups[index]
+ if (cup in state.selectedCups) {
+ dispatch(AppAction.SetSelectedCups(state.selectedCups - cup))
+ } else if (state.selectedCups.count() >= 3) {
+ showCanOnlySelectThreeAlert = true
+ } else {
+ dispatch(AppAction.SetSelectedCups(state.selectedCups + cup))
+ }
+ }
+ )
+ if (showCanOnlySelectThreeAlert) {
+ AlertDialog(
+ title = { Text(text = "Sorry") },
+ text = { Text(text = "You can only select 3 different Cups.") },
+ onDismissRequest = { showCanOnlySelectThreeAlert = false },
+ confirmButton = {
+ Button(
+ onClick = { showCanOnlySelectThreeAlert = false },
+ content = { Text(text = "Ok") }
+ )
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/GoalOfTheDayBottomSheet.kt b/app/src/main/java/at/florianschuster/hydro/ui/GoalOfTheDayBottomSheet.kt
new file mode 100644
index 0000000..05e000c
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/GoalOfTheDayBottomSheet.kt
@@ -0,0 +1,88 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Slider
+import androidx.compose.material3.SliderDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.ui.base.BottomSheet
+import at.florianschuster.hydro.ui.base.HydroTheme
+import kotlin.math.roundToInt
+
+@Composable
+fun GoalOfTheDayBottomSheet(
+ state: AppState,
+ dispatch: (AppAction) -> Unit
+) {
+ BottomSheet(
+ title = "Goal of the Day"
+ ) {
+ MillilitersSlider(
+ range = remember { Milliliters.DAILY_GOAL_MIN..Milliliters.DAILY_GOAL_MAX },
+ stepsSize = remember { Milliliters.DAILY_GOAL_STEPS },
+ milliliters = state.dailyGoal,
+ onMillilitersChanged = { dispatch(AppAction.SetDailyGoal(it)) }
+ )
+ Text(text = state.dailyGoal.format(state.liquidUnit))
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun MillilitersSlider(
+ range: ClosedRange,
+ stepsSize: Milliliters,
+ milliliters: Milliliters,
+ onMillilitersChanged: (Milliliters) -> Unit
+) {
+ val valueRange = remember(range) {
+ range.start.value.toFloat()..range.endInclusive.value.toFloat()
+ }
+ val steps = remember(valueRange) {
+ val itemCount = (valueRange.endInclusive - valueRange.start).roundToInt()
+ if (stepsSize.value == 1) 0 else (itemCount / stepsSize.value - 1)
+ }
+ Slider(
+ value = milliliters.value.toFloat(),
+ valueRange = valueRange,
+ steps = steps,
+ onValueChange = { onMillilitersChanged(Milliliters(it.roundToInt())) },
+ colors = SliderDefaults.colors(
+ activeTickColor = Color.Transparent,
+ inactiveTickColor = Color.Transparent
+ )
+ )
+}
+
+@Preview
+@Composable
+fun MillilitersSliderPreviewDark() {
+ HydroTheme(darkTheme = true, dynamicColor = false) {
+ MillilitersSlider(
+ range = Milliliters(0)..Milliliters(2000),
+ stepsSize = Milliliters(100),
+ milliliters = Milliliters(1000),
+ onMillilitersChanged = {}
+ )
+ }
+}
+
+@Preview
+@Composable
+fun MillilitersSliderPreviewLight() {
+ HydroTheme(darkTheme = false, dynamicColor = false) {
+ MillilitersSlider(
+ range = Milliliters(0)..Milliliters(2000),
+ stepsSize = Milliliters(100),
+ milliliters = Milliliters(1000),
+ onMillilitersChanged = {}
+ )
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/HistoryScreen.kt b/app/src/main/java/at/florianschuster/hydro/ui/HistoryScreen.kt
new file mode 100644
index 0000000..035e713
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/HistoryScreen.kt
@@ -0,0 +1,227 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import at.florianschuster.hydro.App
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.Day
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Today
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.model.reachedGoal
+import at.florianschuster.hydro.model.sumOfMilliliters
+import at.florianschuster.hydro.service.HydrationHistoryStore
+import at.florianschuster.hydro.ui.HistoryScreenStore.Companion.LOAD_MORE_THRESHOLD
+import at.florianschuster.hydro.ui.base.HydrationCarousel
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.update
+import kotlinx.datetime.DatePeriod
+import kotlinx.datetime.LocalDate
+import kotlinx.datetime.plus
+
+@Composable
+fun HistoryScreen(
+ contentPadding: PaddingValues,
+ appState: AppState,
+ historyScreenStore: HistoryScreenStore = remember(appState) {
+ HistoryScreenStore(
+ hydrationHistoryStore = App.instance.hydrationHistoryStore
+ )
+ }
+) {
+ Column(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ val state by historyScreenStore.state.collectAsStateWithLifecycle()
+
+ val lazyColumnState = rememberLazyListState()
+ val shouldLoadNext by remember {
+ derivedStateOf {
+ if (!historyScreenStore.state.value.canLoadNext) return@derivedStateOf false
+ val lastVisibleItemPosition = lazyColumnState.layoutInfo.visibleItemsInfo
+ .lastOrNull()
+ ?.index ?: 0
+ val itemCount = lazyColumnState.layoutInfo.totalItemsCount + 1 // loading
+ (lastVisibleItemPosition + LOAD_MORE_THRESHOLD) > itemCount
+ }
+ }
+ LaunchedEffect(shouldLoadNext) {
+ if (shouldLoadNext) {
+ historyScreenStore.loadNext()
+ }
+ }
+ LazyColumn(
+ modifier = Modifier.fillMaxWidth(),
+ contentPadding = contentPadding,
+ state = lazyColumnState,
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ items(state.days, key = Day::id) { day ->
+ DayItem(
+ modifier = Modifier.padding(horizontal = 16.dp),
+ day = day,
+ unit = appState.liquidUnit
+ )
+ }
+ item {
+ if (state.loading) {
+ CircularProgressIndicator(
+ modifier = Modifier.padding(24.dp)
+ )
+ }
+ }
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun HistoryScreenToolbar(
+ containerColor: Color = Color.Transparent,
+ onGoBack: () -> Unit
+) {
+ CenterAlignedTopAppBar(
+ modifier = Modifier
+ .fillMaxWidth(),
+ navigationIcon = {
+ IconButton(
+ onClick = onGoBack,
+ content = {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = "close history"
+ )
+ }
+ )
+ },
+ title = {
+ Text(
+ text = "History",
+ style = MaterialTheme.typography.headlineSmall
+ )
+ },
+ colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
+ containerColor = containerColor
+ )
+ )
+}
+
+@Composable
+private fun DayItem(
+ modifier: Modifier = Modifier,
+ day: Day,
+ unit: LiquidUnit
+) {
+ Card(
+ modifier = modifier,
+ colors = CardDefaults.cardColors(
+ containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.95f)
+ )
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 24.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ Text(
+ modifier = Modifier.padding(horizontal = 24.dp),
+ text = day.date.format(),
+ style = MaterialTheme.typography.labelLarge
+ )
+
+ val milliliters = remember(day) { day.hydration.map { it.milliliters } }
+ HydrationCarousel(
+ contentPadding = PaddingValues(horizontal = 24.dp),
+ milliliterItems = milliliters,
+ selected = milliliters,
+ liquidUnit = unit,
+ contentBelowItem = { index ->
+ Text(
+ text = day.hydration[index].time.format(),
+ style = MaterialTheme.typography.labelMedium
+ )
+ }
+ )
+
+ Text(
+ modifier = Modifier.padding(horizontal = 24.dp),
+ text = day.hydration.sumOfMilliliters().format(unit) +
+ " out of " +
+ day.goal.format(unit) +
+ if (day.reachedGoal()) " 🎉" else "",
+ style = MaterialTheme.typography.labelLarge
+ )
+ }
+ }
+}
+
+class HistoryScreenStore(
+ private val hydrationHistoryStore: HydrationHistoryStore
+) {
+
+ data class State(
+ val days: List = emptyList(),
+ val loading: Boolean = false,
+ val lastQueriedDate: LocalDate = Today + DatePeriod(days = 1),
+ val reachedStart: Boolean = false
+ ) {
+ val canLoadNext = !loading && !reachedStart
+ }
+
+ private val _state = MutableStateFlow(State())
+ val state: StateFlow = _state.asStateFlow()
+
+ suspend fun loadNext() {
+ _state.update { it.copy(loading = true) }
+ val days = hydrationHistoryStore.days(_state.value.lastQueriedDate)
+ _state.update {
+ it.copy(
+ loading = false,
+ days = it.days + days,
+ lastQueriedDate = if (days.isNotEmpty()) days.last().date else it.lastQueriedDate,
+ reachedStart = days.isEmpty()
+ )
+ }
+ }
+
+ companion object {
+ const val LOAD_MORE_THRESHOLD = 10
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/OnboardingScreen.kt b/app/src/main/java/at/florianschuster/hydro/ui/OnboardingScreen.kt
new file mode 100644
index 0000000..d728324
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/OnboardingScreen.kt
@@ -0,0 +1,77 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.NavigateNext
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import at.florianschuster.hydro.AppAction
+import kotlinx.coroutines.delay
+import kotlin.time.Duration.Companion.milliseconds
+
+@Composable
+fun OnboardingScreen(
+ contentPadding: PaddingValues,
+ dispatch: (AppAction) -> Unit,
+ onOnboardingFinished: () -> Unit
+) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(contentPadding)
+ ) {
+ Column(
+ modifier = Modifier.padding(horizontal = 32.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Spacer(modifier = Modifier.fillMaxHeight(0.3f))
+ Text(
+ text = "Welcome to hydro",
+ style = MaterialTheme.typography.headlineMedium,
+ fontWeight = FontWeight.Bold
+ )
+ Text(
+ text = "a simple no-nonsense hydration tracking app",
+ style = MaterialTheme.typography.bodyLarge,
+ fontWeight = FontWeight.Light,
+ textAlign = TextAlign.Center
+ )
+ }
+
+ FloatingActionButton(
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .padding(24.dp),
+ onClick = {
+ dispatch(AppAction.SetOnboardingShown)
+ onOnboardingFinished()
+ },
+ content = {
+ Icon(
+ Icons.Outlined.NavigateNext,
+ contentDescription = "go next"
+ )
+ }
+ )
+ }
+
+ LaunchedEffect(Unit) {
+ delay(500.milliseconds)
+ dispatch(AppAction.SetHydrationForOnboarding)
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/SetIntervalBottomSheet.kt b/app/src/main/java/at/florianschuster/hydro/ui/SetIntervalBottomSheet.kt
new file mode 100644
index 0000000..dbec264
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/SetIntervalBottomSheet.kt
@@ -0,0 +1,48 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.material3.Slider
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.ui.base.BottomSheet
+import kotlin.math.roundToInt
+import kotlin.time.Duration.Companion.minutes
+
+@Composable
+fun SetIntervalBottomSheet(
+ state: AppState,
+ dispatch: (AppAction) -> Unit,
+ onClose: () -> Unit
+) {
+ check(state.reminder != null)
+ BottomSheet(
+ title = "Interval"
+ ) {
+ var value by remember(state.reminder) {
+ mutableStateOf(state.reminder.interval.inWholeMinutes.toFloat())
+ }
+ val intervalValue by remember(value) {
+ derivedStateOf { value.roundToInt().minutes }
+ }
+ Slider(
+ value = value,
+ valueRange = 1f..60f,
+ steps = 58,
+ onValueChange = { minutesValue -> value = minutesValue },
+ onValueChangeFinished = {
+ dispatch(
+ AppAction.SetReminder(state.reminder.copy(interval = intervalValue))
+ )
+ onClose()
+ }
+ )
+ Text(text = intervalValue.format())
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/SetLiquidUnitBottomSheet.kt b/app/src/main/java/at/florianschuster/hydro/ui/SetLiquidUnitBottomSheet.kt
new file mode 100644
index 0000000..afb0778
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/SetLiquidUnitBottomSheet.kt
@@ -0,0 +1,46 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.foundation.clickable
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Check
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.model.formatMoreInfo
+import at.florianschuster.hydro.ui.base.BottomSheet
+import at.florianschuster.hydro.ui.base.HydroListItem
+
+@Composable
+fun SetLiquidUnitBottomSheet(
+ state: AppState,
+ dispatch: (AppAction) -> Unit,
+ onClose: () -> Unit
+) {
+ BottomSheet(
+ title = "Measurement Unit"
+ ) {
+ LiquidUnit.entries.forEach { liquidUnit ->
+ HydroListItem(
+ modifier = Modifier.clickable {
+ dispatch(AppAction.SetLiquidUnit(liquidUnit))
+ onClose()
+ },
+ headlineContent = { Text(text = liquidUnit.format()) },
+ supportingContent = { Text(text = liquidUnit.formatMoreInfo()) },
+ trailingContent = {
+ if (state.liquidUnit == liquidUnit) {
+ Icon(
+ imageVector = Icons.Outlined.Check,
+ contentDescription = "selected"
+ )
+ }
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/SettingsScreen.kt b/app/src/main/java/at/florianschuster/hydro/ui/SettingsScreen.kt
new file mode 100644
index 0000000..7b503f6
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/SettingsScreen.kt
@@ -0,0 +1,568 @@
+package at.florianschuster.hydro.ui
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Close
+import androidx.compose.material.icons.outlined.Delete
+import androidx.compose.material.icons.outlined.Email
+import androidx.compose.material.icons.outlined.Info
+import androidx.compose.material.icons.outlined.InvertColors
+import androidx.compose.material.icons.outlined.Notifications
+import androidx.compose.material.icons.outlined.NotificationsActive
+import androidx.compose.material.icons.outlined.NotificationsOff
+import androidx.compose.material.icons.outlined.RestartAlt
+import androidx.compose.material.icons.outlined.Start
+import androidx.compose.material.icons.outlined.WaterDrop
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Button
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.core.content.ContextCompat
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.R
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.Reminder
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.ui.base.SettingItem
+import at.florianschuster.hydro.ui.base.SettingsSection
+import at.florianschuster.hydro.ui.base.TimePickerDialog
+import at.florianschuster.hydro.ui.base.ToggleSettingItem
+import kotlinx.datetime.LocalTime
+
+@Composable
+fun SettingsScreen(
+ contentPadding: PaddingValues,
+ state: AppState,
+ dispatch: (AppAction) -> Unit,
+ onSetGoalOfTheDay: () -> Unit,
+ onSetLiquidUnit: () -> Unit,
+ onSetTheme: () -> Unit,
+ onShowDeveloperInfo: () -> Unit,
+ onWriteDeveloper: () -> Unit,
+ onSetInterval: () -> Unit
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .verticalScroll(rememberScrollState())
+ ) {
+ SettingsSection(
+ modifier = Modifier
+ .padding(top = contentPadding.calculateTopPadding())
+ .padding(horizontal = 16.dp),
+ title = "Hydration"
+ ) {
+ SettingItem(
+ fieldName = "Daily Goal",
+ value = state.dailyGoal.format(state.liquidUnit),
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.WaterDrop,
+ contentDescription = null
+ )
+ },
+ onClick = onSetGoalOfTheDay
+ )
+ SettingItem(
+ fieldName = "Measurement Unit",
+ value = state.liquidUnit.format(),
+ icon = {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = painterResource(R.drawable.ic_unit),
+ contentDescription = null
+ )
+ },
+ onClick = onSetLiquidUnit
+ )
+ CupCarouselSelection(
+ state = state,
+ dispatch = dispatch
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ ReminderSettingsSection(
+ canScheduleAlarms = state.canScheduleAlarms,
+ reminder = state.reminder,
+ onRemindersChanged = { dispatch(AppAction.SetReminder(it)) },
+ onSetInterval = onSetInterval
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ SettingsSection(
+ modifier = Modifier
+ .padding(horizontal = 16.dp),
+ title = "App"
+ ) {
+ SettingItem(
+ fieldName = "Theme",
+ value = state.theme.format(),
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.InvertColors,
+ contentDescription = null
+ )
+ },
+ onClick = onSetTheme
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ DataSettingsSection(
+ onDeleteAll = { dispatch(AppAction.DeleteAll) }
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ SettingsSection(
+ modifier = Modifier
+ .padding(horizontal = 16.dp)
+ .apply {
+ if (!state.isDebug) {
+ padding(bottom = contentPadding.calculateBottomPadding())
+ }
+ },
+ title = "About"
+ ) {
+ SettingItem(
+ fieldName = "Developer Info",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.Info,
+ contentDescription = null
+ )
+ },
+ onClick = onShowDeveloperInfo
+ )
+ SettingItem(
+ fieldName = "Feedback",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.Email,
+ contentDescription = null
+ )
+ },
+ onClick = onWriteDeveloper
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ if (state.isDebug) {
+ DebugSettingsSection(
+ modifier = Modifier.padding(bottom = contentPadding.calculateBottomPadding()),
+ todayHydration = state.todayHydration,
+ liquidUnit = state.liquidUnit,
+ onResetToday = { dispatch(AppAction.ResetToday) },
+ onShowReminderNotification = {
+ dispatch(AppAction.ShowHydrationReminderNotification(forced = true))
+ }
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun SettingsToolbar(
+ containerColor: Color = Color.Transparent,
+ onGoBack: () -> Unit
+) {
+ CenterAlignedTopAppBar(
+ modifier = Modifier
+ .fillMaxWidth()
+ .statusBarsPadding(),
+ navigationIcon = {
+ IconButton(
+ onClick = onGoBack,
+ content = {
+ Icon(
+ imageVector = Icons.Outlined.Close,
+ contentDescription = "close settings"
+ )
+ }
+ )
+ },
+ title = {
+ Text(
+ text = "Settings",
+ style = MaterialTheme.typography.headlineSmall
+ )
+ },
+ colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
+ containerColor = containerColor
+ )
+ )
+}
+
+@Composable
+private fun ReminderSettingsSection(
+ canScheduleAlarms: Boolean,
+ reminder: Reminder?,
+ onRemindersChanged: (Reminder?) -> Unit,
+ onSetInterval: () -> Unit
+) {
+ var showPermissionRationaleDialog by remember { mutableStateOf(false) }
+ var showScheduleAlarmsDialog by remember { mutableStateOf(false) }
+ val launcher = rememberLauncherForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { granted ->
+ if (!granted) {
+ showPermissionRationaleDialog = true
+ } else if (!canScheduleAlarms) {
+ showScheduleAlarmsDialog = true
+ } else {
+ onRemindersChanged(Reminder.DEFAULT)
+ }
+ }
+ val context = LocalContext.current
+ SettingsSection(
+ modifier = Modifier.padding(horizontal = 16.dp),
+ title = "Reminders"
+ ) {
+ ToggleSettingItem(
+ fieldName = "Enabled",
+ icon = if (reminder != null) {
+ Icons.Outlined.Notifications
+ } else {
+ Icons.Outlined.NotificationsOff
+ },
+ checked = reminder != null,
+ onCheckedChange = { checked ->
+ if (checked) {
+ if (!canScheduleAlarms) {
+ showScheduleAlarmsDialog = true
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ val permission = android.Manifest.permission.POST_NOTIFICATIONS
+ if (!context.isPermissionGranted(permission)) {
+ launcher.launch(permission)
+ } else {
+ onRemindersChanged(Reminder.DEFAULT)
+ }
+ } else {
+ onRemindersChanged(Reminder.DEFAULT)
+ }
+ } else {
+ onRemindersChanged(null)
+ }
+ }
+ )
+ if (reminder != null) {
+ var showStartPicker by remember { mutableStateOf(false) }
+ var showEndPicker by remember { mutableStateOf(false) }
+ var showStartBeforeEndAlert by remember { mutableStateOf(false) }
+ SettingItem(
+ fieldName = "Start",
+ value = reminder.start.format(),
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.Start,
+ contentDescription = null
+ )
+ },
+ onClick = { showStartPicker = true }
+ )
+ SettingItem(
+ fieldName = "End",
+ value = reminder.end.format(),
+ icon = {
+ Icon(
+ modifier = Modifier.scale(scaleX = -1f, scaleY = 1f),
+ imageVector = Icons.Outlined.Start,
+ contentDescription = null
+ )
+ },
+ onClick = { showEndPicker = true }
+ )
+ SettingItem(
+ fieldName = "Interval",
+ value = reminder.interval.format(),
+ icon = {
+ Icon(
+ modifier = Modifier.size(24.dp),
+ painter = painterResource(R.drawable.ic_arrow_range),
+ contentDescription = null
+ )
+ },
+ onClick = onSetInterval
+ )
+ if (showStartPicker) {
+ TimePickerDialog(
+ initialHour = reminder.start.hour,
+ initialMinute = reminder.start.minute,
+ onConfirm = { hour, minute ->
+ showStartPicker = false
+ val start = LocalTime(hour, minute, 0)
+ if (start > reminder.end) {
+ showStartBeforeEndAlert = true
+ } else {
+ onRemindersChanged(reminder.copy(start = start))
+ }
+ },
+ onCancel = { showStartPicker = false }
+ )
+ }
+ if (showEndPicker) {
+ TimePickerDialog(
+ initialHour = reminder.end.hour,
+ initialMinute = reminder.end.minute,
+ onConfirm = { hour, minute ->
+ showEndPicker = false
+ val end = LocalTime(hour, minute, 0)
+ if (reminder.start > end) {
+ showStartBeforeEndAlert = true
+ } else {
+ onRemindersChanged(reminder.copy(end = end))
+ }
+ },
+ onCancel = { showEndPicker = false }
+ )
+ }
+ if (showStartBeforeEndAlert) {
+ StartBeforeEndAlert(
+ onDismiss = { showStartBeforeEndAlert = false }
+ )
+ }
+ }
+ if (showPermissionRationaleDialog) {
+ NotificationPermissionSettingsAlert(
+ onDismiss = { showPermissionRationaleDialog = false }
+ )
+ }
+ if (showScheduleAlarmsDialog) {
+ AlarmSystemSettingsAlert(
+ onDismiss = { showScheduleAlarmsDialog = false }
+ )
+ }
+ }
+}
+
+private fun Context.isPermissionGranted(permission: String): Boolean {
+ return ContextCompat.checkSelfPermission(
+ this,
+ permission
+ ) == PackageManager.PERMISSION_GRANTED
+}
+
+@Composable
+private fun StartBeforeEndAlert(onDismiss: () -> Unit) {
+ AlertDialog(
+ onDismissRequest = { onDismiss() },
+ title = { Text(text = "Time constraints") },
+ text = {
+ Text(
+ text = "Start time of the Reminder must be before the end time."
+ )
+ },
+ confirmButton = {
+ Button(
+ onClick = { onDismiss() },
+ content = { Text(text = "Ok") }
+ )
+ }
+ )
+}
+
+@Composable
+private fun NotificationPermissionSettingsAlert(onDismiss: () -> Unit) {
+ val context = LocalContext.current
+ AlertDialog(
+ onDismissRequest = { onDismiss() },
+ title = { Text(text = "Notification permission denied") },
+ text = {
+ Text(
+ text = "The app is unable to show Reminders " +
+ "without the notification permission."
+ )
+ },
+ confirmButton = {
+ Button(
+ onClick = {
+ context.goToNotificationPermissionSettings()
+ onDismiss()
+ },
+ content = { Text(text = "Go To Settings") }
+ )
+ },
+ dismissButton = {
+ Button(
+ onClick = { onDismiss() },
+ content = { Text(text = "Cancel") }
+ )
+ }
+ )
+}
+
+private fun Context.goToNotificationPermissionSettings() {
+ startActivity(
+ Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
+ data = Uri.parse("package:$packageName")
+ }
+ )
+}
+
+@Composable
+private fun AlarmSystemSettingsAlert(onDismiss: () -> Unit) {
+ val context = LocalContext.current
+ AlertDialog(
+ onDismissRequest = { onDismiss() },
+ title = { Text(text = "Alarm permission denied") },
+ text = {
+ Text(
+ text = "The app is unable to show Reminders " +
+ "without the alarm permission."
+ )
+ },
+ confirmButton = {
+ Button(
+ onClick = {
+ context.goToAlarmSystemSettings()
+ onDismiss()
+ },
+ content = { Text(text = "Go To Settings") }
+ )
+ },
+ dismissButton = {
+ Button(
+ onClick = { onDismiss() },
+ content = { Text(text = "Cancel") }
+ )
+ }
+ )
+}
+
+private fun Context.goToAlarmSystemSettings() {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return
+ startActivity(
+ Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).apply {
+ data = Uri.parse("package:$packageName")
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
+ }
+ )
+}
+
+@Composable
+private fun DataSettingsSection(
+ modifier: Modifier = Modifier,
+ onDeleteAll: () -> Unit
+) {
+ var showDeleteAllDialog by remember { mutableStateOf(false) }
+ SettingsSection(
+ modifier = modifier.padding(horizontal = 16.dp),
+ title = "Data"
+ ) {
+ SettingItem(
+ fieldName = "Delete all stored data",
+ value = "This includes all settings and the complete hydration history",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.Delete,
+ contentDescription = null
+ )
+ },
+ onClick = { showDeleteAllDialog = true }
+ )
+ }
+ if (showDeleteAllDialog) {
+ AlertDialog(
+ onDismissRequest = { showDeleteAllDialog = false },
+ title = { Text(text = "Are you sure?") },
+ text = { Text(text = "This cannot be reversed.") },
+ confirmButton = {
+ Button(
+ onClick = {
+ showDeleteAllDialog = false
+ onDeleteAll()
+ },
+ content = { Text(text = "Yes") }
+ )
+ },
+ dismissButton = {
+ Button(
+ onClick = { showDeleteAllDialog = false },
+ content = { Text(text = "Cancel") }
+ )
+ }
+ )
+ }
+}
+
+@Composable
+private fun DebugSettingsSection(
+ modifier: Modifier = Modifier,
+ todayHydration: Milliliters,
+ liquidUnit: LiquidUnit,
+ onResetToday: () -> Unit,
+ onShowReminderNotification: () -> Unit
+) {
+ SettingsSection(
+ modifier = modifier.padding(horizontal = 16.dp),
+ title = "Debug"
+ ) {
+ SettingItem(
+ fieldName = "Reset hydration today",
+ value = "This sets today's hydration from ${todayHydration.format(liquidUnit)} " +
+ "to ${Milliliters.ZERO.format(liquidUnit)}",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.RestartAlt,
+ contentDescription = null
+ )
+ },
+ onClick = onResetToday
+ )
+
+ SettingItem(
+ fieldName = "Show Reminder Notification",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.NotificationsActive,
+ contentDescription = null
+ )
+ },
+ onClick = onShowReminderNotification
+ )
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/ThemeBottomSheet.kt b/app/src/main/java/at/florianschuster/hydro/ui/ThemeBottomSheet.kt
new file mode 100644
index 0000000..62de914
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/ThemeBottomSheet.kt
@@ -0,0 +1,65 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Check
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.model.Theme
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.model.icon
+import at.florianschuster.hydro.ui.base.BottomSheet
+import at.florianschuster.hydro.ui.base.HydroListItem
+
+@Composable
+fun ThemeBottomSheet(
+ state: AppState,
+ dispatch: (AppAction) -> Unit,
+ onClose: () -> Unit
+) {
+ BottomSheet(
+ title = "Theme"
+ ) {
+ Theme.entries.forEach { theme ->
+ HydroListItem(
+ modifier = Modifier.clickable {
+ dispatch(AppAction.SetTheme(theme))
+ onClose()
+ },
+ headlineContent = { Text(text = theme.format()) },
+ supportingContent = {
+ if (theme == Theme.System) {
+ Text(
+ text = "Current system theme is " +
+ "${if (isSystemInDarkTheme()) "dark" else "light"}."
+ )
+ }
+ if (theme == Theme.Dynamic) {
+ Text(
+ text = "Uses your phone's wallpaper to determine colors."
+ )
+ }
+ },
+ leadingContent = {
+ Icon(
+ imageVector = theme.icon(),
+ contentDescription = "system theme"
+ )
+ },
+ trailingContent = {
+ if (state.theme == theme) {
+ Icon(
+ imageVector = Icons.Outlined.Check,
+ contentDescription = "selected"
+ )
+ }
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/TodayScreen.kt b/app/src/main/java/at/florianschuster/hydro/ui/TodayScreen.kt
new file mode 100644
index 0000000..8027092
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/TodayScreen.kt
@@ -0,0 +1,140 @@
+package at.florianschuster.hydro.ui
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.QueryStats
+import androidx.compose.material.icons.outlined.Settings
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FloatingActionButton
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import at.florianschuster.hydro.AppAction
+import at.florianschuster.hydro.AppState
+import at.florianschuster.hydro.R
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.model.icon
+import com.airbnb.lottie.compose.LottieAnimation
+import com.airbnb.lottie.compose.LottieCompositionSpec
+import com.airbnb.lottie.compose.rememberLottieComposition
+
+@Composable
+internal fun TodayScreen(
+ contentPadding: PaddingValues,
+ state: AppState,
+ dispatch: (AppAction) -> Unit
+) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(contentPadding)
+ ) {
+ Column(
+ modifier = Modifier.align(Alignment.Center),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ AnimatedVisibility(visible = state.dailyGoalReached) {
+ LottieAnimation(
+ modifier = Modifier.size(148.dp),
+ composition = rememberLottieComposition(
+ // https://lottiefiles.com/animations/trophy-yEGPe40FVr
+ spec = LottieCompositionSpec.RawRes(R.raw.winner)
+ ).value
+ )
+ }
+ Text(
+ text = state.todayHydration.format(state.liquidUnit),
+ style = MaterialTheme.typography.displayLarge
+ )
+ Text(
+ text = state.hydrationProgress.format(),
+ style = MaterialTheme.typography.titleMedium
+ )
+ }
+
+ Row(
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .padding(24.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ state.selectedCups.forEach { cup ->
+ FloatingActionButton(
+ onClick = { dispatch(AppAction.AddHydration(cup.milliliters)) },
+ content = {
+ Column(horizontalAlignment = Alignment.CenterHorizontally) {
+ Icon(
+ modifier = Modifier.size(20.dp),
+ painter = cup.milliliters.icon(),
+ contentDescription = "add one cup"
+ )
+ Text(
+ text = cup.milliliters.format(state.liquidUnit),
+ style = MaterialTheme.typography.labelSmall
+ )
+ }
+ }
+ )
+ }
+ }
+ }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun TodayToolbar(
+ containerColor: Color = Color.Transparent,
+ isDebug: Boolean,
+ onGoToHistory: () -> Unit,
+ onGoToSettings: () -> Unit
+) {
+ CenterAlignedTopAppBar(
+ modifier = Modifier
+ .fillMaxWidth()
+ .statusBarsPadding(),
+ actions = {
+ if (isDebug) {
+ IconButton(
+ onClick = onGoToHistory,
+ content = {
+ Icon(
+ imageVector = Icons.Outlined.QueryStats,
+ contentDescription = "go to history"
+ )
+ }
+ )
+ }
+ IconButton(
+ onClick = onGoToSettings,
+ content = {
+ Icon(
+ imageVector = Icons.Outlined.Settings,
+ contentDescription = "go to settings"
+ )
+ }
+ )
+ },
+ title = {},
+ colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
+ containerColor = containerColor
+ )
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/BottomSheet.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/BottomSheet.kt
new file mode 100644
index 0000000..30486e4
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/BottomSheet.kt
@@ -0,0 +1,66 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBarsPadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CornerSize
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun BottomSheet(
+ title: String,
+ content: @Composable ColumnScope.() -> Unit
+) {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth(),
+ shape = MaterialTheme.shapes.extraLarge.copy(
+ bottomStart = CornerSize(0.dp),
+ bottomEnd = CornerSize(0.dp)
+ ),
+ colors = CardDefaults.cardColors(
+ MaterialTheme.colorScheme.primaryContainer
+ )
+ ) {
+ Column(
+ modifier = Modifier
+ .padding(horizontal = 24.dp)
+ .padding(bottom = 24.dp)
+ .navigationBarsPadding(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Spacer(modifier = Modifier.height(12.dp))
+ Spacer(
+ modifier = Modifier
+ .size(width = 50.dp, height = 4.dp)
+ .clip(MaterialTheme.shapes.medium)
+ .background(MaterialTheme.colorScheme.onSurface)
+ )
+ Spacer(modifier = Modifier.height(24.dp))
+
+ Text(
+ text = title,
+ style = MaterialTheme.typography.headlineMedium,
+ color = MaterialTheme.colorScheme.primary
+ )
+
+ Spacer(modifier = Modifier.height(32.dp))
+
+ content()
+ }
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationBackground.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationBackground.kt
new file mode 100644
index 0000000..4e1a433
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationBackground.kt
@@ -0,0 +1,46 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import at.florianschuster.hydro.R
+import at.florianschuster.hydro.model.Percent
+import com.airbnb.lottie.compose.LottieAnimation
+import com.airbnb.lottie.compose.LottieClipSpec
+import com.airbnb.lottie.compose.LottieCompositionSpec
+import com.airbnb.lottie.compose.rememberLottieComposition
+
+@Composable
+internal fun HydrationBackground(
+ modifier: Modifier = Modifier,
+ isSystemInDarkTheme: Boolean,
+ hydrationProgress: Percent
+) {
+ val composition by rememberLottieComposition(
+ LottieCompositionSpec.RawRes(
+ // https://lottiefiles.com/animations/water-fills-square-progress-bar-mGPK3uyxIP
+ if (isSystemInDarkTheme) R.raw.water_dark else R.raw.water_light
+ )
+ )
+ val clipSpec by remember(hydrationProgress) {
+ // 196 == last frame we want to show
+ val maximumFrame = (minOf(1.0f, hydrationProgress.value) * 210).toInt()
+ mutableStateOf(
+ LottieClipSpec.Frame(
+ min = 0,
+ // if max frame = 0 we glitch, so we set it to 1
+ max = maxOf(maximumFrame, 1)
+ )
+ )
+ }
+ LottieAnimation(
+ modifier = modifier.fillMaxSize(),
+ composition = composition,
+ clipSpec = clipSpec,
+ contentScale = ContentScale.FillBounds
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationCarousel.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationCarousel.kt
new file mode 100644
index 0000000..fbf2d1a
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/HydrationCarousel.kt
@@ -0,0 +1,105 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.material3.Text
+import androidx.compose.material3.surfaceColorAtElevation
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.unit.dp
+import at.florianschuster.hydro.model.LiquidUnit
+import at.florianschuster.hydro.model.Milliliters
+import at.florianschuster.hydro.model.format
+import at.florianschuster.hydro.model.icon
+
+@Composable
+fun HydrationCarousel(
+ modifier: Modifier = Modifier,
+ contentPadding: PaddingValues = PaddingValues(0.dp),
+ milliliterItems: List,
+ liquidUnit: LiquidUnit,
+ selected: List = emptyList(),
+ onClick: (index: Int, Milliliters) -> Unit = { _, _ -> },
+ contentBelowItem: @Composable (index: Int) -> Unit = {}
+) {
+ LazyRow(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ contentPadding = contentPadding
+ ) {
+ itemsIndexed(items = milliliterItems) { index, item ->
+ CupItem(
+ item = item,
+ index = index,
+ liquidUnit = liquidUnit,
+ selected = item in selected,
+ onClick = onClick,
+ contentBelowItem = contentBelowItem
+ )
+ }
+ }
+}
+
+@Composable
+private fun CupItem(
+ modifier: Modifier = Modifier,
+ item: Milliliters,
+ index: Int,
+ liquidUnit: LiquidUnit,
+ selected: Boolean,
+ onClick: (index: Int, Milliliters) -> Unit,
+ contentBelowItem: @Composable (index: Int) -> Unit
+) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ OutlinedCard(
+ modifier = modifier,
+ colors = CardDefaults.outlinedCardColors(
+ containerColor = if (selected) {
+ MaterialTheme.colorScheme.surfaceColorAtElevation(24.dp)
+ } else {
+ MaterialTheme.colorScheme.surface
+ }
+ ),
+ border = if (selected) {
+ CardDefaults
+ .outlinedCardBorder()
+ .copy(brush = SolidColor(MaterialTheme.colorScheme.primary))
+ } else {
+ CardDefaults.outlinedCardBorder(false)
+ }
+ ) {
+ Column(
+ modifier = Modifier
+ .clickable { onClick(index, item) }
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Icon(
+ modifier = Modifier.size(28.dp),
+ painter = item.icon(),
+ contentDescription = null
+ )
+ Text(
+ text = item.format(liquidUnit),
+ style = MaterialTheme.typography.labelLarge
+ )
+ }
+ }
+
+ contentBelowItem(index)
+ }
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/HydroListItem.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/HydroListItem.kt
new file mode 100644
index 0000000..56268f1
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/HydroListItem.kt
@@ -0,0 +1,27 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.ListItemDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+
+@Composable
+internal fun HydroListItem(
+ modifier: Modifier = Modifier,
+ headlineContent: @Composable () -> Unit,
+ overlineContent: @Composable (() -> Unit)? = null,
+ leadingContent: @Composable (() -> Unit)? = null,
+ trailingContent: @Composable (() -> Unit)? = null,
+ supportingContent: @Composable (() -> Unit)? = null
+) {
+ ListItem(
+ modifier = modifier,
+ colors = ListItemDefaults.colors(containerColor = Color.Transparent),
+ overlineContent = overlineContent,
+ headlineContent = headlineContent,
+ leadingContent = leadingContent,
+ trailingContent = trailingContent,
+ supportingContent = supportingContent
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/HydroTheme.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/HydroTheme.kt
new file mode 100644
index 0000000..a9e0ad5
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/HydroTheme.kt
@@ -0,0 +1,216 @@
+@file:Suppress("SpellCheckingInspection", "PrivatePropertyName")
+
+package at.florianschuster.hydro.ui.base
+
+import android.app.Activity
+import android.os.Build
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.dynamicDarkColorScheme
+import androidx.compose.material3.dynamicLightColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.core.view.WindowCompat
+import at.florianschuster.hydro.R
+
+private val md_theme_light_primary = Color(0xFF006683)
+private val md_theme_light_onPrimary = Color(0xFFFFFFFF)
+private val md_theme_light_primaryContainer = Color(0xFFBDE9FF)
+private val md_theme_light_onPrimaryContainer = Color(0xFF001F2A)
+private val md_theme_light_secondary = Color(0xFF006689)
+private val md_theme_light_onSecondary = Color(0xFFFFFFFF)
+private val md_theme_light_secondaryContainer = Color(0xFFC3E8FF)
+private val md_theme_light_onSecondaryContainer = Color(0xFF001E2C)
+private val md_theme_light_tertiary = Color(0xFF00629F)
+private val md_theme_light_onTertiary = Color(0xFFFFFFFF)
+private val md_theme_light_tertiaryContainer = Color(0xFFD0E4FF)
+private val md_theme_light_onTertiaryContainer = Color(0xFF001D34)
+private val md_theme_light_error = Color(0xFFBA1A1A)
+private val md_theme_light_errorContainer = Color(0xFFFFDAD6)
+private val md_theme_light_onError = Color(0xFFFFFFFF)
+private val md_theme_light_onErrorContainer = Color(0xFF410002)
+private val md_theme_light_background = Color(0xFFFAFCFF)
+private val md_theme_light_onBackground = Color(0xFF001F2A)
+private val md_theme_light_surface = Color(0xFFFAFCFF)
+private val md_theme_light_onSurface = Color(0xFF001F2A)
+private val md_theme_light_surfaceVariant = Color(0xFFDCE4E9)
+private val md_theme_light_onSurfaceVariant = Color(0xFF40484C)
+private val md_theme_light_outline = Color(0xFF70787D)
+private val md_theme_light_inverseOnSurface = Color(0xFFE1F4FF)
+private val md_theme_light_inverseSurface = Color(0xFF003547)
+private val md_theme_light_inversePrimary = Color(0xFF65D3FF)
+private val md_theme_light_shadow = Color(0xFF000000)
+private val md_theme_light_surfaceTint = Color(0xFF006683)
+private val md_theme_light_outlineVariant = Color(0xFFC0C8CD)
+private val md_theme_light_scrim = Color(0xFF000000)
+
+private val md_theme_dark_primary = Color(0xFF65D3FF)
+private val md_theme_dark_onPrimary = Color(0xFF003546)
+private val md_theme_dark_primaryContainer = Color(0xFF004D64)
+private val md_theme_dark_onPrimaryContainer = Color(0xFFBDE9FF)
+private val md_theme_dark_secondary = Color(0xFF7AD1FF)
+private val md_theme_dark_onSecondary = Color(0xFF003549)
+private val md_theme_dark_secondaryContainer = Color(0xFF004C68)
+private val md_theme_dark_onSecondaryContainer = Color(0xFFC3E8FF)
+private val md_theme_dark_tertiary = Color(0xFF9BCBFF)
+private val md_theme_dark_onTertiary = Color(0xFF003256)
+private val md_theme_dark_tertiaryContainer = Color(0xFF004A79)
+private val md_theme_dark_onTertiaryContainer = Color(0xFFD0E4FF)
+private val md_theme_dark_error = Color(0xFFFFB4AB)
+private val md_theme_dark_errorContainer = Color(0xFF93000A)
+private val md_theme_dark_onError = Color(0xFF690005)
+private val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
+private val md_theme_dark_background = Color(0xFF001F2A)
+private val md_theme_dark_onBackground = Color(0xFFBFE9FF)
+private val md_theme_dark_surface = Color(0xFF001F2A)
+private val md_theme_dark_onSurface = Color(0xFFBFE9FF)
+private val md_theme_dark_surfaceVariant = Color(0xFF40484C)
+private val md_theme_dark_onSurfaceVariant = Color(0xFFC0C8CD)
+private val md_theme_dark_outline = Color(0xFF8A9297)
+private val md_theme_dark_inverseOnSurface = Color(0xFF001F2A)
+private val md_theme_dark_inverseSurface = Color(0xFFBFE9FF)
+private val md_theme_dark_inversePrimary = Color(0xFF006683)
+private val md_theme_dark_shadow = Color(0xFF000000)
+private val md_theme_dark_surfaceTint = Color(0xFF65D3FF)
+private val md_theme_dark_outlineVariant = Color(0xFF40484C)
+private val md_theme_dark_scrim = Color(0xFF000000)
+
+private val seed = Color(0xFFBBE5FA)
+
+private val LightColors = lightColorScheme(
+ primary = md_theme_light_primary,
+ onPrimary = md_theme_light_onPrimary,
+ primaryContainer = md_theme_light_primaryContainer,
+ onPrimaryContainer = md_theme_light_onPrimaryContainer,
+ secondary = md_theme_light_secondary,
+ onSecondary = md_theme_light_onSecondary,
+ secondaryContainer = md_theme_light_secondaryContainer,
+ onSecondaryContainer = md_theme_light_onSecondaryContainer,
+ tertiary = md_theme_light_tertiary,
+ onTertiary = md_theme_light_onTertiary,
+ tertiaryContainer = md_theme_light_tertiaryContainer,
+ onTertiaryContainer = md_theme_light_onTertiaryContainer,
+ error = md_theme_light_error,
+ errorContainer = md_theme_light_errorContainer,
+ onError = md_theme_light_onError,
+ onErrorContainer = md_theme_light_onErrorContainer,
+ background = md_theme_light_background,
+ onBackground = md_theme_light_onBackground,
+ surface = md_theme_light_surface,
+ onSurface = md_theme_light_onSurface,
+ surfaceVariant = md_theme_light_surfaceVariant,
+ onSurfaceVariant = md_theme_light_onSurfaceVariant,
+ outline = md_theme_light_outline,
+ inverseOnSurface = md_theme_light_inverseOnSurface,
+ inverseSurface = md_theme_light_inverseSurface,
+ inversePrimary = md_theme_light_inversePrimary,
+ surfaceTint = md_theme_light_surfaceTint,
+ outlineVariant = md_theme_light_outlineVariant,
+ scrim = md_theme_light_scrim
+)
+
+private val DarkColors = darkColorScheme(
+ primary = md_theme_dark_primary,
+ onPrimary = md_theme_dark_onPrimary,
+ primaryContainer = md_theme_dark_primaryContainer,
+ onPrimaryContainer = md_theme_dark_onPrimaryContainer,
+ secondary = md_theme_dark_secondary,
+ onSecondary = md_theme_dark_onSecondary,
+ secondaryContainer = md_theme_dark_secondaryContainer,
+ onSecondaryContainer = md_theme_dark_onSecondaryContainer,
+ tertiary = md_theme_dark_tertiary,
+ onTertiary = md_theme_dark_onTertiary,
+ tertiaryContainer = md_theme_dark_tertiaryContainer,
+ onTertiaryContainer = md_theme_dark_onTertiaryContainer,
+ error = md_theme_dark_error,
+ errorContainer = md_theme_dark_errorContainer,
+ onError = md_theme_dark_onError,
+ onErrorContainer = md_theme_dark_onErrorContainer,
+ background = md_theme_dark_background,
+ onBackground = md_theme_dark_onBackground,
+ surface = md_theme_dark_surface,
+ onSurface = md_theme_dark_onSurface,
+ surfaceVariant = md_theme_dark_surfaceVariant,
+ onSurfaceVariant = md_theme_dark_onSurfaceVariant,
+ outline = md_theme_dark_outline,
+ inverseOnSurface = md_theme_dark_inverseOnSurface,
+ inverseSurface = md_theme_dark_inverseSurface,
+ inversePrimary = md_theme_dark_inversePrimary,
+ surfaceTint = md_theme_dark_surfaceTint,
+ outlineVariant = md_theme_dark_outlineVariant,
+ scrim = md_theme_dark_scrim
+)
+
+private val NotoSansFontFamily = FontFamily(
+ Font(R.font.notosans_black, FontWeight.Black),
+ Font(R.font.notosans_bold, FontWeight.Bold),
+ Font(R.font.notosans_extrabold, FontWeight.ExtraBold),
+ Font(R.font.notosans_extralight, FontWeight.ExtraLight),
+ Font(R.font.notosans_light, FontWeight.Light),
+ Font(R.font.notosans_medium, FontWeight.Medium),
+ Font(R.font.notosans_regular, FontWeight.Normal),
+ Font(R.font.notosans_semibold, FontWeight.SemiBold),
+ Font(R.font.notosans_thin, FontWeight.Thin)
+)
+
+// Set of Material typography styles to start with
+private val typography = with(Typography()) {
+ copy(
+ displayLarge = displayLarge.copy(fontFamily = NotoSansFontFamily),
+ displayMedium = displayMedium.copy(fontFamily = NotoSansFontFamily),
+ displaySmall = displaySmall.copy(fontFamily = NotoSansFontFamily),
+ headlineLarge = headlineLarge.copy(fontFamily = NotoSansFontFamily),
+ headlineMedium = headlineMedium.copy(fontFamily = NotoSansFontFamily),
+ headlineSmall = headlineSmall.copy(fontFamily = NotoSansFontFamily),
+ titleLarge = titleLarge.copy(fontFamily = NotoSansFontFamily),
+ titleMedium = titleMedium.copy(fontFamily = NotoSansFontFamily),
+ titleSmall = titleSmall.copy(fontFamily = NotoSansFontFamily),
+ bodyLarge = bodyLarge.copy(fontFamily = NotoSansFontFamily),
+ bodyMedium = bodyMedium.copy(fontFamily = NotoSansFontFamily),
+ bodySmall = bodySmall.copy(fontFamily = NotoSansFontFamily),
+ labelLarge = labelLarge.copy(fontFamily = NotoSansFontFamily),
+ labelMedium = labelMedium.copy(fontFamily = NotoSansFontFamily),
+ labelSmall = labelSmall.copy(fontFamily = NotoSansFontFamily)
+ )
+}
+
+@Composable
+fun HydroTheme(
+ darkTheme: Boolean,
+ dynamicColor: Boolean,
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ val context = LocalContext.current
+ if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ }
+
+ darkTheme -> DarkColors
+ else -> LightColors
+ }
+ val view = LocalView.current
+ if (!view.isInEditMode) {
+ SideEffect {
+ val window = (view.context as Activity).window
+ with(WindowCompat.getInsetsController(window, view)) {
+ isAppearanceLightStatusBars = !darkTheme
+ isAppearanceLightNavigationBars = !darkTheme
+ }
+ }
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = typography,
+ content = content
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/Settings.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/Settings.kt
new file mode 100644
index 0000000..fa34ec9
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/Settings.kt
@@ -0,0 +1,109 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Switch
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.dp
+
+@Composable
+fun SettingsSection(
+ modifier: Modifier = Modifier,
+ title: String? = null,
+ content: @Composable ColumnScope.() -> Unit
+) {
+ Card(
+ modifier = modifier,
+ colors = CardDefaults.cardColors(
+ containerColor = MaterialTheme.colorScheme.primaryContainer.copy(alpha = 0.95f)
+ )
+ ) {
+ Column(
+ modifier = Modifier.padding(vertical = 20.dp),
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ if (title != null) {
+ SettingTitle(
+ modifier = Modifier.padding(horizontal = 24.dp),
+ name = title
+ )
+ }
+ content()
+ }
+ }
+}
+
+@Composable
+private fun SettingTitle(
+ modifier: Modifier = Modifier,
+ name: String
+) {
+ Text(
+ modifier = modifier,
+ text = name,
+ style = MaterialTheme.typography.titleLarge
+ )
+}
+
+@Composable
+fun SettingItem(
+ modifier: Modifier = Modifier,
+ icon: @Composable () -> Unit,
+ fieldName: String,
+ value: String? = null,
+ onClick: () -> Unit
+) {
+ HydroListItem(
+ modifier = modifier
+ .clickable(onClick = onClick)
+ .padding(horizontal = 20.dp),
+ headlineContent = {
+ Text(text = fieldName, style = MaterialTheme.typography.titleSmall)
+ },
+ supportingContent = {
+ if (value != null) {
+ Text(
+ text = value,
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.primary
+ )
+ }
+ },
+ leadingContent = { icon() }
+ )
+}
+
+@Composable
+fun ToggleSettingItem(
+ modifier: Modifier = Modifier,
+ icon: ImageVector,
+ fieldName: String,
+ checked: Boolean,
+ onCheckedChange: (Boolean) -> Unit
+) {
+ HydroListItem(
+ modifier = modifier.padding(horizontal = 20.dp),
+ headlineContent = {
+ Text(text = fieldName, style = MaterialTheme.typography.titleSmall)
+ },
+ leadingContent = {
+ Icon(
+ imageVector = icon,
+ contentDescription = "set $fieldName"
+ )
+ },
+ trailingContent = {
+ Switch(checked = checked, onCheckedChange = onCheckedChange)
+ }
+ )
+}
diff --git a/app/src/main/java/at/florianschuster/hydro/ui/base/TimePickerDialog.kt b/app/src/main/java/at/florianschuster/hydro/ui/base/TimePickerDialog.kt
new file mode 100644
index 0000000..710b8a9
--- /dev/null
+++ b/app/src/main/java/at/florianschuster/hydro/ui/base/TimePickerDialog.kt
@@ -0,0 +1,85 @@
+package at.florianschuster.hydro.ui.base
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.IntrinsicSize
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
+import androidx.compose.material3.TimePicker
+import androidx.compose.material3.rememberTimePickerState
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.compose.ui.window.DialogProperties
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun TimePickerDialog(
+ title: String = "Select Time",
+ initialHour: Int = 0,
+ initialMinute: Int = 0,
+ onConfirm: (hour: Int, minute: Int) -> Unit,
+ onCancel: () -> Unit = {}
+) {
+ val state = rememberTimePickerState(
+ initialHour = initialHour,
+ initialMinute = initialMinute
+ )
+ Dialog(
+ onDismissRequest = onCancel,
+ properties = DialogProperties(
+ usePlatformDefaultWidth = false
+ )
+ ) {
+ Surface(
+ shape = MaterialTheme.shapes.extraLarge,
+ tonalElevation = 6.dp,
+ modifier = Modifier
+ .width(IntrinsicSize.Min)
+ .height(IntrinsicSize.Min)
+ .background(
+ shape = MaterialTheme.shapes.extraLarge,
+ color = MaterialTheme.colorScheme.surface
+ )
+ ) {
+ Column(
+ modifier = Modifier.padding(24.dp),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(bottom = 20.dp),
+ text = title,
+ style = MaterialTheme.typography.labelMedium
+ )
+
+ TimePicker(state = state)
+ Row(
+ modifier = Modifier
+ .height(40.dp)
+ .fillMaxWidth()
+ ) {
+ Spacer(modifier = Modifier.weight(1f))
+ TextButton(
+ onClick = onCancel
+ ) { Text("Cancel") }
+ TextButton(
+ onClick = { onConfirm(state.hour, state.minute) }
+ ) { Text("OK") }
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/brand_image.webp b/app/src/main/res/drawable/brand_image.webp
new file mode 100644
index 0000000..cdaaa8b
Binary files /dev/null and b/app/src/main/res/drawable/brand_image.webp differ
diff --git a/app/src/main/res/drawable/ic_arrow_range.xml b/app/src/main/res/drawable/ic_arrow_range.xml
new file mode 100644
index 0000000..fae2313
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_range.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_notification.xml b/app/src/main/res/drawable/ic_notification.xml
new file mode 100644
index 0000000..93d3dde
--- /dev/null
+++ b/app/src/main/res/drawable/ic_notification.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_unit.xml b/app/src/main/res/drawable/ic_unit.xml
new file mode 100644
index 0000000..52b53b5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_unit.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_water_bottle.xml b/app/src/main/res/drawable/ic_water_bottle.xml
new file mode 100644
index 0000000..df8d568
--- /dev/null
+++ b/app/src/main/res/drawable/ic_water_bottle.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_water_bottle_large.xml b/app/src/main/res/drawable/ic_water_bottle_large.xml
new file mode 100644
index 0000000..0a3f9e1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_water_bottle_large.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_water_full.xml b/app/src/main/res/drawable/ic_water_full.xml
new file mode 100644
index 0000000..908a6df
--- /dev/null
+++ b/app/src/main/res/drawable/ic_water_full.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_water_less.xml b/app/src/main/res/drawable/ic_water_less.xml
new file mode 100644
index 0000000..a044efb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_water_less.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_water_medium.xml b/app/src/main/res/drawable/ic_water_medium.xml
new file mode 100644
index 0000000..f3f5578
--- /dev/null
+++ b/app/src/main/res/drawable/ic_water_medium.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/font/notosans_black.ttf b/app/src/main/res/font/notosans_black.ttf
new file mode 100644
index 0000000..05771e5
Binary files /dev/null and b/app/src/main/res/font/notosans_black.ttf differ
diff --git a/app/src/main/res/font/notosans_bold.ttf b/app/src/main/res/font/notosans_bold.ttf
new file mode 100644
index 0000000..0d19068
Binary files /dev/null and b/app/src/main/res/font/notosans_bold.ttf differ
diff --git a/app/src/main/res/font/notosans_extrabold.ttf b/app/src/main/res/font/notosans_extrabold.ttf
new file mode 100644
index 0000000..a74c69a
Binary files /dev/null and b/app/src/main/res/font/notosans_extrabold.ttf differ
diff --git a/app/src/main/res/font/notosans_extralight.ttf b/app/src/main/res/font/notosans_extralight.ttf
new file mode 100644
index 0000000..13c4bbc
Binary files /dev/null and b/app/src/main/res/font/notosans_extralight.ttf differ
diff --git a/app/src/main/res/font/notosans_light.ttf b/app/src/main/res/font/notosans_light.ttf
new file mode 100644
index 0000000..8fde662
Binary files /dev/null and b/app/src/main/res/font/notosans_light.ttf differ
diff --git a/app/src/main/res/font/notosans_medium.ttf b/app/src/main/res/font/notosans_medium.ttf
new file mode 100644
index 0000000..faf167c
Binary files /dev/null and b/app/src/main/res/font/notosans_medium.ttf differ
diff --git a/app/src/main/res/font/notosans_regular.ttf b/app/src/main/res/font/notosans_regular.ttf
new file mode 100644
index 0000000..7552fbe
Binary files /dev/null and b/app/src/main/res/font/notosans_regular.ttf differ
diff --git a/app/src/main/res/font/notosans_semibold.ttf b/app/src/main/res/font/notosans_semibold.ttf
new file mode 100644
index 0000000..b460754
Binary files /dev/null and b/app/src/main/res/font/notosans_semibold.ttf differ
diff --git a/app/src/main/res/font/notosans_thin.ttf b/app/src/main/res/font/notosans_thin.ttf
new file mode 100644
index 0000000..b5af044
Binary files /dev/null and b/app/src/main/res/font/notosans_thin.ttf differ
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..c9ad5f9
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..37534d7
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..0ba583e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..79bf8b2
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..44166d2
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..6e7df2c
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/raw/water_dark.json b/app/src/main/res/raw/water_dark.json
new file mode 100644
index 0000000..1aae39d
--- /dev/null
+++ b/app/src/main/res/raw/water_dark.json
@@ -0,0 +1 @@
+{"nm":"MC","ddd":0,"h":1080,"w":1080,"meta":{"g":"@lottiefiles/toolkit-js 0.26.1"},"layers":[{"ty":0,"nm":"Wave Animation","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[540,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_0","ind":1}],"v":"5.7.3","fr":60,"op":301,"ip":32,"assets":[{"nm":"","id":"comp_0","layers":[{"ty":3,"nm":"Null 1","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[960,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":0,"ix":11}},"ef":[],"ind":1},{"ty":0,"nm":"wave02","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_1","ind":2},{"ty":0,"nm":"wave04","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[{"ty":0,"mn":"ADBE Ramp","nm":"Gradient Ramp","ix":1,"en":1,"ef":[{"ty":3,"mn":"ADBE Ramp-0001","nm":"Start of Ramp","ix":1,"v":{"a":0,"k":[960,0],"ix":1}},{"ty":2,"mn":"ADBE Ramp-0002","nm":"Start Color","ix":2,"v":{"a":0,"k":[0.8706,0.5725,0.1294],"ix":2}},{"ty":3,"mn":"ADBE Ramp-0003","nm":"End of Ramp","ix":3,"v":{"a":0,"k":[960,1080],"ix":3}},{"ty":2,"mn":"ADBE Ramp-0004","nm":"End Color","ix":4,"v":{"a":0,"k":[1,0.8824,0.7059],"ix":4}},{"ty":7,"mn":"ADBE Ramp-0005","nm":"Ramp Shape","ix":5,"v":{"a":0,"k":1,"ix":5}},{"ty":0,"mn":"ADBE Ramp-0006","nm":"Ramp Scatter","ix":6,"v":{"a":0,"k":0,"ix":6}},{"ty":0,"mn":"ADBE Ramp-0007","nm":"Blend With Original","ix":7,"v":{"a":0,"k":0,"ix":7}},{"ty":6,"mn":"ADBE Ramp-0008","nm":"","ix":8,"v":0}]}],"w":1920,"h":1080,"refId":"comp_2","ind":3},{"ty":0,"nm":"wave03","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_3","ind":4},{"ty":1,"nm":"bg","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[960,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"sc":"#000000","sh":1080,"sw":1920,"ind":5}]},{"nm":"","id":"comp_1","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[181,181,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,705.07,0],"t":0,"ti":[-1752,40,0],"to":[1752,-40,0]},{"s":[7402.4,465.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-386.024,2.075],[-387.882,-60.547],[-561.726,14.756],[-439.996,11.5],[-654.107,25.214],[-426.676,-4.654]],"o":[[0,0],[0,0],[0,0],[0,0],[231.29,-12.079],[720.469,-3.872],[287.741,44.916],[513.957,-13.501],[196.864,-5.145],[474.188,-18.279],[312.228,3.406]],"v":[[3122.657,-403.154],[3032.719,342.805],[-4858.624,366.136],[-4890.188,-284.814],[-4484.46,-263.518],[-3532.053,-171.856],[-2202.288,-282.386],[-1005.658,-163.965],[156.221,-295.452],[1307.92,-312.023],[2380.712,-276.665]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.3411764705882353,0.8901960784313725,1,0.495,0.21176470588235294,0.48627450980392156,0.7294117647058823,0.99,0.17254901960784313,0.6784313725490196,0.9607843137254902],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-11.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]},{"nm":"","id":"comp_2","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,665.07,0],"t":0,"ti":[-1512,13.333,0],"to":[1512,-13.333,0]},{"s":[5962.4,585.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-514.373,15.366],[-276.818,-2.951],[-356.676,20.338],[-192.117,-4.298],[-435.317,65.022],[-444.201,36.5],[-421.576,-65.955]],"o":[[0,0],[0,0],[0,0],[0,0],[119.969,-6.265],[147.306,-4.4],[308.969,3.294],[316.551,-18.05],[514.005,11.5],[641.417,-95.807],[472.947,-38.862],[778.87,121.852]],"v":[[3191.299,-483.627],[3032.719,342.805],[-4858.624,366.136],[-4888.624,-488.364],[-4895.032,-465.76],[-3631.042,-236.271],[-2730.72,-321.387],[-1656.778,-235.801],[-826.579,-298.876],[240.625,-262.316],[1317.387,-174.745],[2394.911,-177.257]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.21568627450980393,0.5686274509803921,0.8313725490196079,0.5,0,0.4588235294117647,0.7058823529411765,1,0.3411764705882353,0.8901960784313725,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-11.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]},{"nm":"","id":"comp_3","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,1345.07,0],"t":0,"ti":[-1512,20,0],"to":[1512,-20,0]},{"s":[5962.4,1225.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-385.992,5.334],[-387.882,-60.547],[-321.535,-7.194],[-439.996,11.5],[-654.107,25.214],[-426.676,-4.654]],"o":[[0,0],[0,0],[0,0],[0,0],[231.29,-12.079],[245.646,-3.395],[570.504,89.054],[514.006,11.5],[196.864,-5.145],[474.188,-18.279],[312.228,3.406]],"v":[[3120.29,-341.615],[3032.719,342.805],[-4858.624,366.136],[-4888.624,-374.755],[-4445.327,-238.541],[-3546.743,-195.277],[-2208.755,-238.645],[-1013.562,-156.864],[221.69,-269.417],[1307.92,-312.023],[2293.137,-222.228]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.03529411764705882,0.7372549019607844,0.9215686274509803,0.5,0.16862745098039217,0.6,0.8392156862745098,1,0.3411764705882353,0.8901960784313725,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-451.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]}]}
\ No newline at end of file
diff --git a/app/src/main/res/raw/water_light.json b/app/src/main/res/raw/water_light.json
new file mode 100644
index 0000000..842d68a
--- /dev/null
+++ b/app/src/main/res/raw/water_light.json
@@ -0,0 +1 @@
+{"nm":"MC","ddd":0,"h":1080,"w":1080,"meta":{"g":"@lottiefiles/toolkit-js 0.26.1"},"layers":[{"ty":0,"nm":"Wave Animation","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[540,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_0","ind":1}],"v":"5.7.3","fr":60,"op":301,"ip":32,"assets":[{"nm":"","id":"comp_0","layers":[{"ty":3,"nm":"Null 1","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[960,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":0,"ix":11}},"ef":[],"ind":1},{"ty":0,"nm":"wave02","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_1","ind":2},{"ty":0,"nm":"wave04","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[{"ty":0,"mn":"ADBE Ramp","nm":"Gradient Ramp","ix":1,"en":1,"ef":[{"ty":3,"mn":"ADBE Ramp-0001","nm":"Start of Ramp","ix":1,"v":{"a":0,"k":[960,0],"ix":1}},{"ty":2,"mn":"ADBE Ramp-0002","nm":"Start Color","ix":2,"v":{"a":0,"k":[0.8706,0.5725,0.1294],"ix":2}},{"ty":3,"mn":"ADBE Ramp-0003","nm":"End of Ramp","ix":3,"v":{"a":0,"k":[960,1080],"ix":3}},{"ty":2,"mn":"ADBE Ramp-0004","nm":"End Color","ix":4,"v":{"a":0,"k":[1,0.8824,0.7059],"ix":4}},{"ty":7,"mn":"ADBE Ramp-0005","nm":"Ramp Shape","ix":5,"v":{"a":0,"k":1,"ix":5}},{"ty":0,"mn":"ADBE Ramp-0006","nm":"Ramp Scatter","ix":6,"v":{"a":0,"k":0,"ix":6}},{"ty":0,"mn":"ADBE Ramp-0007","nm":"Blend With Original","ix":7,"v":{"a":0,"k":0,"ix":7}},{"ty":6,"mn":"ADBE Ramp-0008","nm":"","ix":8,"v":0}]}],"w":1920,"h":1080,"refId":"comp_2","ind":3},{"ty":0,"nm":"wave03","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[116,116,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[960,1620,0],"t":0,"ti":[0,193.333,0],"to":[0,-193.333,0]},{"s":[960,460,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":1920,"h":1080,"refId":"comp_3","ind":4},{"ty":1,"nm":"bg","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[960,540,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[960,540,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"sc":"#ffffff","sh":1080,"sw":1920,"ind":5}]},{"nm":"","id":"comp_1","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[181,181,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,705.07,0],"t":0,"ti":[-1752,40,0],"to":[1752,-40,0]},{"s":[7402.4,465.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-386.024,2.075],[-387.882,-60.547],[-561.726,14.756],[-439.996,11.5],[-654.107,25.214],[-426.676,-4.654]],"o":[[0,0],[0,0],[0,0],[0,0],[231.29,-12.079],[720.469,-3.872],[287.741,44.916],[513.957,-13.501],[196.864,-5.145],[474.188,-18.279],[312.228,3.406]],"v":[[3122.657,-403.154],[3032.719,342.805],[-4858.624,366.136],[-4890.188,-284.814],[-4484.46,-263.518],[-3532.053,-171.856],[-2202.288,-282.386],[-1005.658,-163.965],[156.221,-295.452],[1307.92,-312.023],[2380.712,-276.665]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.3411764705882353,0.8901960784313725,1,0.495,0.21176470588235294,0.48627450980392156,0.7294117647058823,0.99,0.17254901960784313,0.6784313725490196,0.9607843137254902],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-11.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]},{"nm":"","id":"comp_2","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,665.07,0],"t":0,"ti":[-1512,13.333,0],"to":[1512,-13.333,0]},{"s":[5962.4,585.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-514.373,15.366],[-276.818,-2.951],[-356.676,20.338],[-192.117,-4.298],[-435.317,65.022],[-444.201,36.5],[-421.576,-65.955]],"o":[[0,0],[0,0],[0,0],[0,0],[119.969,-6.265],[147.306,-4.4],[308.969,3.294],[316.551,-18.05],[514.005,11.5],[641.417,-95.807],[472.947,-38.862],[778.87,121.852]],"v":[[3191.299,-483.627],[3032.719,342.805],[-4858.624,366.136],[-4888.624,-488.364],[-4895.032,-465.76],[-3631.042,-236.271],[-2730.72,-321.387],[-1656.778,-235.801],[-826.579,-298.876],[240.625,-262.316],[1317.387,-174.745],[2394.911,-177.257]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.21568627450980393,0.5686274509803921,0.8313725490196079,0.5,0,0.4588235294117647,0.7058823529411765,1,0.3411764705882353,0.8901960784313725,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-11.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]},{"nm":"","id":"comp_3","layers":[{"ty":4,"nm":"water","sr":1,"st":0,"op":424,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[169,169,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.333,"y":0},"i":{"x":0.833,"y":0.833},"s":[-3109.6,1345.07,0],"t":0,"ti":[-1512,20,0],"to":[1512,-20,0]},{"s":[5962.4,1225.07,0],"t":227}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":63,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[-267.334,13.961],[-385.992,5.334],[-387.882,-60.547],[-321.535,-7.194],[-439.996,11.5],[-654.107,25.214],[-426.676,-4.654]],"o":[[0,0],[0,0],[0,0],[0,0],[231.29,-12.079],[245.646,-3.395],[570.504,89.054],[514.006,11.5],[196.864,-5.145],[474.188,-18.279],[312.228,3.406]],"v":[[3120.29,-341.615],[3032.719,342.805],[-4858.624,366.136],[-4888.624,-374.755],[-4445.327,-238.541],[-3546.743,-195.277],[-2208.755,-238.645],[-1013.562,-156.864],[221.69,-269.417],[1307.92,-312.023],[2293.137,-222.228]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"c":{"a":0,"k":[0,0.6627,1],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-1710,-142],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.03529411764705882,0.7372549019607844,0.9215686274509803,0.5,0.16862745098039217,0.6,0.8392156862745098,1,0.3411764705882353,0.8901960784313725,1],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1706,-427],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[3.5,-451.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]}]}
\ No newline at end of file
diff --git a/app/src/main/res/raw/winner.json b/app/src/main/res/raw/winner.json
new file mode 100644
index 0000000..a4f54d8
--- /dev/null
+++ b/app/src/main/res/raw/winner.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":30,"ip":0,"op":71,"w":500,"h":500,"nm":"Trophy","ddd":0,"assets":[{"id":"comp_0","nm":"Pre-comp 3","fr":30,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[391.176,345.588,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":2,"op":17,"st":2,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[344.118,294.118,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":1,"op":16,"st":1,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[151.471,317.647,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":7,"op":22,"st":7,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[104.412,266.176,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":6,"op":21,"st":6,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[342.647,145.588,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":4,"op":19,"st":4,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[295.588,94.118,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":3,"op":18,"st":3,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133.824,122.059,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":1,"op":16,"st":1,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Pre-comp 2","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.412,82.353,0],"ix":2,"l":2},"a":{"a":0,"k":[50,48.5,0],"ix":1,"l":2},"s":{"a":0,"k":[50,50,100],"ix":6,"l":2}},"ao":0,"w":100,"h":97,"ip":0,"op":15,"st":0,"bm":0}]},{"id":"comp_1","nm":"Pre-comp 2","fr":30,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[50.5,47,0],"ix":2,"l":2},"a":{"a":0,"k":[-142.5,-154,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-142.5,-154],[-101.5,-154]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":15,"st":-11,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[50.5,47,0],"ix":2,"l":2},"a":{"a":0,"k":[-142.5,-154,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-142.5,-154],[-101.5,-154]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":15,"st":-11,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[50.5,47,0],"ix":2,"l":2},"a":{"a":0,"k":[-142.5,-154,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-142.5,-154],[-101.5,-154]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":15,"st":-11,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[50.5,47,0],"ix":2,"l":2},"a":{"a":0,"k":[-142.5,-154,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-142.5,-154],[-101.5,-154]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[0]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":15,"st":-11,"bm":0}]},{"id":"comp_2","nm":"Pre-comp 1","fr":30,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":30,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":60,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":120,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":150,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":210,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 18","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":240,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 19","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":4,"s":[60]},{"t":14,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":300,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":3,"s":[60]},{"t":13,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 20","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":330,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[0,0],[178,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.705882352941,0.247058838489,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":3,"s":[60]},{"t":13,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[60]},{"t":10,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Pre-comp 3","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":39,"op":61,"st":39,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Pre-comp 3","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":24,"op":46,"st":24,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Cup 3","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.371,-98.838,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.8,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.8,-128.285],[49.3,-128.285],[70.626,-106.958],[62.096,-21.652],[-62.596,-21.652],[-71.126,-106.958]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.2,"y":0},"t":14,"s":[{"i":[[0,6.785],[0,0],[0,-11.667],[0,0],[0,55.777],[0,0]],"o":[[0,0],[0,8.035],[0,0],[0,54.652],[0,0],[0,-12.042]],"v":[[-0.25,-128.285],[-0.25,-128.285],[-0.25,-106.958],[-0.25,-21.652],[-0.25,-21.652],[-0.25,-106.958]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.8,-128.285],[49.3,-128.285],[70.626,-106.958],[62.096,-21.652],[-62.596,-21.652],[-71.126,-106.958]],"c":true}]},{"i":{"x":1,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.8,-128.285],[49.3,-128.285],[70.626,-106.958],[62.096,-21.652],[-62.596,-21.652],[-71.126,-106.958]],"c":true}]},{"i":{"x":0.223,"y":1},"o":{"x":0.2,"y":0},"t":31,"s":[{"i":[[0,6.785],[0,0],[0,-11.667],[0,0],[0,55.777],[0,0]],"o":[[0,0],[0,8.035],[0,0],[0,54.652],[0,0],[0,-12.042]],"v":[[-0.25,-128.285],[-0.25,-128.285],[-0.25,-106.958],[-0.25,-21.652],[-0.25,-21.652],[-0.25,-106.958]],"c":true}]},{"t":50,"s":[{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.8,-128.285],[49.3,-128.285],[70.626,-106.958],[62.096,-21.652],[-62.596,-21.652],[-71.126,-106.958]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.705882370472,0.247058823705,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Cup","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":310,"st":10,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 7","tt":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"t":24,"s":[{"i":[[3.191,-0.395],[2.304,-0.927],[2.095,-1.709],[1.788,-1.877],[0.908,-1.912],[-1.334,-6.312],[-2.779,-4.188],[-3.401,-3.602],[-3.548,-3.297],[-2.312,-2.352],[-2.506,-2.506],[-2.476,-2.535],[-0.232,-1.997],[0.723,-0.831],[0.267,-1.304],[-2.88,-0.857],[1.3,9.712],[4.203,4.76],[9.453,16.328],[-0.295,3.28],[-3.343,1.249],[-4.023,-0.951],[-1.8,-0.768],[-8.286,2.069],[-0.398,3.182],[3.129,3.445],[1.614,1.176],[1.189,0.657],[2.306,0.956],[2.086,0.582]],"o":[[-4.689,0.581],[-2.304,0.927],[-1.938,1.582],[-1.788,1.877],[-3.116,6.566],[1.334,6.312],[2.849,4.294],[3.401,3.602],[2.244,2.084],[2.312,2.352],[2.864,2.864],[2.476,2.535],[0.16,1.372],[-0.723,0.831],[-1.339,6.557],[13.183,3.921],[-1.018,-7.607],[-12.335,-13.97],[-1.509,-2.606],[0.413,-4.602],[3.955,-1.477],[2.275,0.538],[8.878,3.789],[3.458,-0.863],[0.467,-3.729],[-1.703,-1.875],[-1.654,-1.205],[-1.861,-1.028],[-2.371,-0.983],[-7.691,-2.147]],"v":[[-93,-111],[-102.945,-108.846],[-109,-105],[-114.773,-99.748],[-119,-94],[-120.921,-74.216],[-114,-58],[-104.525,-46.252],[-94,-36],[-87.197,-29.316],[-80,-22],[-71.526,-13.849],[-67,-7],[-68.18,-3.949],[-70,-1],[-64,12],[-47,-11],[-59,-30],[-99,-72],[-102,-81],[-94,-91],[-82,-91],[-75,-89],[-55,-79],[-48,-87],[-53,-98],[-58,-101],[-62,-105],[-69,-107],[-75,-110]],"c":true}],"h":1},{"t":25,"s":[{"i":[[6.363,-1.468],[2.979,-2.095],[1.84,-2.639],[0.408,-1.067],[0.408,-1.35],[0.465,-0.387],[0.082,-0.263],[-3.965,-7.542],[-4.029,-4.555],[-0.766,-0.479],[-0.438,-0.523],[-0.104,-0.568],[-0.27,-0.353],[-0.859,-0.529],[-0.842,-0.709],[-4.878,-5.799],[-0.092,-0.71],[0.419,-2.677],[-6.464,-0.238],[-1.53,2.112],[6.189,7.171],[5.82,5.82],[5.515,7.127],[-5.296,5.528],[-9.204,-2.345],[-3.834,-2.514],[-5.231,0.751],[-0.822,3.258],[5.25,2.566],[1.551,0.608]],"o":[[-4.243,0.979],[-2.98,2.096],[-0.962,1.38],[-0.408,1.067],[-0.057,0.189],[-0.465,0.387],[-2.889,9.276],[3.965,7.542],[0.497,0.561],[0.766,0.479],[0.313,0.374],[0.104,0.568],[1.053,1.378],[1.068,0.657],[6.494,5.469],[1.271,1.511],[0.356,2.738],[-1.191,7.598],[4.588,0.169],[8.605,-11.877],[-4.677,-5.419],[-6.151,-6.151],[-4.119,-5.322],[4.622,-4.825],[3.701,0.943],[4.525,2.967],[3.142,-0.451],[2.691,-10.661],[-1.826,-0.892],[-7.754,-3.037]],"v":[[-95,-111],[-105.802,-106.245],[-113,-99],[-114.915,-95.478],[-116,-92],[-116.981,-91.056],[-118,-90],[-114.689,-64.459],[-101,-46],[-98.956,-44.471],[-97,-43],[-96.468,-41.485],[-96,-40],[-92,-37],[-90,-35],[-71,-17],[-65,-8],[-68,-1],[-59,12],[-49,6],[-55,-29],[-72,-45],[-91,-66],[-97,-87],[-77,-91],[-66,-85],[-54,-79],[-46,-86],[-62,-106],[-67,-109]],"c":true}],"h":1},{"t":26,"s":[{"i":[[1.111,-0.113],[2.585,-1.009],[1.674,-1.559],[0.573,-0.084],[0.356,-0.336],[0.475,-0.926],[0.564,-0.79],[0.36,-0.281],[0.285,-0.493],[0.871,-2.718],[0.063,-2.618],[-3.733,-5.588],[-2.015,-2.521],[-0.872,-1.07],[-1.274,-1.411],[-7.648,-7.648],[-0.543,-5.007],[0.55,-2.542],[-2.362,-2.153],[-1.562,7.645],[2.913,4.566],[2.86,3.478],[9.12,11.123],[-1.11,7.282],[-2.157,0.726],[-4.835,-3.467],[-4.962,0.362],[-0.24,6.416],[7.573,3.176],[2.407,0.544]],"o":[[-3.987,0.405],[-2.585,1.009],[-0.352,0.328],[-0.573,0.084],[-0.536,0.507],[-0.475,0.926],[-0.273,0.382],[-0.36,0.281],[-1.452,2.508],[-0.871,2.718],[-0.253,10.508],[1.754,2.625],[0.961,1.203],[1.009,1.238],[6.895,7.635],[5.268,5.268],[0.253,2.337],[-0.918,4.241],[8.175,7.452],[1.806,-8.842],[-2.806,-4.398],[-8.695,-10.574],[-5.23,-6.378],[0.863,-5.666],[7.845,-2.641],[3.765,2.699],[4.671,-0.341],[0.327,-8.737],[-3.3,-1.384],[-5.338,-1.207]],"v":[[-85,-112],[-94.735,-109.865],[-101,-106],[-102.498,-105.506],[-104,-105],[-105.479,-102.712],[-107,-100],[-107.991,-99.083],[-109,-98],[-112.542,-90.083],[-114,-82],[-106,-58],[-100,-51],[-98,-47],[-94,-44],[-75,-23],[-63,-8],[-65,-1],[-63,9],[-43,-1],[-48,-23],[-58,-35],[-84,-62],[-94,-83],[-86,-92],[-64,-86],[-52,-79],[-43,-89],[-63,-108],[-72,-112]],"c":true}],"h":1},{"t":27,"s":[{"i":[[2.317,-0.535],[3.86,-4.04],[1.242,-4.613],[-2.12,-5.938],[-2.373,-3.37],[-0.492,-0.639],[-0.459,-0.632],[-0.8,-1.421],[-0.923,-1.114],[-0.951,-0.655],[-0.472,-0.507],[-0.081,-0.566],[-0.34,-0.374],[-1.019,-0.973],[-0.936,-1.02],[-0.997,-1.18],[-0.954,-1.127],[-0.458,-4.534],[0.591,-1.92],[-7.875,-0.144],[-0.943,9.517],[4.79,6.294],[7.791,10.593],[-2.16,8.125],[-1.994,0.531],[-4.781,-3.242],[-0.608,-0.61],[-0.949,-0.628],[-0.752,8.522],[12.133,3.114]],"o":[[-5.317,1.227],[-3.86,4.04],[-1.851,6.879],[2.12,5.938],[0.571,0.811],[0.492,0.639],[0.875,1.203],[0.8,1.421],[0.723,0.873],[0.951,0.655],[0.337,0.361],[0.081,0.566],[0.99,1.09],[1.018,0.973],[1.058,1.152],[0.997,1.18],[3.481,4.111],[0.271,2.68],[-2.255,7.329],[7.212,0.132],[1.112,-11.222],[-8.19,-10.762],[-4.476,-6.085],[0.814,-3.063],[5.149,-1.372],[0.641,0.434],[1.172,1.175],[7.025,4.649],[0.85,-9.635],[-5.404,-1.387]],"v":[[-82,-111],[-96.057,-102.54],[-104,-89],[-102.668,-69.368],[-95,-55],[-93.416,-52.866],[-92,-51],[-89.536,-46.934],[-87,-43],[-84.312,-40.725],[-82,-39],[-81.502,-37.509],[-81,-36],[-77.959,-32.947],[-75,-30],[-71.923,-26.481],[-69,-23],[-58,-8],[-60,-2],[-51,12],[-38,-5],[-48,-30],[-76,-62],[-84,-85],[-77,-92],[-60,-87],[-57,-85],[-55,-81],[-38,-88],[-65,-111]],"c":true}],"h":1},{"t":28,"s":[{"i":[[9.692,-1.405],[1.755,-0.653],[1.212,-0.989],[0.612,-0.799],[1.064,-1.588],[0.956,-1.834],[0.829,-2.651],[-1.471,-5.599],[-2.124,-4.18],[-2.534,-3.99],[-2.617,-3.613],[-1.064,-1.14],[-0.856,-1.216],[-1.667,-2.958],[-0.212,-2.155],[0.684,-2.633],[-1.441,-2.449],[-1.846,-1.035],[-3.412,0.49],[-1.764,4.555],[0.994,6.213],[1.271,2.573],[1.579,2.614],[5.214,6.995],[2.346,5.732],[-9.454,1.216],[-1.712,-1.097],[-10.861,3.613],[-0.352,2.926],[4.889,4.64]],"o":[[-2.767,0.401],[-1.755,0.653],[-1.489,1.215],[-0.612,0.799],[-1.348,2.013],[-0.956,1.834],[-2.008,6.423],[1.471,5.599],[2.249,4.426],[2.534,3.99],[0.888,1.226],[1.064,1.14],[2.12,3.012],[1.667,2.958],[0.297,3.021],[-0.684,2.633],[0.206,0.35],[1.846,1.035],[3.939,-0.566],[1.764,-4.555],[-0.335,-2.095],[-1.271,-2.573],[-3.799,-6.286],[-5.214,-6.995],[-3.248,-7.936],[1.752,-0.225],[5.75,3.685],[2.926,-0.973],[0.526,-4.371],[-6.865,-6.516]],"v":[[-63,-111],[-69.666,-109.441],[-74,-107],[-76.82,-104.28],[-79,-101],[-82.389,-95.478],[-85,-89],[-85.099,-70.817],[-79,-56],[-71.776,-43.39],[-64,-32],[-60.976,-28.493],[-58,-25],[-52.068,-15.857],[-49,-8],[-50.358,0.429],[-50,8],[-46.904,10.63],[-39,12],[-30.301,3.736],[-29,-13],[-31.567,-20.11],[-36,-28],[-50.589,-48.416],[-63,-68],[-59,-92],[-53,-89],[-34,-79],[-28,-87],[-36,-101]],"c":true}],"h":1},{"t":29,"s":[{"i":[[-2.683,7.317],[-0.869,-1.25],[-0.8,-0.658],[-1.031,-0.204],[-1.563,0.111],[-1.735,1.264],[-0.45,1.828],[3.728,4.807],[2.323,0.76],[3.865,-2.557],[1.585,-3.719],[-0.715,-8.537],[-2.363,-6.29],[-1.877,-4.04],[-1.844,-4.454],[-1.186,-3.102],[-0.134,-2.887],[0.496,-1.449],[0.053,-1.394],[-1.552,-2.05],[-2.93,-0.213],[-1.523,0.346],[-0.883,0.689],[-0.327,1.358],[-0.442,1.593],[1.215,6.113],[1.85,4.387],[0.684,1.501],[0.533,1.264],[2.41,7.866]],"o":[[1.239,1.98],[0.869,1.25],[0.8,0.658],[1.031,0.204],[1.61,-0.114],[1.735,-1.264],[1.234,-5.011],[-3.728,-4.807],[-5.956,-1.948],[-3.865,2.557],[-3.224,7.564],[0.715,8.537],[1.648,4.387],[1.877,4.04],[1.12,2.706],[1.186,3.102],[0.038,0.811],[-0.496,1.449],[-0.136,3.585],[1.552,2.05],[1.025,0.075],[1.523,-0.346],[1.249,-0.974],[0.327,-1.358],[1.71,-6.16],[-1.215,-6.113],[-0.73,-1.733],[-0.684,-1.501],[-3.044,-7.221],[-2.41,-7.866]],"v":[[-33,-87],[-29.914,-82.19],[-27.486,-79.364],[-24.816,-78.105],[-21,-78],[-15.63,-80.215],[-12,-85],[-17.332,-100.689],[-28,-110],[-42.778,-108.25],[-51,-98],[-54.191,-73.044],[-49,-50],[-43.647,-37.55],[-38,-25],[-34.26,-16.136],[-32,-7],[-32.932,-3.437],[-34,1],[-31.799,9.529],[-25,13],[-20.893,12.572],[-17,11],[-14.895,7.464],[-14,3],[-13.83,-15.829],[-19,-32],[-21.148,-36.851],[-23,-41],[-32.295,-63.928]],"c":true}],"h":1},{"t":30,"s":[{"i":[[3.333,-0.976],[1.133,-1.074],[0.545,-1.572],[0.264,-2.087],[0.291,-2.619],[-0.238,-6.751],[-0.732,-6.624],[-0.753,-6.186],[-0.301,-5.438],[0.011,-2.415],[-0.042,-2.238],[-0.282,-1.704],[-0.709,-0.814],[-1.027,-0.436],[-1.371,-0.226],[-1.409,0.198],[-1.139,0.835],[0.122,7.953],[0.958,8.662],[0.318,3.74],[0.375,3.844],[0.571,4.011],[-0.7,2.69],[-0.723,0.668],[-0.748,0.937],[-0.514,0.926],[-0.22,1.386],[0.663,2.516],[0.717,1.6],[2.195,1.193]],"o":[[-2.029,0.594],[-1.133,1.074],[-0.545,1.572],[-0.264,2.087],[-0.729,6.568],[0.238,6.751],[0.732,6.624],[0.753,6.186],[0.124,2.236],[-0.011,2.415],[0.042,2.238],[0.282,1.704],[0.377,0.433],[1.027,0.436],[1.371,0.226],[1.409,-0.198],[3.447,-2.528],[-0.122,-7.953],[-0.353,-3.197],[-0.318,-3.74],[-0.416,-4.266],[-0.571,-4.011],[0.361,-1.39],[0.723,-0.668],[0.726,-0.91],[0.514,-0.926],[0.37,-2.338],[-0.663,-2.516],[-1.885,-4.206],[-2.195,-1.193]],"v":[[-11,-109],[-15.667,-106.502],[-18.108,-102.537],[-19.245,-97.054],[-20,-90],[-20.619,-69.944],[-19.046,-49.805],[-16.7,-30.513],[-15,-13],[-14.877,-5.936],[-14.877,1.132],[-14.438,7.133],[-13,11],[-10.818,12.357],[-7.145,13.403],[-2.899,13.497],[1,12],[5.304,-4.9],[3,-31],[2.016,-41.514],[1,-53],[-0.837,-65.682],[-1,-76],[0.711,-78.84],[3,-81],[4.88,-83.643],[6,-87],[5.316,-94.554],[3,-101],[-2.914,-108.886]],"c":true}],"h":1},{"t":31,"s":[{"i":[[3.441,-0.647],[1.283,-0.953],[0.833,-1.422],[0.508,-1.758],[0.31,-1.96],[-0.087,-1.457],[-0.408,-1.039],[-0.617,-0.938],[-0.714,-1.153],[-0.141,-1.047],[0.131,-1.095],[0.206,-1.125],[0.086,-1.137],[0.415,-3.836],[0.451,-3.58],[0.436,-3.579],[0.369,-3.834],[0.163,-4.005],[-0.565,-3.399],[-1.82,-1.944],[-3.604,0.359],[-1.357,1.89],[-0.311,2.89],[0.076,3.305],[-0.195,3.135],[-0.864,6.178],[-0.881,7.07],[-0.327,7.107],[0.798,6.288],[2.455,2.453]],"o":[[-1.859,0.35],[-1.283,0.953],[-0.833,1.422],[-0.508,1.758],[-0.346,2.191],[0.087,1.457],[0.408,1.039],[0.617,0.938],[0.608,0.981],[0.141,1.047],[-0.131,1.095],[-0.206,1.125],[-0.328,4.346],[-0.415,3.836],[-0.451,3.58],[-0.436,3.579],[-0.363,3.764],[-0.163,4.005],[0.565,3.399],[1.82,1.944],[3.06,-0.305],[1.357,-1.89],[0.311,-2.89],[-0.076,-3.305],[0.275,-4.432],[0.864,-6.178],[0.881,-7.07],[0.327,-7.107],[-0.741,-5.836],[-2.455,-2.453]],"v":[[11,-109],[6.318,-107.013],[3.176,-103.416],[1.196,-98.612],[0,-93],[-0.361,-87.608],[0.409,-83.943],[1.975,-81.057],[4,-78],[5.074,-74.953],[5.041,-71.735],[4.487,-68.399],[4,-65],[2.874,-52.791],[1.563,-41.731],[0.22,-31.056],[-1,-20],[-1.921,-8.134],[-1.45,3.184],[1.995,11.41],[10,14],[16.461,10.561],[18.798,3.245],[18.986,-6.194],[19,-16],[20.851,-32.129],[23.61,-52.216],[25.564,-73.694],[25,-94],[20.025,-106.362]],"c":true}],"h":1},{"t":32,"s":[{"i":[[10.012,-0.857],[0.663,-0.066],[0.696,-0.133],[0.685,-0.25],[0.629,-0.419],[1.161,-1.785],[0.997,-2.24],[0.588,-2.086],[-0.068,-1.321],[-1.507,-1.219],[-0.877,-0.316],[-1.658,-0.093],[-0.11,-0.173],[0.768,-3.552],[0.803,-3.414],[1.144,-4.168],[1.192,-4.1],[1.234,-4.969],[-0.056,-4.277],[-2.293,-3.72],[-5.767,1.698],[-1.257,0.847],[-0.419,0.742],[0.306,2.867],[-0.16,2.647],[-0.757,2.689],[-0.84,3.026],[-1.59,5.162],[-1.1,4.811],[1.605,11.555]],"o":[[-0.585,0.05],[-0.663,0.066],[-0.696,0.133],[-0.685,0.25],[-1.079,0.718],[-1.161,1.785],[-0.997,2.24],[-0.588,2.086],[0.093,1.806],[1.507,1.219],[1.258,0.453],[1.658,0.093],[0.876,1.379],[-0.768,3.552],[-1.23,5.23],[-1.144,4.168],[-1.119,3.847],[-1.234,4.969],[0.062,4.817],[2.293,3.72],[-0.445,0.131],[1.257,-0.847],[1.063,-1.884],[-0.306,-2.867],[0.134,-2.219],[0.757,-2.689],[1.538,-5.541],[1.59,-5.162],[2.433,-10.639],[-1.605,-11.555]],"v":[[27,-109],[25.116,-108.839],[23.066,-108.553],[20.982,-107.991],[19,-107],[15.579,-103.093],[12.28,-96.903],[9.841,-90.262],[9,-85],[11.912,-80.383],[16,-78],[20.861,-77.29],[24,-77],[23.76,-69.026],[21,-58],[17.471,-44.153],[14,-32],[10.119,-18.323],[8,-4],[11.222,9.887],[23,14],[24.852,12.655],[28,10],[28.678,2.572],[28,-6],[29.471,-13.395],[32,-22],[36.828,-38.047],[41,-53],[43.334,-89.622]],"c":true}],"h":1},{"t":33,"s":[{"i":[[-1.692,-0.766],[1.471,-6.219],[2.553,-5.943],[1.166,-2.647],[1.155,-2.664],[1.283,-2.686],[0.627,-2.395],[-0.895,-5.6],[-2.8,-1.331],[-2.452,0.856],[-0.736,1.221],[0.438,2.954],[-0.248,2.689],[-1.182,2.599],[-0.96,2.214],[-0.473,1.359],[-0.575,1.331],[-0.379,0.478],[-0.227,0.489],[-0.098,0.91],[-0.285,0.66],[-1.26,2.459],[-0.88,2.66],[-0.699,3.206],[-0.248,3.282],[3.214,7.139],[7.793,-0.124],[1.212,-0.836],[-16.354,-1.393],[-1.724,3.235]],"o":[[1.434,6.183],[-1.471,6.218],[-1.18,2.747],[-1.166,2.647],[-1.24,2.86],[-1.283,2.686],[-1.379,5.271],[0.895,5.6],[3.456,1.643],[2.452,-0.856],[1.506,-2.497],[-0.438,-2.954],[0.312,-3.39],[1.182,-2.599],[0.535,-1.233],[0.473,-1.359],[0.258,-0.599],[0.379,-0.478],[0.325,-0.701],[0.098,-0.91],[1.079,-2.504],[1.26,-2.459],[0.958,-2.895],[0.698,-3.206],[0.647,-8.57],[-3.214,-7.139],[-2.471,0.04],[-7.887,5.438],[7.4,0.63],[0.183,-0.343]],"v":[[38,-85],[37.49,-66.32],[31,-48],[27.481,-39.938],[24,-32],[20.04,-23.651],[17,-16],[16.366,1.455],[22,13],[31.04,13.648],[36,10],[36.944,1.644],[36,-7],[38.514,-15.882],[42,-23],[43.47,-26.927],[45,-31],[46.023,-32.582],[47,-34],[47.53,-36.53],[48,-39],[51.649,-46.383],[55,-54],[57.532,-63.209],[59,-73],[55.33,-98.02],[39,-110],[28,-106],[26,-77],[36,-83]],"c":true}],"h":1},{"t":34,"s":[{"i":[[14.095,-1.272],[0.937,-0.322],[0.989,-0.507],[0.677,-0.062],[0.614,-0.406],[1.107,-1.421],[0.922,-1.224],[0.408,-0.14],[0.201,-0.216],[0.756,-2.55],[-0.329,-1.4],[-2.06,-1.454],[-3.378,0.441],[-2.23,3.005],[-1.843,-1.444],[-0.405,-1.932],[-0.025,-1.995],[0.392,-1.914],[0.456,-1.6],[2.132,-3.599],[2.472,-4.571],[0.616,-1.544],[0.771,-1.406],[0.656,-1.147],[0.679,-1.473],[-14.013,-1.683],[-0.906,4.713],[-0.286,3.517],[-3.246,5.959],[-1.098,19.932]],"o":[[-2.264,0.204],[-0.937,0.322],[-0.678,0.347],[-0.677,0.062],[-1.651,1.092],[-1.107,1.421],[-0.169,0.224],[-0.407,0.14],[-1.305,1.401],[-0.756,2.55],[0.382,1.624],[2.06,1.454],[3.235,-0.423],[2.23,-3.005],[0.353,0.276],[0.405,1.932],[0.022,1.745],[-0.392,1.914],[-2.002,7.031],[-2.132,3.6],[-0.767,1.416],[-0.616,1.544],[-0.631,1.151],[-0.757,1.324],[-5.008,10.858],[6.28,0.754],[0.78,-4.06],[0.405,-4.988],[8.39,-15.404],[1.187,-21.552]],"v":[[47,-109],[42.544,-108.226],[40,-107],[37.952,-106.544],[36,-106],[31.953,-102.099],[29,-98],[28.025,-97.494],[27,-97],[23.774,-90.499],[23,-84],[26.753,-78.951],[35,-77],[43.044,-83.9],[49,-88],[50.246,-84.288],[51,-78],[50.358,-72.392],[49,-67],[42.853,-52.155],[36,-41],[34.003,-36.492],[32,-32],[29,-29],[27,-24],[32,14],[44,6],[42,-6],[49,-23],[71,-75]],"c":true}],"h":1},{"t":35,"s":[{"i":[[8.043,-0.886],[1.416,-0.578],[2.278,-1.352],[1.236,-0.627],[0.831,-0.763],[0.311,-0.547],[0.347,-0.438],[0.627,-2.982],[-3.135,-2.767],[-3.115,2.252],[-2.844,2.136],[-1.146,-0.796],[-0.7,-3.858],[2.241,-5.103],[2.163,-3.381],[0.336,-0.745],[0.319,-0.495],[4.168,-7.075],[0.392,-6.585],[-1.84,-4.18],[-4.893,0],[-1.309,1.377],[-0.485,1.491],[0.519,2.006],[-0.269,2.498],[-1.51,2.797],[-1.745,2.835],[-3.084,4.604],[-2.081,10.716],[5.726,6.344]],"o":[[-3.056,0.337],[-1.416,0.578],[-1.225,0.727],[-1.236,0.627],[-0.408,0.374],[-0.311,0.547],[-2.626,3.307],[-0.627,2.981],[4.694,4.144],[3.115,-2.252],[2.716,-2.041],[1.146,0.796],[1.126,6.206],[-2.241,5.103],[-0.337,0.526],[-0.336,0.745],[-3.936,6.116],[-4.168,7.075],[-0.255,4.279],[1.841,4.18],[3.279,0],[1.309,-1.377],[0.806,-2.478],[-0.519,-2.006],[0.213,-1.978],[1.511,-2.797],[3.564,-5.791],[5.859,-8.748],[2.529,-13.025],[-5.149,-5.706]],"v":[[54,-109],[47.916,-107.762],[43,-105],[39.204,-103.026],[36,-101],[34.955,-99.548],[34,-98],[28.68,-88.595],[32,-80],[43.387,-78.79],[52,-87],[57.513,-88.924],[60,-82],[57.466,-64.882],[50,-52],[48.986,-49.976],[48,-48],[34.842,-27.852],[27,-7],[29.139,6.709],[39,14],[45.596,11.618],[48,7],[47.903,0.515],[47,-6],[49.851,-13.357],[55,-22],[67,-40],[80,-70],[72,-102]],"c":true}],"h":1},{"t":36,"s":[{"i":[[6.95,-0.74],[2.905,-1.098],[1.338,-1.282],[2.561,-3.354],[-1.377,-4.54],[-1.524,-1.099],[-2.451,-0.109],[-1.063,0.784],[-0.925,0.989],[-2.672,1.205],[-0.427,0.231],[-1.115,-0.377],[-0.221,-2.138],[2.655,-4.292],[0.852,-1.278],[0.353,-0.47],[0.554,-0.76],[0.376,-0.501],[0.552,-0.759],[1.638,-2.261],[2.119,-8.747],[-11.571,0.349],[0.102,-0.212],[-0.6,5.533],[-3.865,5.614],[-3.36,5.017],[-2.959,7.022],[-0.68,2.933],[8.858,3.993],[0.432,0.229]],"o":[[-3.041,0.324],[-2.905,1.098],[-2.132,2.042],[-2.561,3.354],[0.454,1.496],[1.524,1.099],[2.821,0.126],[1.064,-0.784],[2.484,-2.655],[0.357,-0.161],[1.608,-0.869],[1.776,0.601],[0.807,7.818],[-0.965,1.561],[-0.298,0.447],[-0.636,0.848],[-0.344,0.472],[-0.635,0.846],[-1.758,2.419],[-5.704,7.876],[-2.125,8.771],[5.64,-0.17],[2.416,-5.024],[0.401,-3.692],[4.493,-6.525],[4.477,-6.685],[1.175,-2.788],[3.523,-15.198],[-0.36,-0.162],[-3.543,-1.875]],"v":[[60,-109],[50.723,-106.719],[44,-103],[35.868,-94.873],[33,-83],[36.002,-78.96],[42,-77],[47.422,-78.164],[50,-81],[56,-86],[57,-88],[64,-90],[69,-80],[60,-57],[58,-52],[56,-51],[55,-48],[53,-47],[52,-44],[46,-37],[32,-11],[44,14],[53,9],[51,-6],[60,-21],[73,-39],[84,-59],[88,-68],[76,-105],[75,-107]],"c":true}],"h":1},{"t":37,"s":[{"i":[[6.233,-0.744],[3.673,-1.795],[2.536,-2.251],[1.463,-2.357],[-0.21,-2.367],[-1.895,-1.574],[-2.184,-0.066],[-3.996,3.091],[-3.467,-1.045],[-0.259,-4.087],[3.554,-5.557],[3.616,-4.531],[1.087,-12.139],[-9.903,1.954],[-0.682,3.684],[-0.71,4.488],[-0.964,1.734],[-0.939,1.446],[-0.345,0.461],[-0.554,0.76],[-0.376,0.501],[-0.596,0.775],[-1.455,2.193],[-0.623,0.94],[-0.623,0.94],[-0.506,0.737],[-0.962,1.445],[-0.981,1.538],[0.282,9.538],[7.628,4.07]],"o":[[-4.773,0.57],[-3.673,1.795],[-1.358,1.206],[-1.463,2.357],[0.234,2.637],[1.896,1.574],[6.258,0.189],[4.147,-3.208],[2.255,0.68],[0.397,6.272],[-3.899,6.097],[-9.421,11.805],[-1.145,12.792],[3.806,-0.751],[0.803,-4.341],[0.086,-0.546],[0.913,-1.643],[0.285,-0.438],[0.636,-0.848],[0.344,-0.472],[0.653,-0.87],[2.166,-2.819],[1.103,-1.662],[1.103,-1.662],[0.595,-0.897],[0.809,-1.177],[0.873,-1.312],[4.282,-6.717],[-0.374,-12.63],[-4.306,-2.297]],"v":[[65,-109],[52.323,-105.261],[43,-99],[38.324,-93.371],[36,-86],[39.537,-79.572],[46,-77],[57,-84],[70,-90],[76,-79],[68,-59],[56,-43],[35,-8],[50,14],[57,6],[55,-7],[58,-11],[60,-16],[62,-17],[63,-20],[65,-21],[66,-24],[74,-33],[77,-37],[80,-41],[82,-43],[84,-48],[87,-52],[96,-79],[81,-107]],"c":true}],"h":1},{"t":38,"s":[{"i":[[1.647,-0.211],[3.205,-1.278],[3.453,-2.54],[2.196,-2.853],[-1.45,-4.627],[-1.536,-1.121],[-2.416,-0.112],[-2.608,2.496],[-2.576,1.201],[-2.905,-1.487],[-0.312,-4.948],[1.855,-3.591],[1.77,-2.606],[2.135,-2.77],[2.131,-2.486],[4.115,-5.865],[0,-7.076],[-9.381,0.969],[0.945,4.244],[-0.331,2.895],[-2.557,3.213],[-1.725,2.071],[-2.393,3.051],[-0.908,1.137],[-1.532,2.219],[-0.672,1.075],[-1.198,3.937],[3.55,7.75],[6.098,3.388],[1.056,0.329]],"o":[[-2.727,0.349],[-3.205,1.278],[-2.665,1.96],[-2.196,2.853],[0.439,1.403],[1.536,1.121],[3.993,0.185],[2.608,-2.496],[4.069,-1.897],[2.905,1.487],[0.191,3.028],[-1.855,3.591],[-2.331,3.432],[-2.135,2.77],[-5.541,6.463],[-4.115,5.865],[0,10.245],[8.784,-0.907],[-0.459,-2.063],[0.63,-5.51],[1.77,-2.224],[3.326,-3.993],[0.909,-1.159],[1.718,-2.153],[0.596,-0.863],[2.908,-4.652],[3.053,-10.033],[-3.703,-8.083],[-0.968,-0.538],[-4.187,-1.303]],"v":[[69,-109],[60.044,-106.643],[50,-101],[41.914,-94.001],[40,-83],[43.017,-79.032],[49,-77],[58.562,-81.461],[66,-88],[76.817,-88.634],[82,-79],[78.971,-68.684],[73,-59],[66.35,-49.791],[60,-42],[44.844,-23.959],[38,-5],[52,14],[60,1],[58,-6],[68,-20],[73,-27],[82,-37],[84,-41],[90,-47],[92,-51],[100,-66],[98,-93],[86,-106],[82,-109]],"c":true}],"h":1},{"t":39,"s":[{"i":[[6.89,-0.815],[3.45,-1.257],[3.629,-2.669],[2.123,-2.867],[-1.331,-4.445],[-1.321,-1.204],[-2.45,-0.294],[-2.437,1.703],[-1.607,-13.824],[3.698,-5.29],[0.365,-0.487],[0.611,-0.78],[0.417,-0.448],[0.686,-0.803],[2.043,-2.273],[2.527,-10.638],[-10.055,1.039],[-0.351,0.734],[-0.86,5.47],[-1.778,2.471],[-3.623,4.033],[-1.799,1.999],[-1.727,2.054],[-0.83,1.103],[-0.403,0.433],[-0.679,0.936],[-0.711,1.062],[0.53,11.664],[4.486,4.612],[1.94,1.026]],"o":[[-2.573,0.304],[-3.45,1.257],[-2.84,2.088],[-2.123,2.867],[0.267,0.889],[1.321,1.204],[6.346,0.762],[8.352,-5.838],[0.651,5.598],[-0.322,0.461],[-0.659,0.878],[-0.361,0.46],[-0.697,0.749],[-2.476,2.9],[-10.39,11.564],[-3.517,14.807],[4.645,-0.48],[2.721,-5.69],[0.214,-1.358],[3.702,-5.144],[2.269,-2.525],[1.844,-2.05],[0.988,-1.175],[0.337,-0.448],[0.745,-0.8],[0.829,-1.142],[4.953,-7.395],[-0.454,-9.995],[-2.485,-2.555],[-5.035,-2.663]],"v":[[73,-109],[63.792,-106.773],[53,-101],[44.872,-93.767],[43,-83],[45.362,-79.554],[51,-77],[64,-84],[87,-80],[79,-60],[77,-59],[76,-56],[74,-55],[73,-52],[66,-45],[42,-12],[55,14],[63,9],[61,-7],[66,-14],[77,-27],[83,-34],[89,-40],[91,-44],[93,-45],[94,-48],[97,-51],[107,-80],[97,-101],[91,-107]],"c":true}],"h":1},{"t":40,"s":[{"i":[[4.56,-0.479],[2.024,-0.262],[1.95,-0.748],[0.607,-0.565],[0.799,-0.444],[1.906,-1.337],[1.585,-2.101],[0.779,-1.504],[-0.362,-2.331],[-4.248,-0.316],[-3.926,2.486],[-1.573,-12.837],[4.023,-5.229],[6.173,-6.924],[2.693,-4.652],[0.019,-5.058],[-8.53,1.272],[-0.963,3.04],[0.206,2.491],[-0.396,3.016],[-1.573,2.228],[-3.55,3.963],[-1.701,1.835],[-3.405,4.389],[-0.712,0.971],[-1.534,2.568],[-1.537,4.72],[-0.22,2.206],[6.333,4.201],[0.665,0.404]],"o":[[-1.954,0.206],[-2.024,0.262],[-0.772,0.296],[-0.607,0.565],[-2.79,1.549],[-1.906,1.337],[-1.247,1.653],[-0.779,1.504],[0.802,5.157],[6.652,0.495],[9.988,-6.325],[0.794,6.479],[-5.783,7.516],[-4.146,4.65],[-2.608,4.505],[-0.039,10.342],[5.007,-0.747],[0.615,-1.941],[-0.203,-2.447],[0.19,-1.452],[3.567,-5.052],[2.286,-2.552],[3.581,-3.864],[0.608,-0.783],[2.013,-2.745],[2.329,-3.899],[0.731,-2.245],[1.388,-13.905],[-0.823,-0.546],[-5.657,-3.436]],"v":[[77,-109],[70.996,-108.407],[65,-107],[63.02,-105.611],[61,-104],[54.097,-99.914],[49,-95],[45.793,-90.508],[45,-85],[54,-77],[67,-85],[91,-80],[82,-59],[60,-35],[48,-20],[43,-5],[58,14],[65,7],[66,2],[63,-6],[68,-13],[79,-26],[85,-33],[97,-45],[99,-49],[104,-56],[109,-67],[111,-74],[99,-104],[97,-106]],"c":true}],"h":1},{"t":41,"s":[{"i":[[5.891,-0.619],[7.054,-4.41],[-0.705,-7.194],[-5.031,-0.092],[-2.824,1.828],[-0.657,0.394],[-2.013,0.636],[-2.125,-0.552],[-0.418,-5.349],[2.56,-3.348],[0.67,-0.82],[2.544,-2.78],[1.253,-1.437],[1.207,-1.257],[0,-14.229],[-8.933,0.442],[-0.698,1.155],[0.579,3.606],[-0.339,2.536],[-0.446,0.479],[-0.686,0.877],[-0.919,0.987],[-0.682,0.766],[-5.785,6.618],[-0.808,0.985],[-0.432,0.464],[-0.687,0.872],[-1.654,2.521],[-1.364,6.519],[8.91,4.888]],"o":[[-6.357,0.668],[-5.62,3.514],[0.498,5.084],[5.931,0.109],[0.694,-0.449],[1.764,-1.058],[2.338,-0.739],[2.344,0.608],[0.506,6.467],[-0.612,0.801],[-2.183,2.67],[-1.231,1.345],[-1.246,1.429],[-12.272,12.774],[0,8.527],[2.795,-0.138],[0.685,-1.133],[-0.352,-2.197],[0.226,-1.696],[0.726,-0.779],[1.372,-1.753],[0.681,-0.732],[7.305,-8.207],[0.724,-0.829],[0.388,-0.473],[0.724,-0.777],[1.893,-2.404],[3.54,-5.395],[3.454,-16.502],[-6.286,-3.448]],"v":[[80,-109],[59,-102],[47,-86],[57,-77],[68,-84],[70,-85],[77,-89],[87,-90],[95,-79],[86,-61],[85,-58],[77,-51],[74,-46],[70,-42],[45,-5],[59,14],[67,10],[68,1],[65,-6],[69,-11],[70,-14],[75,-18],[76,-21],[96,-40],[98,-44],[100,-45],[101,-48],[107,-55],[114,-71],[99,-106]],"c":true}],"h":1},{"t":42,"s":[{"i":[[5.581,-0.632],[7.165,-4.053],[-1.142,-7.166],[-1.553,-1.381],[-2.421,-0.18],[-1.8,1.565],[-1.521,0.984],[-3.539,1.312],[-2.811,-0.562],[-1.738,-1.872],[-0.263,-3.155],[2.61,-4.713],[9.48,-10.878],[1.233,-1.504],[1.8,-3.22],[0.368,-5.272],[-1.843,-2.869],[-6.806,1.534],[-0.796,2.513],[0.246,2.439],[-0.489,3.636],[-0.368,0.49],[-0.662,0.792],[-3.438,3.791],[-5.613,8.462],[-1.561,2.724],[-1.17,6.131],[7.022,5.403],[0.481,0.217],[0.411,0.238]],"o":[[-5.48,0.621],[-7.166,4.053],[0.366,2.296],[1.553,1.381],[3.279,0.244],[1.8,-1.565],[2.031,-1.314],[3.54,-1.312],[1.785,0.357],[1.738,1.872],[0.371,4.452],[-8.341,15.06],[-1.324,1.52],[-2.438,2.974],[-1.597,2.857],[-0.327,4.68],[1.338,2.084],[3.671,-0.828],[0.639,-2.018],[-0.224,-2.216],[0.192,-1.43],[0.677,-0.903],[3.676,-4.395],[7.576,-8.354],[1.656,-2.497],[2.724,-4.753],[2.594,-13.588],[-0.41,-0.315],[-0.349,-0.157],[-5.679,-3.284]],"v":[[82,-109],[60.534,-101.908],[49,-85],[51.959,-79.413],[58,-77],[65.318,-79.579],[70,-84],[78.915,-88.407],[89,-90],[94.642,-86.599],[98,-79],[94,-68],[61,-32],[58,-27],[51,-19],[47,-7],[50,8],[63,14],[69,7],[70,2],[67,-6],[71,-11],[72,-14],[85,-27],[108,-52],[112,-59],[117,-72],[106,-104],[104,-104],[103,-106]],"c":true}],"h":1},{"t":43,"s":[{"i":[[4.927,-0.558],[3.542,-1.123],[3.644,-2.146],[2.59,-2.62],[-0.351,-3.759],[-1.728,-1.527],[-1.838,-0.203],[-1.693,1.27],[-1.334,1.242],[-1.264,0.661],[-0.923,0.407],[-1.021,0.334],[-1.016,0.265],[-2.77,-1.549],[-1.102,-4.061],[2.077,-3.671],[2.572,-3.066],[2.696,-2.589],[1.977,-1.977],[2.091,-10.911],[-10.779,1.307],[-1.057,1.787],[-1.051,5.198],[-2.459,2.941],[-0.93,1.141],[-3.209,2.975],[-2.158,2.158],[-2.093,2.308],[-2.789,7.123],[11.877,6.689]],"o":[[-3.189,0.361],[-3.542,1.123],[-2.991,1.761],[-2.59,2.62],[0.251,2.69],[1.728,1.527],[2.895,0.32],[1.693,-1.27],[1.02,-0.95],[1.264,-0.661],[0.9,-0.398],[1.021,-0.334],[4.816,-1.257],[2.77,1.549],[0.882,3.25],[-2.077,3.671],[-2.239,2.668],[-2.696,2.589],[-9.81,9.81],[-2.071,10.81],[1.08,-0.131],[3.745,-6.328],[0.488,-2.412],[0.944,-1.129],[2.981,-3.657],[2.545,-2.359],[2.037,-2.037],[5.832,-6.43],[6.585,-16.816],[-5.88,-3.312]],"v":[[84,-109],[73.841,-106.839],[63,-102],[53.993,-95.498],[50,-86],[53.309,-79.635],[59,-77],[65.671,-78.829],[70,-83],[73.573,-85.407],[77,-87],[79.913,-88.099],[83,-89],[94.285,-88.489],[100,-80],[97.591,-69.362],[90,-59],[82.303,-50.981],[75,-44],[49,-10],[63,14],[70,10],[69,-7],[75,-14],[77,-18],[87,-28],[95,-34],[101,-41],[118,-64],[105,-106]],"c":true}],"h":1},{"t":44,"s":[{"i":[[5.115,-0.566],[0.943,-0.154],[1.191,-0.267],[0.914,-0.327],[1.32,-0.463],[1.941,-0.604],[1.595,-1.01],[0.14,-0.424],[0.226,-0.169],[0.793,-0.671],[0.484,-0.704],[-9.232,-0.443],[-2.197,1.257],[-5.522,-1.014],[-0.547,-6.508],[2.724,-4.107],[3.049,-2.882],[3.51,-5.292],[1.328,-2.294],[0.363,-1.894],[-1.376,-2.868],[-5.947,0.179],[-0.63,1.987],[-1.123,6.386],[-1.55,1.785],[-9.427,10.506],[-1.063,1.345],[-1.763,2.75],[0.099,8.822],[7.131,4.016]],"o":[[-1.038,0.115],[-0.943,0.154],[-1.026,0.231],[-0.914,0.327],[-1.639,0.575],[-1.941,0.604],[-0.215,0.136],[-0.14,0.424],[-0.907,0.68],[-1.156,0.978],[-5.414,7.879],[4.964,0.238],[4.374,-2.503],[3.374,0.62],[0.679,8.082],[-3.097,4.669],[-5.604,5.298],[-2.105,3.173],[-1.447,2.499],[-1.606,8.373],[2.312,4.819],[6.404,-0.193],[2.077,-6.55],[0.135,-0.768],[10.333,-11.897],[0.89,-0.991],[2.309,-2.921],[3.774,-5.887],[-0.135,-11.968],[-6.041,-3.402]],"v":[[86,-109],[83.114,-108.614],[80,-108],[77.22,-107.174],[74,-106],[68.467,-104.326],[63,-102],[62.508,-101.025],[62,-100],[59,-99],[55,-95],[61,-77],[75,-85],[93,-90],[103,-79],[91,-58],[78,-44],[61,-28],[54,-19],[50,-11],[52,6],[63,14],[72,7],[70,-7],[75,-14],[107,-45],[109,-49],[115,-56],[123,-79],[107,-106]],"c":true}],"h":1},{"t":45,"s":[{"i":[[0.261,-0.024],[8.017,-4.31],[-2.441,-8.274],[-1.328,-1.18],[-2.397,-0.288],[-2.528,1.81],[-1.946,1.114],[-3.131,1.036],[-3.078,-0.516],[-1.994,-1.612],[-0.453,-3.289],[2.299,-3.506],[2.393,-2.681],[2.722,-2.635],[2.206,-2.206],[2.769,-2.663],[2.362,-2.786],[2.18,-3.757],[0.046,-4.341],[-2.666,-3.677],[-4.385,0.463],[1.056,5.63],[-0.76,4],[-2.669,2.987],[-6.78,6.435],[-3.89,11.92],[3.755,5.161],[2.881,1.299],[0.428,0.231],[7.572,0.345]],"o":[[-5.371,0.485],[-8.018,4.31],[0.293,0.992],[1.328,1.18],[2.942,0.353],[2.528,-1.81],[2.397,-1.371],[3.131,-1.036],[1.571,0.263],[1.994,1.612],[0.59,4.296],[-2.299,3.506],[-2.904,3.254],[-2.722,2.635],[-2.564,2.564],[-2.769,2.663],[-2.232,2.632],[-2.181,3.757],[-0.05,4.755],[2.666,3.677],[7.589,-0.801],[-0.441,-2.352],[0.115,-0.608],[6.683,-7.478],[10.619,-10.079],[3.595,-11.016],[-2.432,-3.343],[-0.358,-0.161],[-4.269,-2.305],[-0.985,-0.045]],"v":[[88,-109],[64.641,-101.842],[53,-83],[55.422,-79.472],[61,-77],[69.247,-79.9],[76,-85],[84.489,-88.916],[94,-90],[99.839,-87.269],[104,-80],[100.738,-68.289],[93,-59],[84.476,-50.214],[77,-43],[68.849,-35.167],[61,-27],[53.861,-17.282],[50,-5],[54.174,8.414],[65,14],[73,1],[71,-7],[77,-15],[99,-36],[123,-69],[118,-97],[110,-104],[109,-106],[90,-110]],"c":true}],"h":1},{"t":46,"s":[{"i":[[0.261,-0.024],[3.609,-1.108],[3.998,-2.245],[-0.756,-8.148],[-4.586,-0.172],[-3.519,2.276],[-3.334,0.953],[-4.742,-2.039],[-0.147,-6.015],[1.516,-2.355],[5.212,-4.928],[2.644,-2.52],[2.302,-2.807],[1.252,-1.683],[0.027,-7.326],[-9.201,1.116],[1.156,7.206],[-0.386,2.527],[-2.006,2.278],[-4.659,4.126],[-1.031,0.939],[-4.081,4.977],[-0.432,0.464],[-0.685,0.891],[-1.167,2.216],[0.124,6.681],[1.678,2.899],[2.982,2.713],[0.823,0.444],[6.03,0.275]],"o":[[-3.566,0.322],[-3.609,1.108],[-6.202,3.483],[0.531,5.729],[7.273,0.272],[2.833,-1.832],[3.97,-1.135],[1.682,0.723],[0.086,3.512],[-5.448,8.46],[-2.964,2.802],[-3.241,3.089],[-1.422,1.734],[-3.514,4.726],[-0.035,9.359],[6.251,-0.758],[-0.396,-2.471],[0.249,-1.627],[4.982,-5.658],[1.278,-1.132],[5.173,-4.711],[0.388,-0.473],[0.73,-0.785],[2.117,-2.754],[2.635,-5.004],[-0.117,-6.315],[-2.072,-3.579],[-2.029,-1.847],[-4.47,-2.413],[-0.985,-0.045]],"v":[[89,-109],[78.324,-106.942],[67,-102],[53,-86],[63,-77],[73,-83],[84,-88],[99,-89],[106,-78],[101,-67],[78,-42],[69,-35],[62,-26],[58,-22],[51,-5],[66,14],[74,1],[71,-6],[77,-13],[93,-29],[97,-32],[112,-49],[114,-50],[115,-53],[121,-60],[126,-79],[121,-94],[115,-101],[110,-106],[91,-110]],"c":true}],"h":1},{"t":47,"s":[{"i":[[0.256,-0.022],[2.254,-0.585],[3.206,-1.332],[1.791,-0.633],[1.243,-0.803],[0.459,-0.344],[0.796,-0.69],[0.578,-2.536],[-5.412,-0.37],[-5.389,2.961],[-5.612,-7.141],[4.373,-4.9],[5.997,-4.909],[3.55,-3.74],[1.212,-6.251],[-3.531,-3.523],[-4.555,1.079],[-0.436,0.887],[-0.723,4.885],[-1.207,1.819],[-1.929,1.28],[-0.83,0.751],[-7.632,9.27],[-2.211,5.316],[-0.595,2.568],[2.654,4.923],[0.466,0.486],[3.364,1.516],[0.428,0.231],[8.55,0.39]],"o":[[-3.78,0.33],[-2.254,0.585],[-1.595,0.663],[-1.791,0.633],[-0.437,0.283],[-0.915,0.687],[-2.477,2.147],[-1.81,7.935],[5.485,0.375],[9.229,-5.071],[7.221,9.187],[-7.227,8.097],[-4.679,3.831],[-5.316,5.6],[-1.874,9.669],[2.82,2.814],[1.501,-0.355],[3.521,-7.157],[0.248,-1.678],[1.85,-2.789],[1.033,-0.685],[9.235,-8.355],[4.474,-5.434],[0.69,-1.658],[2.05,-8.853],[-0.787,-1.461],[-2.878,-3.004],[-0.358,-0.161],[-4.426,-2.389],[-0.981,-0.045]],"v":[[90,-109],[81.569,-107.752],[74,-105],[68.736,-103.105],[64,-101],[63,-99],[60,-98],[54,-90],[63,-77],[78,-85],[104,-85],[96,-60],[77,-41],[65,-29],[52,-11],[57,10],[68,14],[74,9],[72,-6],[79,-15],[86,-22],[88,-24],[112,-48],[124,-64],[126,-71],[123,-92],[121,-96],[112,-104],[111,-106],[92,-110]],"c":true}],"h":1},{"t":48,"s":[{"i":[[5.707,-0.548],[3.607,-1.102],[4.005,-2.249],[2.819,-2.546],[-0.378,-4.074],[-1.662,-1.648],[-2.151,-0.238],[-1.707,1.271],[-1.321,1.23],[-4.305,1.431],[-2.995,-0.388],[-2.217,-1.571],[-0.439,-4.495],[2.592,-3.463],[2.102,-2.328],[3.975,-3.638],[4.112,-3.924],[2.697,-3.058],[1.5,-3.18],[0.57,-2.285],[-0.267,-2.771],[-10.363,1.257],[1.29,7.424],[-0.455,2.952],[-2.67,2.951],[-4.807,4.372],[-3.133,3.133],[-1.813,14.684],[3.516,5.047],[5.309,2.786]],"o":[[-3.566,0.342],[-3.607,1.102],[-3.101,1.742],[-2.819,2.546],[0.201,2.169],[1.662,1.648],[2.852,0.316],[1.707,-1.271],[1.786,-1.663],[4.305,-1.431],[1.695,0.22],[2.216,1.571],[0.471,4.82],[-2.592,3.463],[-4.989,5.524],[-3.975,3.638],[-2.714,2.59],[-2.697,3.058],[-0.985,2.088],[-0.571,2.285],[0.413,4.288],[6.161,-0.747],[-0.406,-2.339],[0.384,-2.489],[5.442,-6.015],[2.741,-2.493],[10.566,-10.566],[1.415,-11.462],[-3.734,-5.361],[-5.857,-3.073]],"v":[[90,-109],[79.329,-106.93],[68,-102],[58.391,-95.749],[54,-86],[57.038,-80.051],[63,-77],[69.648,-78.841],[74,-83],[84.094,-88.039],[96,-90],[102.442,-87.706],[107,-79],[102.93,-66.631],[95,-58],[81.841,-44.8],[70,-34],[61.59,-25.442],[55,-16],[52.561,-9.512],[52,-2],[67,14],[75,1],[72,-6],[79,-14],[94,-29],[102,-37],[127,-73],[121,-96],[111,-106]],"c":true}],"h":1},{"t":49,"s":[{"i":[[3.726,-0.269],[3.866,-1.088],[4.144,-2.403],[2.823,-2.612],[-0.276,-3.822],[-1.586,-1.63],[-2.499,-0.282],[-1.548,1.293],[-1.59,1.192],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.118,-3.707],[1.76,-2.908],[6.757,-6.211],[3.75,-10.485],[-0.208,-3.713],[-1.091,-1.383],[2.067,12.881],[-0.361,2.289],[-1.78,2.037],[-2.428,2.305],[-7.457,6.16],[-3.098,4.195],[3.88,12.637],[0.571,0.761],[0.508,0.74],[2.927,1.694],[0.556,0.251]],"o":[[-3.391,0.245],[-3.866,1.088],[-2.984,1.73],[-2.823,2.612],[0.159,2.197],[1.586,1.63],[3.218,0.363],[1.548,-1.293],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[2.825,2.405],[0.108,3.373],[-5.399,8.92],[-11.244,10.335],[-2.003,5.601],[0.162,2.889],[6.774,8.581],[-0.434,-2.706],[0.207,-1.314],[2.331,-2.667],[8.916,-8.463],[4.571,-3.776],[5.652,-7.653],[-0.646,-2.104],[-0.616,-0.821],[-3.524,-5.128],[-0.784,-0.454],[-4.8,-2.162]],"v":[[91,-109],[80.065,-107.118],[68,-102],[58.555,-95.569],[54,-86],[56.744,-80.063],[63,-77],[69.721,-78.833],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[108,-78],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[107,-41],[118,-54],[127,-87],[123,-93],[122,-96],[112,-105],[110,-107]],"c":true}],"h":1},{"t":50,"s":[{"i":[[10.014,-0.756],[0.334,0.01],[0.332,-0.013],[7.34,-4.098],[-0.047,-5.375],[-1.561,-1.849],[-2.735,-0.328],[-1.553,1.304],[-1.559,1.17],[-0.564,0.12],[-0.354,0.225],[-4.846,0.868],[-3.148,-2.679],[-0.605,-0.782],[-0.453,-0.912],[2.39,-3.712],[5.022,-4.916],[1.428,-1.092],[0.716,-0.65],[4.753,-5.254],[0.052,-8.184],[-9.639,1.902],[0.967,6.027],[-0.365,2.287],[-0.108,0.144],[-0.519,0.745],[-3.935,3.656],[-4.823,4.433],[-3.771,12.303],[9.393,5.781]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.69,0.232],[-7.339,4.098],[0.02,2.276],[1.561,1.849],[3.227,0.388],[1.553,-1.304],[0.392,-0.294],[0.564,-0.12],[3.47,-2.209],[4.846,-0.868],[1.127,0.96],[0.605,0.782],[2.799,5.636],[-4.487,6.967],[-2.004,1.962],[-0.743,0.568],[-5.103,4.635],[-4.541,5.021],[-0.059,9.36],[6.182,-1.22],[-0.434,-2.705],[0.005,-0.029],[0.621,-0.828],[3.433,-4.925],[6.122,-5.688],[10.354,-9.517],[4.825,-15.744],[-6.583,-4.051]],"v":[[91,-109],[90.001,-108.991],[89,-109],[67.197,-101.857],[54,-87],[56.464,-80.539],[63,-77],[69.751,-78.832],[74,-83],[75.529,-83.551],[77,-84],[90.242,-89.166],[103,-87],[105.506,-84.464],[107,-82],[103,-67],[88,-50],[82,-44],[79,-43],[63,-27],[52,-5],[68,14],[75,1],[72,-6],[74,-7],[75,-10],[86,-21],[101,-35],[126,-68],[114,-104]],"c":true}],"h":1},{"t":51,"s":[{"i":[[10.014,-0.756],[0.334,0.01],[0.332,-0.013],[7.385,-4.171],[-0.434,-6.076],[-1.652,-1.692],[-2.25,-0.27],[-3.046,2.238],[-3.59,1.436],[-3.744,0.083],[-2.191,-1.865],[-0.881,-1.501],[-0.057,-1.79],[1.061,-1.93],[0.82,-1.273],[2.519,-2.714],[2.61,-2.555],[1.071,-1.118],[0.714,-0.546],[0.716,-0.65],[4.921,-5.441],[0,-8.425],[-9.948,1.963],[0.967,6.027],[-0.361,2.289],[-1.893,2.135],[-2.46,2.285],[-4.891,4.496],[-3.77,12.301],[9.393,5.781]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.894,0.24],[-7.385,4.171],[0.141,1.96],[1.652,1.692],[3.227,0.388],[3.046,-2.238],[3.834,-1.534],[3.744,-0.083],[1.418,1.208],[0.881,1.501],[0.064,2.005],[-1.061,1.93],[-2.312,3.591],[-2.519,2.714],[-1.002,0.981],[-1.071,1.118],[-0.743,0.568],[-5.167,4.692],[-4.504,4.98],[0,9.142],[6.182,-1.22],[-0.434,-2.706],[0.105,-0.668],[2.217,-2.501],[6.163,-5.726],[10.351,-9.515],[4.825,-15.744],[-6.583,-4.051]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.754,-101.877],[54,-86],[56.918,-80.233],[63,-77],[72.227,-80.632],[82,-87],[93.732,-89.55],[103,-87],[106.521,-82.937],[108,-78],[106.163,-71.951],[103,-67],[95.723,-57.723],[88,-50],[84.784,-46.674],[82,-44],[79,-43],[63,-27],[52,-5],[68,14],[75,1],[72,-6],[78,-14],[86,-21],[101,-35],[126,-68],[114,-104]],"c":true}],"h":1},{"t":52,"s":[{"i":[[12.38,-0.935],[0.334,0.01],[0.332,-0.013],[7.395,-4.231],[-0.401,-5.84],[-1.589,-1.631],[-2.495,-0.281],[-1.556,1.296],[-1.569,1.177],[-0.708,0.451],[-6.344,-5.401],[-0.118,-3.707],[1.553,-2.412],[2.109,-2.261],[3.479,-3.032],[1.015,-0.925],[4.884,-5.399],[0.457,-0.597],[0.675,-0.881],[0.965,-1.73],[-4.653,-6.739],[-6.717,1.325],[0.967,6.027],[-0.361,2.289],[-1.893,2.135],[-2.46,2.285],[-4.813,4.442],[-3.763,12.278],[3.547,5.784],[3.366,3.062]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.822,0.237],[-7.395,4.231],[0.151,2.196],[1.589,1.631],[3.209,0.362],[1.556,-1.296],[0.784,-0.588],[6.92,-4.404],[2.825,2.405],[0.127,3.97],[-1.794,2.785],[-3.802,4.076],[-1.461,1.273],[-5.345,4.868],[-0.563,0.622],[-0.636,0.832],[-1.303,1.701],[-4.265,7.65],[2.215,3.208],[6.182,-1.22],[-0.434,-2.706],[0.105,-0.668],[2.217,-2.501],[6.121,-5.687],[10.358,-9.559],[2.752,-8.978],[-2.654,-4.329],[-7.422,-6.753]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.832,-101.702],[54,-86],[56.742,-80.064],[63,-77],[69.73,-78.846],[74,-83],[77,-84],[103,-87],[108,-78],[103,-67],[96,-58],[84,-46],[79,-43],[63,-27],[61,-25],[60,-22],[56,-18],[56,8],[68,14],[75,1],[72,-6],[78,-14],[86,-21],[101,-35],[126,-68],[124,-93],[117,-101]],"c":true}],"h":1},{"t":53,"s":[{"i":[[12.304,-0.929],[0.334,0.01],[0.332,-0.013],[7.404,-4.223],[-0.424,-5.87],[-1.586,-1.63],[-2.499,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.882,-1.486],[-0.059,-1.853],[1.066,-1.956],[0.799,-1.242],[3.42,-3.683],[2.926,-2.55],[1.015,-0.925],[4.644,-5.08],[-8.281,-11.995],[-6.717,1.325],[0.967,6.027],[-0.361,2.289],[-1.837,2.073],[-2.369,2.222],[-4.859,4.485],[13.718,22.37],[3.366,3.062]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.404,4.223],[0.159,2.197],[1.586,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[1.412,1.203],[0.882,1.486],[0.061,1.934],[-1.066,1.956],[-2.394,3.718],[-3.42,3.683],[-1.461,1.273],[-5.408,4.924],[-7.65,8.367],[2.215,3.208],[6.182,-1.22],[-0.434,-2.706],[0.097,-0.617],[2.18,-2.459],[6.391,-5.993],[13.758,-12.697],[-2.654,-4.329],[-7.482,-6.808]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.828,-101.724],[54,-86],[56.744,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[106.515,-82.988],[108,-78],[106.146,-71.981],[103,-67],[93.899,-55.624],[84,-46],[79,-43],[63,-27],[56,8],[68,14],[75,1],[72,-6],[78,-14],[86,-21],[101,-35],[124,-93],[117,-101]],"c":true}],"h":1},{"t":54,"s":[{"i":[[12.304,-0.929],[0.334,0.01],[0.332,-0.013],[7.404,-4.223],[-0.424,-5.87],[-1.586,-1.63],[-2.499,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.882,-1.486],[-0.059,-1.853],[1.066,-1.956],[0.799,-1.242],[3.42,-3.683],[2.926,-2.55],[1.015,-0.925],[4.644,-5.08],[-8.281,-11.995],[-6.717,1.325],[0.967,6.027],[-0.361,2.289],[-1.837,2.073],[-2.369,2.222],[-4.843,4.499],[13.699,22.339],[3.366,3.062]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.404,4.223],[0.159,2.197],[1.586,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[1.412,1.203],[0.882,1.486],[0.061,1.934],[-1.066,1.956],[-2.394,3.718],[-3.42,3.683],[-1.461,1.273],[-5.408,4.924],[-7.65,8.367],[2.215,3.208],[6.182,-1.22],[-0.434,-2.706],[0.097,-0.617],[2.18,-2.459],[6.39,-5.993],[13.777,-12.8],[-2.654,-4.329],[-7.482,-6.808]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.828,-101.724],[54,-86],[56.744,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[106.515,-82.988],[108,-78],[106.146,-71.981],[103,-67],[93.899,-55.624],[84,-46],[79,-43],[63,-27],[56,8],[68,14],[75,1],[72,-6],[78,-14],[86,-21],[101,-35],[124,-93],[117,-101]],"c":true}],"h":1},{"t":55,"s":[{"i":[[12.3,-0.929],[0.334,0.01],[0.332,-0.013],[7.404,-4.223],[-0.424,-5.87],[-1.586,-1.63],[-2.499,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-6.344,-5.401],[-0.118,-3.707],[1.809,-2.989],[6.743,-6.198],[3.75,-10.485],[-0.208,-3.713],[-1.091,-1.383],[2.067,12.881],[-0.361,2.289],[-1.831,2.095],[-2.428,2.305],[-3.88,3.668],[-1.006,0.754],[-0.796,0.79],[-2.045,2.458],[-2.43,5.656],[-0.59,2.441],[2.858,4.937],[2.61,2.375]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.404,4.223],[0.159,2.197],[1.586,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[6.92,-4.404],[2.825,2.405],[0.107,3.347],[-5.399,8.921],[-11.244,10.335],[-2.003,5.601],[0.162,2.889],[6.774,8.581],[-0.434,-2.706],[0.213,-1.349],[2.331,-2.667],[5.725,-5.434],[1.796,-1.698],[0.952,-0.714],[2.279,-2.261],[4.543,-5.459],[0.729,-1.698],[2.288,-9.461],[-1.972,-3.406],[-7.468,-6.795]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.828,-101.724],[54,-86],[56.744,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[103,-87],[108,-78],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[99,-34],[104,-39],[107,-40],[113,-48],[125,-64],[127,-71],[123,-94],[117,-101]],"c":true}],"h":1},{"t":56,"s":[{"i":[[12.291,-0.928],[0.334,0.01],[0.332,-0.013],[7.404,-4.223],[-0.424,-5.87],[-1.585,-1.63],[-2.5,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.118,-3.707],[1.809,-2.989],[6.743,-6.198],[3.75,-10.485],[-0.208,-3.713],[-1.091,-1.383],[2.067,12.881],[-0.361,2.289],[-1.78,2.037],[-2.428,2.305],[-5.434,5.059],[-0.68,0.664],[-2.148,2.482],[-1.904,2.579],[0.202,10.903],[1.709,2.951],[2.701,2.457]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.404,4.223],[0.159,2.197],[1.585,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[2.825,2.405],[0.107,3.347],[-5.399,8.921],[-11.244,10.335],[-2.003,5.601],[0.162,2.889],[6.774,8.581],[-0.434,-2.706],[0.207,-1.314],[2.331,-2.667],[7.595,-7.21],[0.69,-0.642],[2.343,-2.289],[2.151,-2.486],[4.975,-6.737],[-0.118,-6.386],[-1.971,-3.404],[-7.448,-6.777]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.828,-101.724],[54,-86],[56.744,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[108,-78],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[103,-38],[106,-39],[112,-47],[118,-54],[128,-79],[123,-94],[117,-101]],"c":true}],"h":1},{"t":57,"s":[{"i":[[12.291,-0.928],[0.334,0.01],[0.332,-0.013],[7.406,-4.223],[-0.432,-5.871],[-1.584,-1.63],[-2.502,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.882,-1.486],[-0.059,-1.853],[0.787,-1.708],[0.904,-1.495],[6.663,-6.125],[3.75,-10.485],[-0.208,-3.713],[-1.091,-1.383],[2.067,12.881],[-0.361,2.289],[-1.78,2.037],[-2.428,2.305],[-7.457,6.16],[-0.666,0.747],[0.293,15.788],[1.709,2.951],[2.701,2.457]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.406,4.223],[0.162,2.198],[1.584,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[1.412,1.203],[0.882,1.486],[0.053,1.673],[-0.787,1.708],[-5.368,8.869],[-11.244,10.335],[-2.003,5.601],[0.162,2.889],[6.774,8.581],[-0.434,-2.706],[0.207,-1.314],[2.331,-2.667],[8.916,-8.463],[0.788,-0.651],[8.101,-9.083],[-0.118,-6.386],[-1.971,-3.404],[-7.448,-6.777]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.821,-101.725],[54,-86],[56.745,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[106.515,-82.988],[108,-78],[106.719,-72.866],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[107,-41],[109,-43],[128,-79],[123,-94],[117,-101]],"c":true}],"h":1},{"t":58,"s":[{"i":[[12.291,-0.928],[0.334,0.01],[0.332,-0.013],[7.406,-4.223],[-0.432,-5.871],[-1.584,-1.63],[-2.502,-0.282],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.882,-1.486],[-0.059,-1.853],[0.787,-1.708],[0.904,-1.495],[6.663,-6.125],[3.75,-10.485],[-0.208,-3.713],[-1.091,-1.383],[2.067,12.881],[-0.361,2.289],[-1.78,2.037],[-2.428,2.305],[-7.457,6.16],[-0.666,0.747],[0.293,15.788],[1.709,2.951],[2.701,2.457]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.806,0.237],[-7.406,4.223],[0.162,2.198],[1.584,1.63],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[1.412,1.203],[0.882,1.486],[0.053,1.673],[-0.787,1.708],[-5.368,8.869],[-11.244,10.335],[-2.003,5.601],[0.162,2.889],[6.774,8.581],[-0.434,-2.706],[0.207,-1.314],[2.331,-2.667],[8.916,-8.463],[0.788,-0.651],[8.101,-9.083],[-0.118,-6.386],[-1.971,-3.404],[-7.448,-6.777]],"v":[[91,-109],[90.001,-108.991],[89,-109],[66.821,-101.725],[54,-86],[56.745,-80.063],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[106.515,-82.988],[108,-78],[106.719,-72.866],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[107,-41],[109,-43],[128,-79],[123,-94],[117,-101]],"c":true}],"h":1},{"t":59,"s":[{"i":[[0.233,-0.018],[0.334,0.01],[0.332,-0.013],[7.34,-4.074],[-0.087,-5.471],[-1.568,-1.799],[-2.689,-0.303],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.118,-3.707],[1.665,-2.75],[6.591,-6.058],[3.695,-10.333],[-0.208,-3.713],[-1.136,-1.439],[2.07,12.899],[-0.361,2.289],[-2.204,2.522],[-2.383,2.262],[-7.197,5.946],[-3.098,4.195],[0.194,10.463],[2.607,2.721],[3.203,1.444],[0.428,0.231],[6.327,0.288]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.729,0.234],[-7.339,4.074],[0.04,2.501],[1.568,1.799],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[2.825,2.405],[0.102,3.205],[-5.468,9.033],[-11.226,10.319],[-2.003,5.601],[0.162,2.892],[6.756,8.557],[-0.434,-2.706],[0.214,-1.36],[2.256,-2.581],[8.329,-7.906],[4.571,-3.776],[4.943,-6.693],[-0.111,-5.958],[-2.958,-3.088],[-0.358,-0.161],[-4.365,-2.357],[-0.963,-0.044]],"v":[[91,-109],[90.001,-108.991],[89,-109],[67.138,-101.928],[54,-87],[56.513,-80.352],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[108,-78],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[107,-41],[118,-54],[128,-79],[122,-96],[113,-104],[112,-106],[93,-110]],"c":true}],"h":1},{"t":60,"s":[{"i":[[12.291,-0.928],[0.334,0.01],[0.332,-0.013],[7.34,-4.074],[-0.087,-5.471],[-1.568,-1.799],[-2.689,-0.303],[-1.556,1.296],[-1.569,1.177],[-0.564,0.12],[-0.354,0.225],[-4.842,0.875],[-3.172,-2.701],[-0.882,-1.486],[-0.059,-1.853],[0.805,-1.756],[0.833,-1.375],[6.591,-6.058],[3.695,-10.333],[-0.208,-3.713],[-1.136,-1.439],[2.07,12.899],[-0.361,2.289],[-1.78,2.037],[-2.428,2.305],[-7.457,6.16],[-0.666,0.747],[0.293,15.788],[1.709,2.951],[2.701,2.457]],"o":[[-0.331,0.025],[-0.334,-0.01],[-5.729,0.234],[-7.339,4.074],[0.04,2.501],[1.568,1.799],[3.209,0.362],[1.556,-1.296],[0.392,-0.294],[0.564,-0.12],[3.46,-2.202],[4.842,-0.875],[1.412,1.203],[0.882,1.486],[0.051,1.602],[-0.805,1.756],[-5.468,9.033],[-11.226,10.319],[-2.003,5.601],[0.162,2.892],[6.756,8.557],[-0.434,-2.706],[0.207,-1.314],[2.331,-2.667],[8.916,-8.463],[0.788,-0.651],[8.101,-9.083],[-0.118,-6.386],[-1.971,-3.404],[-7.448,-6.777]],"v":[[91,-109],[90.001,-108.991],[89,-109],[67.138,-101.928],[54,-87],[56.513,-80.352],[63,-77],[69.73,-78.846],[74,-83],[75.529,-83.551],[77,-84],[90.216,-89.177],[103,-87],[106.515,-82.988],[108,-78],[106.663,-72.829],[104,-68],[82,-45],[54,-13],[52,-3],[56,9],[75,1],[72,-6],[78,-13],[85,-20],[107,-41],[109,-43],[128,-79],[123,-94],[117,-101]],"c":true}],"h":1}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":31,"op":300,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 4","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[43.313,-47.836],"ix":2},"a":{"a":0,"k":[43.313,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":31,"st":10,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 1","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[43.313,-47.836],"ix":2},"a":{"a":0,"k":[43.313,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":18,"st":10,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 5","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-78.173,-47.836],"ix":2},"a":{"a":0,"k":[-78.173,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":18,"op":24,"st":10,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Cup 2","parent":15,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.55,-73.91],[49.55,-73.91],[70.876,-52.583],[62.346,32.723],[-62.346,32.723],[-70.876,-52.583]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.705882370472,0.247058823705,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Cup","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Star 4 :M","parent":15,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[-225,-6.953,0],"to":[75,0,0],"ti":[-75,0,0]},{"t":50,"s":[225,-6.953,0]}],"ix":2,"l":2},"a":{"a":0,"k":[24.984,188.998,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.278,-3.874],[6.547,-0.032],[5.316,3.822],[2.054,6.217],[-1.993,6.237],[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237]],"o":[[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237],[5.278,-3.874],[6.547,-0.033],[5.316,3.822],[2.054,6.217],[-1.993,6.237]],"v":[[19.304,28.834],[0.146,23.68],[-18.962,29.022],[-19.98,9.209],[-30.965,-7.313],[-12.436,-14.404],[-0.118,-29.957],[12.352,-14.526],[30.95,-7.617],[20.128,9.011]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,188.998],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-200.016,188.998],"ix":2},"a":{"a":0,"k":[249.984,188.998],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star 4","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.278,-3.874],[6.547,-0.032],[5.316,3.822],[2.054,6.217],[-1.993,6.237],[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237]],"o":[[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237],[5.278,-3.874],[6.547,-0.033],[5.316,3.822],[2.054,6.217],[-1.993,6.237]],"v":[[19.304,28.834],[0.146,23.68],[-18.962,29.022],[-19.98,9.209],[-30.965,-7.313],[-12.436,-14.404],[-0.118,-29.957],[12.352,-14.526],[30.95,-7.617],[20.128,9.011]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,188.998],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-50.016,188.998],"ix":2},"a":{"a":0,"k":[249.984,188.998],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star 3","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.278,-3.874],[6.547,-0.032],[5.316,3.822],[2.054,6.217],[-1.993,6.237],[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237]],"o":[[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237],[5.278,-3.874],[6.547,-0.033],[5.316,3.822],[2.054,6.217],[-1.993,6.237]],"v":[[19.304,28.834],[0.146,23.68],[-18.962,29.022],[-19.98,9.209],[-30.965,-7.313],[-12.436,-14.404],[-0.118,-29.957],[12.352,-14.526],[30.95,-7.617],[20.128,9.011]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,188.998],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[99.984,188.998],"ix":2},"a":{"a":0,"k":[249.984,188.998],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.278,-3.874],[6.547,-0.032],[5.316,3.822],[2.054,6.217],[-1.993,6.237],[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237]],"o":[[-5.278,3.874],[-6.547,0.032],[-5.316,-3.822],[-2.054,-6.217],[1.993,-6.237],[5.278,-3.874],[6.547,-0.033],[5.316,3.822],[2.054,6.217],[-1.993,6.237]],"v":[[19.304,28.834],[0.146,23.68],[-18.962,29.022],[-19.98,9.209],[-30.965,-7.313],[-12.436,-14.404],[-0.118,-29.957],[12.352,-14.526],[30.95,-7.617],[20.128,9.011]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,188.998],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,188.998],"ix":2},"a":{"a":0,"k":[249.984,188.998],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Star","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Black Stand 2","parent":14,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-24.605,0],[0,0],[18.303,0]],"o":[[-18.303,0],[0,0],[24.605,0],[0,0]],"v":[[-42.653,-29.114],[-53.962,29.114],[53.962,29.114],[42.653,-29.114]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.349019616842,0.345098048449,0.43137255311,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Black Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"White Stand 4 :M","parent":14,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[-225,-1.544,0],"to":[75,0,0],"ti":[-75,0,0]},{"t":50,"s":[225,-1.544,0]}],"ix":2,"l":2},"a":{"a":0,"k":[24.984,347.302,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.323,0],[0,0],[-1.582,-4.024],[0,0],[4.323,0],[0,0],[-1.582,4.024],[0,0]],"o":[[0,0],[4.323,0],[0,0],[1.582,4.024],[0,0],[-4.323,0],[0,0],[1.582,-4.024]],"v":[[-25.949,-12.268],[25.998,-12.268],[33.803,-4.464],[37.313,4.464],[31.758,12.268],[-32.174,12.268],[-37.263,4.464],[-33.753,-4.464]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,347.302],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-200.016,347.302],"ix":2},"a":{"a":0,"k":[249.984,347.302],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand 4","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.323,0],[0,0],[-1.582,-4.024],[0,0],[4.323,0],[0,0],[-1.582,4.024],[0,0]],"o":[[0,0],[4.323,0],[0,0],[1.582,4.024],[0,0],[-4.323,0],[0,0],[1.582,-4.024]],"v":[[-25.949,-12.268],[25.998,-12.268],[33.803,-4.464],[37.313,4.464],[31.758,12.268],[-32.174,12.268],[-37.263,4.464],[-33.753,-4.464]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,347.302],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-50.016,347.302],"ix":2},"a":{"a":0,"k":[249.984,347.302],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand 3","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.323,0],[0,0],[-1.582,-4.024],[0,0],[4.323,0],[0,0],[-1.582,4.024],[0,0]],"o":[[0,0],[4.323,0],[0,0],[1.582,4.024],[0,0],[-4.323,0],[0,0],[1.582,-4.024]],"v":[[-25.949,-12.268],[25.998,-12.268],[33.803,-4.464],[37.313,4.464],[31.758,12.268],[-32.174,12.268],[-37.263,4.464],[-33.753,-4.464]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,347.302],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[99.984,347.302],"ix":2},"a":{"a":0,"k":[249.984,347.302],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.323,0],[0,0],[-1.582,-4.024],[0,0],[4.323,0],[0,0],[-1.582,4.024],[0,0]],"o":[[0,0],[4.323,0],[0,0],[1.582,4.024],[0,0],[-4.323,0],[0,0],[1.582,-4.024]],"v":[[-25.949,-12.268],[25.998,-12.268],[33.803,-4.464],[37.313,4.464],[31.758,12.268],[-32.174,12.268],[-37.263,4.464],[-33.753,-4.464]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,347.302],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[249.984,347.302],"ix":2},"a":{"a":0,"k":[249.984,347.302],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"White Stand","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Black Stand","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"k":[{"s":[90],"t":2,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[88.052],"t":3,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[83.09],"t":4,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[75.985],"t":5,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[67.277],"t":6,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[57.336],"t":7,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[46.447],"t":8,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[34.86],"t":9,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[10.836],"t":11,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":12,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.514],"t":13,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-10.253],"t":14,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-11.772],"t":15,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-11.657],"t":16,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-10.457],"t":17,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-8.646],"t":18,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-6.599],"t":19,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-4.592],"t":20,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-2.804],"t":21,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-1.336],"t":22,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.223],"t":23,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.544],"t":24,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.006],"t":25,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.219],"t":26,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.245],"t":27,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[1.142],"t":28,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.963],"t":29,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.75],"t":30,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.535],"t":31,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.34],"t":32,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.176],"t":33,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.049],"t":34,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.04],"t":35,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.097],"t":36,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.125],"t":37,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.132],"t":38,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.124],"t":39,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.107],"t":40,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.085],"t":41,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.062],"t":42,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.041],"t":43,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.023],"t":44,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.008],"t":45,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.002],"t":46,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.009],"t":47,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.013],"t":48,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.014],"t":49,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.013],"t":50,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.012],"t":51,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.01],"t":52,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.007],"t":53,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.005],"t":54,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.003],"t":55,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.001],"t":56,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":57,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":58,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":59,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":60,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":61,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":62,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":63,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[-0.001],"t":65,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":66,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":67,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":68,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0],"t":69,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"p":{"k":[{"s":[138.235,254.547,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[143.584,250.368,0],"t":1,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[157.812,240.556,0],"t":2,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[179.791,229.215,0],"t":3,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[209.087,221.759,0],"t":4,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[243.189,225.873,0],"t":5,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[274.404,246.799,0],"t":6,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[294.84,281.274,0],"t":7,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[299.502,322.507,0],"t":8,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[282.589,360.014,0],"t":9,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.984,377.959,0],"t":10,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[228.111,384.013,0],"t":11,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[215.555,387.488,0],"t":12,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[210.454,388.9,0],"t":13,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[210.841,388.792,0],"t":14,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[214.869,387.678,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[220.951,385.994,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[227.823,384.092,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[234.564,382.227,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[240.567,380.565,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[245.498,379.201,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.235,378.166,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[251.813,377.453,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[253.364,377.023,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[254.079,376.826,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[254.164,376.802,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[253.818,376.898,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[253.217,377.064,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[252.503,377.262,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[251.782,377.461,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[251.126,377.643,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[250.576,377.795,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[250.15,377.913,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.849,377.996,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.66,378.049,0],"t":34,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[249.909,377.98,0],"t":42,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[0,29.114,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[0,0,100]},{"t":10,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Elastic Controller","np":5,"mn":"Pseudo/MDS Elastic Controller","ix":1,"en":1,"ef":[{"ty":0,"nm":"Amplitude","mn":"Pseudo/MDS Elastic Controller-0001","ix":1,"v":{"a":0,"k":20,"ix":1}},{"ty":0,"nm":"Frequency","mn":"Pseudo/MDS Elastic Controller-0002","ix":2,"v":{"a":0,"k":40,"ix":2}},{"ty":0,"nm":"Decay","mn":"Pseudo/MDS Elastic Controller-0003","ix":3,"v":{"a":0,"k":60,"ix":3}}]},{"ty":5,"nm":"Elastic Controller 2","np":5,"mn":"Pseudo/MDS Elastic Controller","ix":2,"en":1,"ef":[{"ty":0,"nm":"Amplitude","mn":"Pseudo/MDS Elastic Controller-0001","ix":1,"v":{"a":0,"k":20,"ix":1}},{"ty":0,"nm":"Frequency","mn":"Pseudo/MDS Elastic Controller-0002","ix":2,"v":{"a":0,"k":40,"ix":2}},{"ty":0,"nm":"Decay","mn":"Pseudo/MDS Elastic Controller-0003","ix":3,"v":{"a":0,"k":60,"ix":3}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-24.605,0],[0,0],[18.303,0]],"o":[[-18.303,0],[0,0],[24.605,0],[0,0]],"v":[[-42.653,-29.114],[-53.962,29.114],[53.962,29.114],[42.653,-29.114]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.349019616842,0.345098048449,0.43137255311,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Black Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Cup","parent":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-152.895,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.815,0],[0,0],[1.176,-11.756],[0,0],[5.492,54.916],[0,0]],"o":[[0,0],[11.815,0],[0,0],[-5.492,54.916],[0,0],[-1.176,-11.756]],"v":[[-49.55,-73.91],[49.55,-73.91],[70.876,-52.583],[62.346,32.723],[-62.346,32.723],[-70.876,-52.583]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.705882370472,0.247058823705,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Cup","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Stand","parent":14,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-56.636,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[19.235,36.65],[0,0],[-15.853,-38.082],[0,0]],"o":[[0,0],[-20.405,35.342],[0,0],[17.561,-38.659]],"v":[[-33.841,-56.55],[33.841,-56.55],[25.31,56.55],[-25.31,56.55]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.525490224361,0.270588248968,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Stand","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":310,"st":10,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 3","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[43.313,-47.836],"ix":2},"a":{"a":0,"k":[43.313,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":18,"op":24,"st":10,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 6","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-78.173,-47.836],"ix":2},"a":{"a":0,"k":[-78.173,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":310,"st":10,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 2","parent":15,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.016,54.049,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":10,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":18,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]},{"i":{"x":0,"y":1},"o":{"x":0.333,"y":0},"t":24,"s":[{"i":[[0,0],[11.928,-26.533],[-4,-20],[1.5,-2]],"o":[[-4.5,-7],[-12.25,27.25],[0.88,4.401],[-1.5,2]],"v":[[-64.5,-87],[-116.25,-85.75],[-62.5,-7],[-65.5,4]],"c":false}]},{"t":50,"s":[{"i":[[0,0],[-11.928,-26.533],[4,-20],[-1.5,-2]],"o":[[4.5,-7],[12.25,27.25],[-0.88,4.401],[1.5,2]],"v":[[64.42,-87],[116.17,-85.75],[62.42,-7],[65.42,4]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.525490196078,0.270588235294,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":20,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-78.173,-47.836],"ix":2},"a":{"a":0,"k":[-78.173,-47.836],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":18,"st":10,"bm":0},{"ddd":0,"ind":21,"ty":0,"nm":"Pre-comp 1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":60,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":16,"op":316,"st":16,"bm":0},{"ddd":0,"ind":22,"ty":0,"nm":"Pre-comp 1","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":45,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":11,"op":311,"st":11,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/res/values-night/ic_launcher_background.xml b/app/src/main/res/values-night/ic_launcher_background.xml
new file mode 100644
index 0000000..c0f8818
--- /dev/null
+++ b/app/src/main/res/values-night/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #000
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v31/themes.xml b/app/src/main/res/values-v31/themes.xml
new file mode 100644
index 0000000..2ce2d86
--- /dev/null
+++ b/app/src/main/res/values-v31/themes.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..c5d5899
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..9f77183
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ hydro
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..3f286bc
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..6cebe05
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..7012ee7
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,8 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id "com.android.application" version "8.1.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.9.0" apply false
+ id "org.jetbrains.kotlin.plugin.serialization" version "1.9.0" apply false
+ id "com.google.devtools.ksp" version "1.9.0-1.0.13" apply false
+ id "org.jlleitschuh.gradle.ktlint" version "11.3.2" apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..3c5031e
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,23 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..df7f0c0
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Jul 12 18:38:17 CEST 2023
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..4f906e0
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..ac1b06f
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..088beb9
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,16 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+rootProject.name = "hydro"
+include ':app'