├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── font
│ │ │ │ ├── inter_bold.ttf
│ │ │ │ ├── inter_medium.ttf
│ │ │ │ └── inter_regular.ttf
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── values
│ │ │ │ ├── colors.xml
│ │ │ │ ├── themes.xml
│ │ │ │ └── strings.xml
│ │ │ ├── xml
│ │ │ │ ├── backup_rules.xml
│ │ │ │ └── data_extraction_rules.xml
│ │ │ ├── drawable
│ │ │ │ ├── ic_back_arrow.xml
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ └── which_one_logo.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── raw
│ │ │ │ ├── force_update_store_anim.json
│ │ │ │ └── opps_anim.json
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── loftymr
│ │ │ │ └── whichone
│ │ │ │ ├── domain
│ │ │ │ ├── viewstate
│ │ │ │ │ ├── ViewData.kt
│ │ │ │ │ ├── splash
│ │ │ │ │ │ └── SplashViewState.kt
│ │ │ │ │ └── survey
│ │ │ │ │ │ └── SurveyViewState.kt
│ │ │ │ └── repository
│ │ │ │ │ └── SurveyRepository.kt
│ │ │ │ ├── data
│ │ │ │ ├── remote
│ │ │ │ │ ├── util
│ │ │ │ │ │ └── DataState.kt
│ │ │ │ │ ├── api
│ │ │ │ │ │ └── SurveyService.kt
│ │ │ │ │ └── source
│ │ │ │ │ │ └── BaseRemoteDataSource.kt
│ │ │ │ ├── di
│ │ │ │ │ ├── ServiceModule.kt
│ │ │ │ │ ├── AppModule.kt
│ │ │ │ │ └── RemoteDataModule.kt
│ │ │ │ └── model
│ │ │ │ │ └── RingsOfThePowerResponse.kt
│ │ │ │ ├── feature
│ │ │ │ ├── theme
│ │ │ │ │ ├── Shape.kt
│ │ │ │ │ ├── Color.kt
│ │ │ │ │ ├── Type.kt
│ │ │ │ │ └── Theme.kt
│ │ │ │ ├── component
│ │ │ │ │ ├── WhichOneLottieAnim.kt
│ │ │ │ │ ├── WhichOneTemplate.kt
│ │ │ │ │ ├── WhichOneButton.kt
│ │ │ │ │ ├── CircularProgressAnimated.kt
│ │ │ │ │ ├── WhichOneTopBar.kt
│ │ │ │ │ ├── Head.kt
│ │ │ │ │ ├── StepsProgressBar.kt
│ │ │ │ │ ├── SelectionBox.kt
│ │ │ │ │ └── AdsView.kt
│ │ │ │ ├── screen
│ │ │ │ │ ├── splash
│ │ │ │ │ │ ├── SplashViewModel.kt
│ │ │ │ │ │ └── SplashActivity.kt
│ │ │ │ │ ├── main
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ │ ├── forceupdate
│ │ │ │ │ │ └── ForceUpdateScreen.kt
│ │ │ │ │ ├── survey
│ │ │ │ │ │ ├── SurveyViewModel.kt
│ │ │ │ │ │ └── SurveyScreen.kt
│ │ │ │ │ └── result
│ │ │ │ │ │ └── ResultScreen.kt
│ │ │ │ ├── base
│ │ │ │ │ └── BaseViewModel.kt
│ │ │ │ └── navigation
│ │ │ │ │ └── NavGraph.kt
│ │ │ │ ├── util
│ │ │ │ ├── extension
│ │ │ │ │ └── Modifier.kt
│ │ │ │ └── ForceUpdateChecker.kt
│ │ │ │ └── WhichOneApp.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── loftymr
│ │ │ └── whichone
│ │ │ └── ExampleUnitTest.kt
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── loftymr
│ │ └── whichone
│ │ └── ExampleInstrumentedTest.kt
├── proguard-rules.pro
└── build.gradle
├── .github
└── FUNDING.yml
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
├── LICENSE
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [tfaki]
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/font/inter_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/font/inter_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/font/inter_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/font/inter_medium.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/inter_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/font/inter_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tfaki/WhichOne-Android/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/domain/viewstate/ViewData.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.domain.viewstate
2 |
3 | /**
4 | * Created by talhafaki on 9.09.2022.
5 | */
6 |
7 | interface WhichOneViewState
8 | interface WhichOneViewEvent
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 09 13:08:31 TRT 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/domain/viewstate/splash/SplashViewState.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.domain.viewstate.splash
2 |
3 | import com.loftymr.whichone.domain.viewstate.WhichOneViewState
4 |
5 | /**
6 | * Created by talhafaki on 9.09.2022.
7 | */
8 |
9 | data class SplashViewState(
10 | val isLoading: Boolean = false
11 | ) : WhichOneViewState
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/remote/util/DataState.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.remote.util
2 |
3 | /**
4 | * Created by talhafaki on 9.09.2022.
5 | */
6 |
7 | sealed class DataState {
8 | class Success(val data: T) : DataState()
9 | class Loading : DataState()
10 | class Error(val exception: Exception) : DataState()
11 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 | rootProject.name = "WhichOne"
16 | include ':app'
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/theme/Shape.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.theme
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.material.Shapes
5 | import androidx.compose.ui.unit.dp
6 |
7 | val Shapes = Shapes(
8 | small = RoundedCornerShape(4.dp),
9 | medium = RoundedCornerShape(4.dp),
10 | large = RoundedCornerShape(0.dp)
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/app/src/test/java/com/loftymr/whichone/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/domain/viewstate/survey/SurveyViewState.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.domain.viewstate.survey
2 |
3 | import com.loftymr.whichone.data.model.RingsOfThePowerResponse
4 | import com.loftymr.whichone.domain.viewstate.WhichOneViewState
5 |
6 | /**
7 | * Created by talhafaki on 9.09.2022.
8 | */
9 |
10 | data class SurveyViewState(
11 | var isLoading: Boolean = false,
12 | val isError: Boolean = false,
13 | val data: RingsOfThePowerResponse? = null
14 | ) : WhichOneViewState
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/remote/api/SurveyService.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.remote.api
2 |
3 | import com.loftymr.whichone.data.model.RingsOfThePowerResponse
4 | import retrofit2.Response
5 | import retrofit2.http.GET
6 | import retrofit2.http.Query
7 |
8 | /**
9 | * Created by talhafaki on 9.09.2022.
10 | */
11 |
12 | interface SurveyService {
13 | @GET("")
14 | suspend fun getRingsOfThePowerSurveys(
15 | @Query("count") count: Int = 10
16 | ): Response
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/di/ServiceModule.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.di
2 |
3 | import com.loftymr.whichone.data.remote.api.SurveyService
4 | import dagger.Module
5 | import dagger.Provides
6 | import dagger.hilt.InstallIn
7 | import dagger.hilt.android.components.ViewModelComponent
8 | import retrofit2.Retrofit
9 |
10 | /**
11 | * Created by talhafaki on 9.09.2022.
12 | */
13 |
14 | @Module
15 | @InstallIn(ViewModelComponent::class)
16 | class ServiceModule {
17 |
18 | @Provides
19 | fun provideSurveyService(retrofit: Retrofit): SurveyService =
20 | retrofit.create(SurveyService::class.java)
21 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/util/extension/Modifier.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.util.extension
2 |
3 | import androidx.compose.foundation.clickable
4 | import androidx.compose.foundation.interaction.MutableInteractionSource
5 | import androidx.compose.runtime.remember
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.composed
8 |
9 | /**
10 | * Created by talhafaki on 13.09.2022.
11 | */
12 |
13 | inline fun Modifier.noRippleClickable(crossinline onClick: ()->Unit): Modifier = composed {
14 | clickable(indication = null,
15 | interactionSource = remember { MutableInteractionSource() }) {
16 | onClick()
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.di
2 |
3 | import android.content.Context
4 | import com.loftymr.whichone.WhichOneApp
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.qualifiers.ApplicationContext
9 | import dagger.hilt.components.SingletonComponent
10 | import javax.inject.Singleton
11 |
12 | /**
13 | * Created by talhafaki on 9.09.2022.
14 | */
15 |
16 | @Module
17 | @InstallIn(SingletonComponent::class)
18 | class AppModule {
19 |
20 | @Singleton
21 | @Provides
22 | fun provideApplication(@ApplicationContext app: Context): WhichOneApp {
23 | return app as WhichOneApp
24 | }
25 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/loftymr/whichone/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.loftymr.whichone", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/domain/repository/SurveyRepository.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.domain.repository
2 |
3 | import com.loftymr.whichone.data.model.RingsOfThePowerResponse
4 | import com.loftymr.whichone.data.remote.source.BaseRemoteDataSource
5 | import com.loftymr.whichone.data.remote.api.SurveyService
6 | import com.loftymr.whichone.data.remote.util.DataState
7 | import kotlinx.coroutines.flow.Flow
8 | import javax.inject.Inject
9 |
10 | /**
11 | * Created by talhafaki on 9.09.2022.
12 | */
13 |
14 | class SurveyRepository @Inject constructor(
15 | private val surveyService: SurveyService
16 | ) : BaseRemoteDataSource() {
17 |
18 | suspend fun ringsOfThePowerSurvey(): Flow> =
19 | getResult {
20 | surveyService.getRingsOfThePowerSurveys()
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | object SurveyColor {
6 | val Purple200 = Color(0xFFBB86FC)
7 | val Purple500 = Color(0xFF6200EE)
8 | val Purple700 = Color(0xFF3700B3)
9 | val Teal200 = Color(0xFF03DAC5)
10 |
11 | val SolidBlue = Color(0xFF3552A2)
12 | val Black = Color(0xFF000000)
13 | val DarkGray = Color(0xFF444444)
14 | val Gray = Color(0xFF888888)
15 | val LightGray = Color(0xFFCCCCCC)
16 | val White = Color(0xFFFFFFFF)
17 | val Red = Color(0xFFFF0000)
18 | val Green = Color(0xFF00FF00)
19 | val Blue = Color(0xFF0000FF)
20 | val Yellow = Color(0xFFFFFF00)
21 | val Transparent = Color(0x00000000)
22 | val DeepBlue = Color(0xFF005A70)
23 | val Alabaster = Color(0xFFFAFAFA)
24 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | WhichOne
3 |
4 | ca-app-pub-3940256099942544/6300978111
5 |
6 | ca-app-pub-3940256099942544/8691691433
7 |
8 | Something went wrong!
9 | RETRY
10 | AGAIN
11 |
12 |
13 | Rings Of Power
14 |
15 |
16 |
17 | New version available
18 | Please, update app to new version to continue reposting.
19 | Go To Play Store
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Talha Fakıoğlu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/WhichOneLottieAnim.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.annotation.RawRes
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.foundation.layout.height
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Modifier
8 | import androidx.compose.ui.unit.dp
9 | import com.airbnb.lottie.compose.*
10 |
11 | /**
12 | * Created by talhafaki on 13.09.2022.
13 | */
14 |
15 | @Composable
16 | fun WhichOneAnim(modifier: Modifier = Modifier, @RawRes rawResId: Int) {
17 | val composition =
18 | rememberLottieComposition(LottieCompositionSpec.RawRes(rawResId))
19 |
20 | val progress = animateLottieCompositionAsState(
21 | composition.value,
22 | iterations = LottieConstants.IterateForever,
23 | speed = 1f,
24 | restartOnPlay = false
25 | )
26 |
27 | LottieAnimation(
28 | composition = composition.value,
29 | progress = progress.value,
30 | modifier = modifier
31 | .fillMaxWidth()
32 | .height(300.dp)
33 | )
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/WhichOneTemplate.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Box
5 | import androidx.compose.foundation.layout.PaddingValues
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.material.Scaffold
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Modifier
10 | import com.loftymr.whichone.feature.theme.SurveyColor
11 |
12 | /**
13 | * Created by talhafaki on 13.09.2022.
14 | */
15 |
16 | @Composable
17 | fun WhichOneTemplate(
18 | topBar: @Composable () -> Unit = {},
19 | content: @Composable (PaddingValues) -> Unit
20 | ) {
21 | Box(
22 | modifier = Modifier
23 | .fillMaxSize()
24 | ) {
25 | Scaffold(
26 | backgroundColor = SurveyColor.Transparent,
27 | content = content,
28 | topBar = topBar,
29 | modifier = Modifier
30 | .fillMaxSize()
31 | .background(color = SurveyColor.SolidBlue)
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/splash/SplashViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.splash
2 |
3 | import androidx.lifecycle.viewModelScope
4 | import com.loftymr.whichone.feature.base.BaseViewModel
5 | import com.loftymr.whichone.domain.viewstate.WhichOneViewEvent
6 | import com.loftymr.whichone.domain.viewstate.splash.SplashViewState
7 | import dagger.hilt.android.lifecycle.HiltViewModel
8 | import kotlinx.coroutines.delay
9 | import kotlinx.coroutines.launch
10 | import javax.inject.Inject
11 |
12 | /**
13 | * Created by talhafaki on 9.09.2022.
14 | */
15 |
16 | @HiltViewModel
17 | class SplashViewModel @Inject constructor(
18 | ) : BaseViewModel() {
19 |
20 | init {
21 | viewModelScope.launch {
22 | delay(1000)
23 | setEvent(SplashViewEvent.DirectToDashBoard)
24 | }
25 | }
26 |
27 | override fun createInitialState() = SplashViewState()
28 | override fun onTriggerEvent(event: SplashViewEvent) {}
29 | }
30 |
31 | sealed class SplashViewEvent : WhichOneViewEvent {
32 | object DirectToDashBoard : SplashViewEvent()
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.theme
2 |
3 | import androidx.compose.material.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.Font
6 | import androidx.compose.ui.text.font.FontFamily
7 | import androidx.compose.ui.text.font.FontWeight
8 | import androidx.compose.ui.unit.sp
9 | import com.loftymr.whichone.R
10 |
11 | // Set of Material typography styles to start with
12 | val Fonts = FontFamily(
13 | Font(R.font.inter_bold),
14 | Font(R.font.inter_medium),
15 | Font(R.font.inter_regular)
16 | )
17 |
18 | val Typography = Typography(
19 | body1 = TextStyle(
20 | fontFamily = Fonts,
21 | fontWeight = FontWeight.Normal,
22 | fontSize = 16.sp,
23 | color = SurveyColor.Black
24 | ),
25 | h1 = TextStyle(
26 | fontFamily = Fonts,
27 | fontWeight = FontWeight.Bold,
28 | fontSize = 16.sp,
29 | color = SurveyColor.Black
30 | ),
31 | body2 = TextStyle(
32 | fontFamily = Fonts,
33 | fontWeight = FontWeight.Medium,
34 | fontSize = 16.sp,
35 | color = SurveyColor.Black
36 | )
37 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/remote/source/BaseRemoteDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.remote.source
2 |
3 | import com.loftymr.whichone.data.remote.util.DataState
4 | import kotlinx.coroutines.Dispatchers
5 | import kotlinx.coroutines.flow.*
6 | import retrofit2.Response
7 | import java.lang.Exception
8 |
9 | /**
10 | * Created by talhafaki on 9.09.2022.
11 | */
12 |
13 | open class BaseRemoteDataSource {
14 | protected suspend fun getResult(call: suspend () -> Response): Flow> {
15 | return flow> {
16 | val response = call()
17 | if (response.isSuccessful) {
18 | val body = response.body()
19 | if (body != null) emit(DataState.Success(body))
20 | else {
21 | emit(DataState.Error(exception = Exception("Something went wrong")))
22 | }
23 | } else {
24 | emit(DataState.Error(exception = Exception("Something went wrong")))
25 | }
26 |
27 | }
28 | .catch {
29 | emit(DataState.Error(exception = Exception(it.message ?: "Something went wrong")))
30 | }
31 | .onStart { emit(DataState.Loading()) }
32 | .flowOn(Dispatchers.IO)
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/model/RingsOfThePowerResponse.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.model
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | /**
6 | * Created by talhafaki on 9.09.2022.
7 | */
8 |
9 | data class RingsOfThePowerResponse(
10 | @SerializedName("questions")
11 | val questions: List? = null,
12 | @SerializedName("charecter")
13 | val character: Character? = null,
14 | @SerializedName("backGroundPictures")
15 | val backgroundPictures: List? = null
16 | )
17 |
18 | data class Questions(
19 | @SerializedName("id")
20 | val id: String? = null,
21 | @SerializedName("questionText")
22 | val questionText: String? = null,
23 | @SerializedName("choices")
24 | val choices: List? = null
25 | )
26 |
27 | data class Character(
28 | @SerializedName("title")
29 | val title: String? = null,
30 | @SerializedName("srcset")
31 | val srcSet: SrcSet? = null,
32 | @SerializedName("description")
33 | val description: String? = null
34 | )
35 |
36 | data class SrcSet(
37 | @SerializedName("320w")
38 | val threeHundred: String? = null,
39 | @SerializedName("480w")
40 | val fourHundred: String? = null,
41 | @SerializedName("650w")
42 | val sixHundred: String? = null,
43 | @SerializedName("970w")
44 | val nineHundred: String? = null
45 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material.MaterialTheme
5 | import androidx.compose.material.darkColors
6 | import androidx.compose.material.lightColors
7 | import androidx.compose.runtime.Composable
8 |
9 | private val DarkColorPalette = darkColors(
10 | primary = SurveyColor.Purple200,
11 | primaryVariant = SurveyColor.Purple700,
12 | secondary = SurveyColor.Teal200
13 | )
14 |
15 | private val LightColorPalette = lightColors(
16 | primary = SurveyColor.Purple500,
17 | primaryVariant = SurveyColor.Purple700,
18 | secondary = SurveyColor.Teal200
19 |
20 | /* Other default colors to override
21 | background = Color.White,
22 | surface = Color.White,
23 | onPrimary = Color.White,
24 | onSecondary = Color.Black,
25 | onBackground = Color.Black,
26 | onSurface = Color.Black,
27 | */
28 | )
29 |
30 | @Composable
31 | fun WhichOneTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
32 | val colors = if (darkTheme) {
33 | DarkColorPalette
34 | } else {
35 | LightColorPalette
36 | }
37 |
38 | MaterialTheme(
39 | colors = colors,
40 | typography = Typography,
41 | shapes = Shapes,
42 | content = content
43 | )
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/WhichOneApp.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import com.google.firebase.FirebaseApp
6 | import com.google.firebase.remoteconfig.FirebaseRemoteConfig
7 | import com.loftymr.whichone.util.ForceUpdateChecker
8 | import dagger.hilt.android.HiltAndroidApp
9 |
10 |
11 | /**
12 | * Created by talhafaki on 9.09.2022.
13 | */
14 |
15 | @HiltAndroidApp
16 | class WhichOneApp : Application() {
17 |
18 | override fun onCreate() {
19 | super.onCreate()
20 |
21 | val firebaseRemoteConfig: FirebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
22 |
23 | // set in-app defaults
24 | val remoteConfigDefaults: MutableMap = HashMap()
25 | remoteConfigDefaults[ForceUpdateChecker.KEY_UPDATE_REQUIRED] = false
26 | remoteConfigDefaults[ForceUpdateChecker.KEY_CURRENT_VERSION] = "1.0.0"
27 | remoteConfigDefaults[ForceUpdateChecker.KEY_UPDATE_URL] =
28 | "https://play.google.com/store/apps/details?id=com.fribbleapp.mathriddles&hl=tr&gl=US"
29 | firebaseRemoteConfig.setDefaultsAsync(remoteConfigDefaults)
30 | firebaseRemoteConfig.fetch(60) // fetch every minutes
31 | .addOnCompleteListener {
32 | if (it.isSuccessful) {
33 | firebaseRemoteConfig.fetchAndActivate()
34 | }
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 |
25 | BASE_URL = ""
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/splash/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.splash
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.viewModels
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
9 | import androidx.lifecycle.lifecycleScope
10 | import com.loftymr.whichone.feature.screen.main.MainActivity
11 |
12 | /**
13 | * Created by talhafaki on 9.09.2022.
14 | */
15 | @SuppressLint("CustomSplashScreen")
16 | class SplashActivity : AppCompatActivity() {
17 | private val viewModel by viewModels()
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | val splashScreen = installSplashScreen()
21 | super.onCreate(savedInstanceState)
22 | splashScreen.setKeepOnScreenCondition { true }
23 |
24 | lifecycleScope.launchWhenCreated {
25 | viewModel.uiEvent.collect {
26 | when (it) {
27 | is SplashViewEvent.DirectToDashBoard -> {
28 | startMainActivity()
29 | finish()
30 | }
31 | }
32 | }
33 | }
34 | }
35 |
36 | private fun startMainActivity() {
37 | val intent =
38 | Intent(Intent.ACTION_VIEW).setClassName(packageName, MainActivity::class.java.name)
39 | startActivity(intent)
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/WhichOneButton.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.foundation.shape.RoundedCornerShape
5 | import androidx.compose.material.*
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.unit.dp
10 | import androidx.compose.ui.unit.sp
11 | import com.loftymr.whichone.feature.theme.SurveyColor
12 |
13 | /**
14 | * Created by talhafaki on 13.09.2022.
15 | */
16 |
17 | @Composable
18 | fun WhichOneButton(modifier: Modifier = Modifier, buttonText: String, onClick: () -> Unit) {
19 | Card(
20 | modifier = modifier
21 | .fillMaxWidth()
22 | .height(50.dp)
23 | .padding(horizontal = 16.dp),
24 | elevation = 10.dp,
25 | shape = RoundedCornerShape(8.dp)
26 | ) {
27 | Button(
28 | onClick = { onClick.invoke() },
29 | modifier = Modifier
30 | .fillMaxSize(),
31 | colors = ButtonDefaults.buttonColors(backgroundColor = SurveyColor.Alabaster)
32 | ) {
33 | Text(
34 | text = buttonText,
35 | modifier = Modifier
36 | .fillMaxSize()
37 | .wrapContentSize(align = Alignment.Center),
38 | style = MaterialTheme.typography.h1.copy(
39 | fontSize = 18.sp,
40 | color = SurveyColor.SolidBlue
41 | )
42 | )
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/base/BaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.base
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import com.loftymr.whichone.domain.viewstate.WhichOneViewEvent
6 | import com.loftymr.whichone.domain.viewstate.WhichOneViewState
7 | import kotlinx.coroutines.flow.*
8 | import kotlinx.coroutines.launch
9 |
10 | /**
11 | * Created by talhafaki on 9.09.2022.
12 | */
13 | abstract class BaseViewModel : ViewModel() {
14 |
15 | private val initialState: State by lazy { createInitialState() }
16 | abstract fun createInitialState(): State
17 |
18 | val currentState: State get() = uiState.value
19 |
20 | abstract fun onTriggerEvent(event: Event)
21 |
22 | private val _uiState: MutableStateFlow = MutableStateFlow(initialState)
23 | val uiState: StateFlow = _uiState
24 |
25 | private val _uiEvent: MutableSharedFlow = MutableSharedFlow()
26 | val uiEvent = _uiEvent.asSharedFlow()
27 |
28 | protected fun setState(reduce: State.() -> State) {
29 | val newState = currentState.reduce()
30 | _uiState.value = newState
31 | }
32 |
33 | protected fun setEvent(event: Event) {
34 | viewModelScope.launch { _uiEvent.emit(event) }
35 | }
36 |
37 | protected suspend fun call(
38 | callFlow: Flow,
39 | completionHandler: (collect: T) -> Unit = {}
40 | ) {
41 | callFlow
42 | .catch { }
43 | .collect {
44 | completionHandler.invoke(it)
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/CircularProgressAnimated.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.animation.core.animateFloat
4 | import androidx.compose.animation.core.infiniteRepeatable
5 | import androidx.compose.animation.core.rememberInfiniteTransition
6 | import androidx.compose.animation.core.tween
7 | import androidx.compose.foundation.background
8 | import androidx.compose.foundation.layout.Box
9 | import androidx.compose.foundation.layout.fillMaxSize
10 | import androidx.compose.foundation.layout.wrapContentSize
11 | import androidx.compose.material.CircularProgressIndicator
12 | import androidx.compose.runtime.Composable
13 | import androidx.compose.runtime.getValue
14 | import androidx.compose.ui.Alignment
15 | import androidx.compose.ui.Modifier
16 | import com.loftymr.whichone.feature.theme.SurveyColor
17 |
18 | /**
19 | * Created by talhafaki on 13.09.2022.
20 | */
21 |
22 | @Composable
23 | fun CircularProgressAnimated(modifier: Modifier = Modifier) {
24 | val progressValue = 1f
25 | val infiniteTransition = rememberInfiniteTransition()
26 |
27 | val progressAnimationValue by infiniteTransition.animateFloat(
28 | initialValue = 0.0f,
29 | targetValue = progressValue, animationSpec = infiniteRepeatable(animation = tween(900))
30 | )
31 |
32 | Box(
33 | modifier = modifier
34 | .fillMaxSize()
35 | .background(color = SurveyColor.SolidBlue),
36 | contentAlignment = Alignment.Center
37 | ) {
38 | CircularProgressIndicator(
39 | progress = progressAnimationValue,
40 | modifier = Modifier
41 | .wrapContentSize(),
42 | color = SurveyColor.White.copy(alpha = 0.8f)
43 | )
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/WhichOneTopBar.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.clickable
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.foundation.layout.padding
8 | import androidx.compose.material.MaterialTheme
9 | import androidx.compose.material.Text
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.res.painterResource
15 | import androidx.compose.ui.text.style.TextAlign
16 | import androidx.compose.ui.unit.dp
17 | import com.loftymr.whichone.R
18 | import com.loftymr.whichone.feature.theme.SurveyColor
19 |
20 | /**
21 | * Created by talhafaki on 13.09.2022.
22 | */
23 |
24 | @Composable
25 | fun WhichOneTopBar(
26 | title: String,
27 | backButtonEnabled: Boolean = true,
28 | clickBack: () -> Unit = {}
29 | ) {
30 | Box(
31 | modifier = Modifier
32 | .fillMaxWidth()
33 | ) {
34 | if (backButtonEnabled) {
35 | Image(
36 | painter = painterResource(id = R.drawable.ic_back_arrow),
37 | contentDescription = "",
38 | modifier = Modifier
39 | .align(Alignment.TopStart)
40 | .padding(start = 16.dp)
41 | .clickable {
42 | clickBack.invoke()
43 | }
44 | )
45 | }
46 |
47 | Text(
48 | text = title,
49 | style = MaterialTheme.typography.body1.copy(color = SurveyColor.White),
50 | textAlign = TextAlign.Center,
51 | modifier = Modifier
52 | .fillMaxWidth()
53 | .align(Alignment.Center)
54 | )
55 | }
56 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/Head.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.animation.core.animateFloatAsState
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.Card
8 | import androidx.compose.material3.CardDefaults
9 | import androidx.compose.material3.LinearProgressIndicator
10 | import androidx.compose.material3.ProgressIndicatorDefaults
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.getValue
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.layout.ContentScale
15 | import androidx.compose.ui.unit.dp
16 | import coil.compose.rememberImagePainter
17 | import com.loftymr.whichone.feature.theme.SurveyColor
18 |
19 | /**
20 | * Created by talhafaki on 9.09.2022.
21 | */
22 |
23 | @Composable
24 | fun Head(imageSource: String, numberOfSteps: Int, currentStep: Int) {
25 | val animatedProgress by animateFloatAsState(
26 | targetValue = (currentStep + 1) / (numberOfSteps + 1).toFloat(),
27 | animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec
28 | )
29 | Card(
30 | modifier = Modifier
31 | .fillMaxWidth()
32 | .height(250.dp)
33 | .padding(16.dp),
34 | shape = RoundedCornerShape(8.dp),
35 | elevation = CardDefaults.cardElevation(10.dp)
36 | ) {
37 | Image(
38 | painter = rememberImagePainter(imageSource),
39 | contentDescription = "",
40 | contentScale = ContentScale.Crop,
41 | modifier = Modifier
42 | .fillMaxSize()
43 | )
44 | }
45 | Spacer(modifier = Modifier.height(8.dp))
46 | LinearProgressIndicator(
47 | progress = animatedProgress,
48 | modifier = Modifier
49 | .fillMaxWidth()
50 | .padding(horizontal = 20.dp),
51 | color = SurveyColor.DeepBlue,
52 | trackColor = SurveyColor.DeepBlue.copy(alpha = 0.12f),
53 | )
54 | Spacer(modifier = Modifier.height(12.dp))
55 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | #OKHTTP
24 | -keepattributes Signature
25 | -keepattributes *Annotation*
26 | -keep class okhttp3.** { *; }
27 | -keep interface okhttp3.** { *; }
28 | -dontwarn okhttp3.**
29 | -dontwarn Java.nio.file.*
30 |
31 | #Gson
32 | -keep class com.google.gson.stream.** { *; }
33 |
34 | #Retrofit
35 | -keep class com.google.gson.** { *; }
36 | -keep public class com.google.gson.** {public private protected *;}
37 | -keep class com.google.inject.** { *; }
38 | -keep class org.apache.http.** { *; }
39 | -keep class org.apache.james.mime4j.** { *; }
40 | -keep class javax.inject.** { *; }
41 | -keep class javax.xml.stream.** { *; }
42 | -keep class retrofit.** { *; }
43 | -keep class com.google.appengine.** { *; }
44 | -keepattributes *Annotation*
45 | -keepattributes Signature
46 | -dontwarn com.squareup.okhttp.*
47 | -dontwarn javax.xml.stream.**
48 | -dontwarn com.google.appengine.**
49 | -dontwarn java.nio.file.**
50 | -dontwarn org.codehaus.**
51 |
52 | -keep class com.loftymr.whichone.feature.screen.splash.SplashActivity
53 | -keep class com.loftymr.whichone.feature.screen.main.MainActivity
54 | -keep class com.loftymr.whichone.data.model.Character
55 | -keep class com.loftymr.whichone.data.model.Questions
56 | -keep class com.loftymr.whichone.data.model.RingsOfThePowerResponse
57 | -keep class com.loftymr.whichone.data.model.SrcSet
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/StepsProgressBar.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.foundation.Canvas
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.layout.Box
6 | import androidx.compose.foundation.layout.Row
7 | import androidx.compose.foundation.layout.size
8 | import androidx.compose.foundation.shape.CircleShape
9 | import androidx.compose.material.Divider
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Alignment
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.graphics.Color
14 | import androidx.compose.ui.unit.dp
15 | import com.loftymr.whichone.feature.theme.SurveyColor
16 |
17 | /**
18 | * Created by talhafaki on 13.09.2022.
19 | */
20 |
21 | @Composable
22 | fun StepsProgressBar(modifier: Modifier = Modifier, numberOfSteps: Int, currentStep: Int) {
23 | Row(
24 | modifier = modifier,
25 | verticalAlignment = Alignment.CenterVertically
26 | ) {
27 | for (step in 0..numberOfSteps) {
28 | Step(
29 | modifier = Modifier.weight(1F),
30 | isCompete = step < currentStep,
31 | isCurrent = step == currentStep
32 | )
33 | }
34 | }
35 | }
36 |
37 | @Composable
38 | fun Step(modifier: Modifier = Modifier, isCompete: Boolean, isCurrent: Boolean) {
39 | val color = if (isCompete || isCurrent) SurveyColor.SolidBlue else Color.LightGray
40 | val innerCircleColor = if (isCompete) SurveyColor.SolidBlue else Color.LightGray
41 |
42 | Box(modifier = modifier) {
43 |
44 | //Line
45 | Divider(
46 | modifier = Modifier.align(Alignment.CenterStart),
47 | color = color,
48 | thickness = 2.dp
49 | )
50 |
51 | //Circle
52 | Canvas(modifier = Modifier
53 | .size(15.dp)
54 | .align(Alignment.CenterEnd)
55 | .border(
56 | shape = CircleShape,
57 | width = 2.dp,
58 | color = color
59 | ),
60 | onDraw = {
61 | drawCircle(color = innerCircleColor)
62 | }
63 | )
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.main
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import androidx.compose.foundation.layout.fillMaxSize
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.material.Surface
11 | import androidx.compose.ui.Modifier
12 | import com.google.android.gms.ads.MobileAds
13 | import com.google.firebase.FirebaseApp
14 | import com.loftymr.whichone.feature.navigation.NavGraph
15 | import com.loftymr.whichone.feature.theme.WhichOneTheme
16 | import com.loftymr.whichone.util.ForceUpdateChecker
17 | import dagger.hilt.android.AndroidEntryPoint
18 |
19 | @AndroidEntryPoint
20 | class MainActivity : ComponentActivity() {
21 |
22 | private var navigateURL = ""
23 |
24 | override fun onCreate(savedInstanceState: Bundle?) {
25 | super.onCreate(savedInstanceState)
26 | FirebaseApp.initializeApp(this)
27 | ForceUpdateChecker.with(this)
28 | .onUpdateNeeded(object : ForceUpdateChecker.OnUpdateNeededListener {
29 | override fun onUpdateNeeded(updateUrl: String?) {
30 | navigateURL = updateUrl.orEmpty()
31 | }
32 |
33 | }).check()
34 | setContent {
35 | WhichOneTheme(darkTheme = false) {
36 | // A surface container using the 'background' color from the theme
37 | Surface(
38 | modifier = Modifier
39 | .fillMaxSize(),
40 | color = MaterialTheme.colors.background
41 | ) {
42 | NavGraph(
43 | updateURL = navigateURL,
44 | navigateToPlayStore = {
45 | redirectStore(navigateURL)
46 | }
47 | )
48 | }
49 | }
50 | }
51 | MobileAds.initialize(this)
52 | }
53 |
54 | private fun redirectStore(updateUrl: String) {
55 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(updateUrl))
56 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
57 | startActivity(intent)
58 | }
59 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/navigation/NavGraph.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.navigation
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.navigation.NavType
5 | import androidx.navigation.compose.NavHost
6 | import androidx.navigation.compose.composable
7 | import androidx.navigation.compose.rememberNavController
8 | import androidx.navigation.navArgument
9 | import com.loftymr.whichone.feature.screen.forceupdate.ForceUpdateScreen
10 | import com.loftymr.whichone.feature.screen.result.ResultScreen
11 | import com.loftymr.whichone.feature.screen.survey.SurveyScreen
12 | import java.net.URLEncoder
13 | import java.nio.charset.StandardCharsets
14 |
15 | /**
16 | * Created by talhafaki on 10.09.2022.
17 | */
18 |
19 | @Composable
20 | fun NavGraph(updateURL: String, navigateToPlayStore: () -> Unit) {
21 | val navController = rememberNavController()
22 |
23 | NavHost(
24 | navController,
25 | startDestination = if (updateURL.isEmpty()) "survey" else "forceUpdate"
26 | ) {
27 | composable(route = "survey") {
28 | SurveyScreen(
29 | navigateToResult = { title, srcSet, desc ->
30 | val encodedUrl = URLEncoder.encode(srcSet, StandardCharsets.UTF_8.toString())
31 | navController.navigate("result/$encodedUrl/$title/$desc")
32 | }
33 | )
34 | }
35 |
36 | composable(
37 | route = "result/{imageSource}/{title}/{desc}",
38 | arguments = listOf(
39 | navArgument("title") {
40 | defaultValue = ""
41 | type = NavType.StringType
42 | },
43 | navArgument("imageSource") {
44 | defaultValue = ""
45 | type = NavType.StringType
46 | },
47 | navArgument("desc") {
48 | defaultValue = ""
49 | type = NavType.StringType
50 | }
51 | )) {
52 | ResultScreen(
53 | title = it.arguments?.getString("title").orEmpty(),
54 | character = it.arguments?.getString("imageSource").orEmpty(),
55 | desc = it.arguments?.getString("desc").orEmpty(),
56 | navigateToSurvey = {
57 | navController.navigate("survey")
58 | }
59 | )
60 | }
61 |
62 | composable(route = "forceUpdate") {
63 | ForceUpdateScreen(
64 | navigateToPlayStore = {
65 | navigateToPlayStore.invoke()
66 | }
67 | )
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/SelectionBox.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import androidx.compose.animation.Animatable
4 | import androidx.compose.animation.core.tween
5 | import androidx.compose.foundation.BorderStroke
6 | import androidx.compose.foundation.layout.*
7 | import androidx.compose.foundation.shape.RoundedCornerShape
8 | import androidx.compose.material3.Card
9 | import androidx.compose.material.MaterialTheme
10 | import androidx.compose.material.Text
11 | import androidx.compose.material3.CardDefaults
12 | import androidx.compose.runtime.*
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.text.style.TextAlign
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 | import com.loftymr.whichone.feature.theme.SurveyColor
18 | import com.loftymr.whichone.util.extension.noRippleClickable
19 | import kotlinx.coroutines.delay
20 |
21 | /**
22 | * Created by talhafaki on 13.09.2022.
23 | */
24 |
25 | @Composable
26 | fun SelectionBox(
27 | modifier: Modifier = Modifier,
28 | text: String,
29 | isSelected: () -> Unit
30 | ) {
31 | val color = remember { Animatable(SurveyColor.White) }
32 | var isClicked by remember { mutableStateOf(false) }
33 | if (isClicked) {
34 | LaunchedEffect(Unit) {
35 | color.animateTo(SurveyColor.DeepBlue, animationSpec = tween(150))
36 | delay(500)
37 | isSelected.invoke()
38 | isClicked = false
39 | }
40 | }
41 |
42 | Spacer(modifier = Modifier.height(6.dp))
43 | val backgroundColor = if (isClicked) color.value else SurveyColor.White
44 | val borderStroke = if (isClicked) BorderStroke(
45 | width = 1.dp,
46 | color = SurveyColor.SolidBlue
47 | ) else BorderStroke(width = 1.dp, color = SurveyColor.Black)
48 | Card(
49 | modifier = modifier
50 | .fillMaxWidth()
51 | .noRippleClickable {
52 | isClicked = true
53 | },
54 | shape = RoundedCornerShape(8.dp),
55 | elevation = CardDefaults.cardElevation(6.dp),
56 | colors = CardDefaults.cardColors(backgroundColor),
57 | border = borderStroke
58 | ) {
59 | Text(
60 | text = text,
61 | modifier = Modifier
62 | .fillMaxSize()
63 | .padding(10.dp),
64 | style = MaterialTheme.typography.body2.copy(
65 | color = if (isClicked) SurveyColor.White else SurveyColor.Black,
66 | textAlign = TextAlign.Center,
67 | fontSize = 14.sp
68 | )
69 | )
70 | }
71 | Spacer(modifier = Modifier.height(6.dp))
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/forceupdate/ForceUpdateScreen.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.forceupdate
2 |
3 | import androidx.compose.foundation.layout.*
4 | import androidx.compose.material.MaterialTheme
5 | import androidx.compose.material.Text
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.res.stringResource
10 | import androidx.compose.ui.text.style.TextAlign
11 | import androidx.compose.ui.unit.dp
12 | import androidx.compose.ui.unit.sp
13 | import com.loftymr.whichone.R
14 | import com.loftymr.whichone.feature.component.WhichOneAnim
15 | import com.loftymr.whichone.feature.component.WhichOneButton
16 | import com.loftymr.whichone.feature.component.WhichOneTemplate
17 | import com.loftymr.whichone.feature.theme.SurveyColor
18 |
19 | /**
20 | * Created by talhafaki on 10.09.2022.
21 | */
22 |
23 | @Composable
24 | fun ForceUpdateScreen(navigateToPlayStore: () -> Unit) {
25 | WhichOneTemplate {
26 | ForceUpdateContent(
27 | navigateToPlayStore = {
28 | navigateToPlayStore.invoke()
29 | }
30 | )
31 | }
32 | }
33 |
34 | @Composable
35 | fun ForceUpdateContent(navigateToPlayStore: () -> Unit) {
36 |
37 | Column(
38 | modifier = Modifier
39 | .fillMaxSize(),
40 | verticalArrangement = Arrangement.Top
41 | ) {
42 |
43 | WhichOneAnim(
44 | rawResId = R.raw.force_update_store_anim
45 | )
46 |
47 | Text(
48 | text = stringResource(id = R.string.new_version_available),
49 | modifier = Modifier
50 | .fillMaxWidth()
51 | .wrapContentWidth(Alignment.CenterHorizontally)
52 | .padding(horizontal = 16.dp, vertical = 4.dp),
53 | style = MaterialTheme.typography.h1.copy(fontSize = 24.sp, color = SurveyColor.White)
54 | )
55 |
56 | Text(
57 | text = stringResource(id = R.string.new_version_available_desc),
58 | modifier = Modifier
59 | .fillMaxWidth()
60 | .wrapContentWidth(Alignment.CenterHorizontally)
61 | .padding(horizontal = 16.dp, vertical = 8.dp),
62 | style = MaterialTheme.typography.h1.copy(
63 | fontSize = 16.sp,
64 | textAlign = TextAlign.Center,
65 | color = SurveyColor.Alabaster
66 | )
67 | )
68 |
69 | Spacer(modifier = Modifier.height(24.dp))
70 |
71 | WhichOneButton(buttonText = stringResource(id = R.string.go_to_play_store)) {
72 | navigateToPlayStore.invoke()
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/survey/SurveyViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.survey
2 |
3 | import androidx.lifecycle.viewModelScope
4 | import com.loftymr.whichone.data.remote.util.DataState
5 | import com.loftymr.whichone.domain.repository.SurveyRepository
6 | import com.loftymr.whichone.domain.viewstate.WhichOneViewEvent
7 | import com.loftymr.whichone.domain.viewstate.survey.SurveyViewState
8 | import com.loftymr.whichone.feature.base.BaseViewModel
9 | import dagger.hilt.android.lifecycle.HiltViewModel
10 | import kotlinx.coroutines.delay
11 | import kotlinx.coroutines.launch
12 | import javax.inject.Inject
13 |
14 | /**
15 | * Created by talhafaki on 9.09.2022.
16 | */
17 |
18 | @HiltViewModel
19 | class SurveyViewModel @Inject constructor(
20 | private val surveyRepository: SurveyRepository
21 | ) : BaseViewModel() {
22 |
23 | init {
24 | getRingsOfThePower()
25 | }
26 |
27 | fun getRingsOfThePower() {
28 | viewModelScope.launch {
29 | setState { currentState.copy(isLoading = true) }
30 | delay(2000)
31 | surveyRepository.ringsOfThePowerSurvey().collect {
32 | when (it) {
33 | is DataState.Success -> {
34 | setState {
35 | if (it.data.character != null && !it.data.questions.isNullOrEmpty() && it.data.backgroundPictures?.isNotEmpty() == true) {
36 | currentState.copy(
37 | data = it.data,
38 | isLoading = false,
39 | isError = false
40 | )
41 | } else {
42 | currentState.copy(isLoading = false, isError = true)
43 | }
44 | }
45 | }
46 | is DataState.Loading -> {
47 | setState { currentState.copy(isLoading = true, isError = false) }
48 | }
49 | is DataState.Error -> {
50 | setState { currentState.copy(isLoading = false, isError = true) }
51 | }
52 | }
53 | }
54 | }
55 | }
56 |
57 | fun showLoading(hasLoading: Boolean) {
58 | if (hasLoading) {
59 | setState { currentState.copy(isLoading = true) }
60 | } else {
61 | setState { currentState.copy(isLoading = false) }
62 | }
63 | }
64 |
65 | override fun createInitialState(): SurveyViewState = SurveyViewState()
66 | override fun onTriggerEvent(event: SurveyViewEvent) {}
67 | }
68 |
69 | sealed class SurveyViewEvent : WhichOneViewEvent {}
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/data/di/RemoteDataModule.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.data.di
2 |
3 | import android.content.Context
4 | import com.chuckerteam.chucker.api.ChuckerCollector
5 | import com.chuckerteam.chucker.api.ChuckerInterceptor
6 | import com.chuckerteam.chucker.api.RetentionManager
7 | import com.loftymr.whichone.BuildConfig
8 | import dagger.Module
9 | import dagger.Provides
10 | import dagger.hilt.InstallIn
11 | import dagger.hilt.android.qualifiers.ApplicationContext
12 | import dagger.hilt.components.SingletonComponent
13 | import okhttp3.OkHttpClient
14 | import okhttp3.logging.HttpLoggingInterceptor
15 | import retrofit2.Retrofit
16 | import retrofit2.converter.gson.GsonConverterFactory
17 | import javax.inject.Singleton
18 |
19 | /**
20 | * Created by talhafaki on 9.09.2022.
21 | */
22 |
23 | @Module
24 | @InstallIn(SingletonComponent::class)
25 | object RemoteDataModule {
26 |
27 | @Provides
28 | @Singleton
29 | fun provideRetrofit(
30 | okHttpClient: OkHttpClient,
31 | gsonConverterFactory: GsonConverterFactory,
32 | baseURL: String
33 | ): Retrofit {
34 | return Retrofit.Builder().baseUrl(baseURL)
35 | .addConverterFactory(gsonConverterFactory)
36 | .client(okHttpClient).build()
37 | }
38 |
39 | @Provides
40 | fun provideSurveyBaseURL(): String = BuildConfig.BASE_URL
41 |
42 | @Provides
43 | @Singleton
44 | fun provideOkHttpClient(
45 | httpLoggingInterceptor: HttpLoggingInterceptor,
46 | chuckInterceptor: ChuckerInterceptor
47 | ): OkHttpClient =
48 | OkHttpClient.Builder()
49 | .addInterceptor(chuckInterceptor)
50 | .addInterceptor(httpLoggingInterceptor).build()
51 |
52 | @Singleton
53 | @Provides
54 | fun provideGsonConverterFactory(): GsonConverterFactory = GsonConverterFactory.create()
55 |
56 | @Singleton
57 | @Provides
58 | fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor().apply {
59 | setLevel(HttpLoggingInterceptor.Level.BASIC)
60 | }
61 |
62 | @Singleton
63 | @Provides
64 | fun provideChuckerInterceptor(
65 | @ApplicationContext context: Context,
66 | chuckerCollector: ChuckerCollector
67 | ): ChuckerInterceptor =
68 | ChuckerInterceptor.Builder(context).collector(chuckerCollector)
69 | .alwaysReadResponseBody(true).build()
70 |
71 | @Singleton
72 | @Provides
73 | fun provideChuckerCollector(@ApplicationContext context: Context): ChuckerCollector = ChuckerCollector(
74 | context = context,
75 | // Toggles visibility of the push notification
76 | showNotification = true,
77 | // Allows to customize the retention period of collected data
78 | retentionPeriod = RetentionManager.Period.ONE_HOUR
79 | )
80 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/util/ForceUpdateChecker.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.util
2 |
3 | import android.content.Context
4 | import android.content.pm.PackageManager
5 | import android.text.TextUtils
6 | import android.util.Log
7 | import com.google.firebase.remoteconfig.FirebaseRemoteConfig
8 |
9 |
10 | /**
11 | * Created by talhafaki on 10.09.2022.
12 | */
13 |
14 | class ForceUpdateChecker(
15 | context: Context,
16 | onUpdateNeededListener: OnUpdateNeededListener?
17 | ) {
18 | private val onUpdateNeededListener: OnUpdateNeededListener?
19 | private val context: Context
20 |
21 | interface OnUpdateNeededListener {
22 | fun onUpdateNeeded(updateUrl: String?)
23 | }
24 |
25 | init {
26 | this.context = context
27 | this.onUpdateNeededListener = onUpdateNeededListener
28 | }
29 |
30 | fun check() {
31 | val remoteConfig = FirebaseRemoteConfig.getInstance()
32 | if (remoteConfig.getBoolean(KEY_UPDATE_REQUIRED)) {
33 | val currentVersion = remoteConfig.getString(KEY_CURRENT_VERSION)
34 | val appVersion = getAppVersion(context)
35 | val updateUrl = remoteConfig.getString(KEY_UPDATE_URL)
36 | if (!TextUtils.equals(currentVersion, appVersion)
37 | && onUpdateNeededListener != null
38 | ) {
39 | onUpdateNeededListener.onUpdateNeeded(updateUrl)
40 | }
41 | }
42 | }
43 |
44 | private fun getAppVersion(context: Context): String {
45 | var result = ""
46 | try {
47 | result = context.packageManager
48 | .getPackageInfo(context.packageName, 0).versionName
49 | result = result.replace("[a-zA-Z]|-".toRegex(), "")
50 | } catch (e: PackageManager.NameNotFoundException) {
51 | Log.e(TAG, e.message.orEmpty())
52 | }
53 | return result
54 | }
55 |
56 | class Builder(context: Context) {
57 | private val context: Context
58 | private var onUpdateNeededListener: OnUpdateNeededListener? = null
59 |
60 | init {
61 | this.context = context
62 | }
63 |
64 | fun onUpdateNeeded(onUpdateNeededListener: OnUpdateNeededListener?): Builder {
65 | this.onUpdateNeededListener = onUpdateNeededListener
66 | return this
67 | }
68 |
69 | private fun build(): ForceUpdateChecker {
70 | return ForceUpdateChecker(context, onUpdateNeededListener)
71 | }
72 |
73 | fun check(): ForceUpdateChecker {
74 | val forceUpdateChecker = build()
75 | forceUpdateChecker.check()
76 | return forceUpdateChecker
77 | }
78 | }
79 |
80 | companion object {
81 | private val TAG = ForceUpdateChecker::class.java.simpleName
82 | const val KEY_UPDATE_REQUIRED = "force_update_required"
83 | const val KEY_CURRENT_VERSION = "force_update_current_version"
84 | const val KEY_UPDATE_URL = "force_update_store_url"
85 | fun with(context: Context): Builder {
86 | return Builder(context)
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/component/AdsView.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.component
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.os.Handler
6 | import androidx.compose.foundation.layout.fillMaxWidth
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.viewinterop.AndroidView
10 | import com.google.android.gms.ads.*
11 | import com.google.android.gms.ads.interstitial.InterstitialAd
12 | import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
13 | import com.loftymr.whichone.BuildConfig
14 | import com.loftymr.whichone.R
15 |
16 | /**
17 | * Created by talhafaki on 13.09.2022.
18 | */
19 |
20 | private var mInterstitialAd: InterstitialAd? = null
21 |
22 | @Composable
23 | fun AdvertView(modifier: Modifier = Modifier) {
24 | AndroidView(
25 | modifier = modifier.fillMaxWidth(),
26 | factory = { context ->
27 | AdView(context).apply {
28 | val bannerID =
29 | if (BuildConfig.DEBUG) context.getString(R.string.ad_test_id_banner) else context.getString(
30 | R.string.ad_id_banner
31 | )
32 | setAdSize(AdSize.BANNER)
33 | adUnitId = bannerID
34 | loadAd(AdRequest.Builder().build())
35 | }
36 | }, update = {
37 | it.apply {
38 | loadAd(AdRequest.Builder().build())
39 | }
40 | }
41 | )
42 | }
43 |
44 | fun loadInterstitial(context: Context, isFinished: (Boolean) -> Unit) {
45 | InterstitialAd.load(
46 | context,
47 | context.getString(if (BuildConfig.DEBUG) R.string.ad_test_id_interstitial else R.string.ad_id_interstitial),
48 | AdRequest.Builder().build(),
49 | object : InterstitialAdLoadCallback() {
50 | override fun onAdFailedToLoad(adError: LoadAdError) {
51 | mInterstitialAd = null
52 | isFinished.invoke(true)
53 | }
54 |
55 | override fun onAdLoaded(interstitialAd: InterstitialAd) {
56 | mInterstitialAd = interstitialAd
57 | showInterstitial(context, isFinished)
58 | }
59 | }
60 | )
61 | Handler().postDelayed({
62 | if (mInterstitialAd == null) {
63 | isFinished.invoke(true)
64 | }
65 | }, 3500)
66 | }
67 |
68 | fun showInterstitial(context: Context, isFinished: (Boolean) -> Unit) {
69 | if (mInterstitialAd != null) {
70 | mInterstitialAd!!.show(context as Activity)
71 |
72 | addInterstitialCallbacks(isFinished = isFinished)
73 | } else {
74 | isFinished.invoke(true)
75 | }
76 | }
77 |
78 | // add the interstitial ad callbacks
79 | fun addInterstitialCallbacks(isFinished: (Boolean) -> Unit) {
80 | mInterstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
81 | override fun onAdFailedToShowFullScreenContent(p0: AdError) {
82 | isFinished.invoke(true)
83 | }
84 |
85 | override fun onAdShowedFullScreenContent() {
86 | mInterstitialAd = null
87 | isFinished.invoke(false)
88 | }
89 |
90 | override fun onAdDismissedFullScreenContent() {
91 | isFinished.invoke(true)
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/result/ResultScreen.kt:
--------------------------------------------------------------------------------
1 | package com.loftymr.whichone.feature.screen.result
2 |
3 | import androidx.activity.compose.BackHandler
4 | import androidx.compose.foundation.Image
5 | import androidx.compose.foundation.layout.*
6 | import androidx.compose.foundation.shape.RoundedCornerShape
7 | import androidx.compose.material3.Card
8 | import androidx.compose.material.MaterialTheme
9 | import androidx.compose.material.Text
10 | import androidx.compose.material3.CardDefaults
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Alignment
13 | import androidx.compose.ui.Modifier
14 | import androidx.compose.ui.layout.ContentScale
15 | import androidx.compose.ui.res.stringResource
16 | import androidx.compose.ui.text.style.TextAlign
17 | import androidx.compose.ui.unit.dp
18 | import androidx.compose.ui.unit.sp
19 | import coil.compose.rememberImagePainter
20 | import com.loftymr.whichone.R
21 | import com.loftymr.whichone.feature.component.WhichOneButton
22 | import com.loftymr.whichone.feature.component.WhichOneTemplate
23 | import com.loftymr.whichone.feature.theme.SurveyColor
24 |
25 | /**
26 | * Created by talhafaki on 10.09.2022.
27 | */
28 |
29 | @Composable
30 | fun ResultScreen(
31 | title: String = "",
32 | character: String = "",
33 | desc: String = "",
34 | navigateToSurvey: () -> Unit
35 | ) {
36 | WhichOneTemplate(
37 | topBar = {},
38 | ) {
39 | ResultContent(
40 | title = title,
41 | character = character,
42 | desc = desc,
43 | navigateToSurvey = {
44 | navigateToSurvey.invoke()
45 | }
46 | )
47 | }
48 | BackHandler {
49 | navigateToSurvey.invoke()
50 | }
51 | }
52 |
53 | @Composable
54 | fun ResultContent(
55 | modifier: Modifier = Modifier,
56 | title: String = "",
57 | desc: String = "",
58 | character: String = "",
59 | navigateToSurvey: () -> Unit
60 | ) {
61 | Column(
62 | modifier = modifier
63 | .fillMaxSize()
64 | ) {
65 | Card(
66 | modifier = Modifier
67 | .fillMaxWidth()
68 | .height(400.dp)
69 | .padding(16.dp),
70 | elevation = CardDefaults.cardElevation(10.dp),
71 | shape = RoundedCornerShape(8.dp)
72 | ) {
73 | Image(
74 | painter = rememberImagePainter(character),
75 | contentDescription = "",
76 | contentScale = ContentScale.Crop,
77 | modifier = Modifier.fillMaxSize()
78 | )
79 | }
80 |
81 | Text(
82 | text = title,
83 | modifier = Modifier
84 | .fillMaxWidth()
85 | .wrapContentWidth(Alignment.CenterHorizontally)
86 | .padding(horizontal = 16.dp, vertical = 8.dp),
87 | color = SurveyColor.White,
88 | style = MaterialTheme.typography.h1.copy(color = SurveyColor.White, fontSize = 24.sp)
89 | )
90 |
91 | Spacer(modifier = Modifier.height(8.dp))
92 | Text(
93 | text = desc,
94 | modifier = Modifier
95 | .fillMaxWidth()
96 | .wrapContentWidth(Alignment.CenterHorizontally)
97 | .padding(horizontal = 16.dp, vertical = 8.dp),
98 | color = SurveyColor.White,
99 | style = MaterialTheme.typography.body1.copy(
100 | color = SurveyColor.White.copy(0.5f),
101 | fontSize = 16.sp,
102 | textAlign = TextAlign.Center
103 | )
104 | )
105 | Box(
106 | modifier = Modifier
107 | .fillMaxSize()
108 | .padding(bottom = 24.dp),
109 | contentAlignment = Alignment.BottomCenter
110 | ) {
111 | WhichOneButton(buttonText = stringResource(id = R.string.again)) {
112 | navigateToSurvey.invoke()
113 | }
114 | }
115 | }
116 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WhichOne
2 | A mobile application where you can learn which TV series/movie character it is after answering 10 questions.
3 |
4 |
5 | ## GET IT ON
6 | [](https://play.google.com/store/apps/details?id=com.loftymr.whichone&hl=tr&gl=US)
7 |
8 | ## TECH STACK
9 | - [Compose](https://developer.android.com/jetpack/compose)
10 |
11 | - [Material](https://developer.android.com/jetpack/androidx/releases/compose-material) - Build Jetpack Compose UIs with ready to use Material Design Components.
12 | - [Foundation](https://developer.android.com/jetpack/androidx/releases/compose-foundation) - Write Jetpack Compose applications with ready to use building blocks and extend foundation to build your own design system pieces.
13 | - [UI](https://developer.android.com/jetpack/androidx/releases/compose-ui) - Fundamental components of compose UI needed to interact with the device, including layout, drawing, and input.
14 | - [Lifecycle-ViewModel](https://developer.android.com/jetpack/androidx/releases/lifecycle) - Perform actions in response to a change in the lifecycle status of another component, such as activities and fragments.
15 | - [Lottie](https://github.com/airbnb/lottie/blob/master/android-compose.md) - Lottie is a mobile library for Android and iOS that parses Adobe After Effects animations exported as json with Bodymovin and renders them natively on mobile!
16 | - [Coil](https://coil-kt.github.io/coil/compose/) - An image loading library for Android backed by Kotlin Coroutines.
17 |
18 | - [Jetpack](https://developer.android.com/jetpack)
19 |
20 | - [AndroidX](https://developer.android.com/jetpack/androidx) - Major improvement to the original Android [Support Library](https://developer.android.com/topic/libraries/support-library/index), which is no longer maintained.
21 | - [Lifecycle](https://developer.android.com/topic/libraries/architecture/lifecycle) - Perform actions in response to a change in the lifecycle status of another component, such as activities and fragments.
22 | - [ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel) - Designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
23 |
24 | - Others
25 | - [Retrofit](https://square.github.io/retrofit/)
26 | - [OkHttp-Logging-Interceptor](https://github.com/square/okhttp/blob/master/okhttp-logging-interceptor/README.md) - Logs HTTP request and response data.
27 | - [Flow](https://developer.android.com/kotlin/flow) - Flows are built on top of coroutines and can provide multiple values.
28 | - [Material Design](https://material.io/develop/android/docs/getting-started/) - Build awesome beautiful UIs.
29 | - [Coroutines](https://github.com/Kotlin/kotlinx.coroutines) - Library Support for coroutines,provides runBlocking coroutine builder used in tests.
30 | - [Gson](https://github.com/google/gson) - A modern JSON library for Kotlin and Java.
31 |
32 | ## CONTACT
33 |
34 | - [Linkedin](https://www.linkedin.com/in/talha-fakioglu/)
35 | - [Twitter](https://twitter.com/talhafaki)
36 | - [Medium](https://medium.com/@talhafaki)
37 |
38 | ```xml
39 | MIT License
40 |
41 | Copyright (c) 2023 Talha Fakıoğlu
42 |
43 | Permission is hereby granted, free of charge, to any person obtaining a copy
44 | of this software and associated documentation files (the "Software"), to deal
45 | in the Software without restriction, including without limitation the rights
46 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
47 | copies of the Software, and to permit persons to whom the Software is
48 | furnished to do so, subject to the following conditions:
49 |
50 | The above copyright notice and this permission notice shall be included in all
51 | copies or substantial portions of the Software.
52 |
53 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
58 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
59 | SOFTWARE.
60 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | id 'org.jetbrains.kotlin.kapt'
5 | id 'dagger.hilt.android.plugin'
6 | id 'com.google.gms.google-services'
7 | id 'com.google.firebase.crashlytics'
8 | }
9 |
10 | android {
11 | namespace 'com.loftymr.whichone'
12 | compileSdk 32
13 |
14 | defaultConfig {
15 | applicationId "com.loftymr.whichone"
16 | minSdk 24
17 | targetSdk 32
18 | versionCode 1
19 | versionName "1.0.0"
20 |
21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 | vectorDrawables {
23 | useSupportLibrary true
24 | }
25 | }
26 |
27 | buildTypes {
28 | release {
29 | shrinkResources true
30 | minifyEnabled true
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | debug {
34 | minifyEnabled false
35 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
36 | }
37 | }
38 |
39 | buildTypes.each {
40 | it.buildConfigField 'String', 'BASE_URL', BASE_URL
41 | }
42 |
43 | compileOptions {
44 | sourceCompatibility JavaVersion.VERSION_1_8
45 | targetCompatibility JavaVersion.VERSION_1_8
46 | }
47 | kotlinOptions {
48 | jvmTarget = '1.8'
49 | }
50 | buildFeatures {
51 | compose true
52 | }
53 | composeOptions {
54 | kotlinCompilerExtensionVersion '1.1.1'
55 | }
56 | packagingOptions {
57 | resources {
58 | excludes += '/META-INF/{AL2.0,LGPL2.1}'
59 | }
60 | }
61 | }
62 |
63 | dependencies {
64 |
65 | // Hilt
66 | implementation "com.google.dagger:hilt-android:2.41"
67 | implementation 'com.google.firebase:firebase-config-ktx:21.1.0'
68 | kapt "com.google.dagger:hilt-compiler:2.41"
69 |
70 | // Kotlin Coroutines
71 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1"
72 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2"
73 |
74 | // Networking
75 | implementation "com.squareup.retrofit2:retrofit:2.9.0"
76 | implementation "com.squareup.retrofit2:converter-gson:2.9.0"
77 | implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
78 | implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
79 |
80 | // AndroidX
81 | implementation "androidx.core:core-ktx:1.8.0"
82 | implementation "androidx.annotation:annotation:1.4.0"
83 | implementation "androidx.appcompat:appcompat:1.5.1"
84 | implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.5.1"
85 | implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
86 | implementation "androidx.compose.ui:ui:1.2.1"
87 | implementation "androidx.compose.material:material:1.2.1"
88 | implementation "androidx.compose.ui:ui-tooling:1.2.1"
89 | implementation "androidx.activity:activity-compose:1.5.1"
90 | implementation "androidx.navigation:navigation-compose:2.4.0-alpha07"
91 | implementation "androidx.hilt:hilt-navigation-compose:1.0.0"
92 |
93 | // Splash
94 | implementation "androidx.core:core-splashscreen:1.0.0"
95 |
96 | // Compose Material 3
97 | implementation "androidx.compose.material3:material3:1.0.0-alpha15"
98 |
99 | // Coil
100 | implementation "io.coil-kt:coil-compose:1.4.0"
101 |
102 | // Lottie
103 | implementation "com.airbnb.android:lottie-compose:4.2.2"
104 |
105 | // Google Ads
106 | implementation "com.google.android.gms:play-services-ads:21.2.0"
107 |
108 | // Firebase
109 | implementation 'com.google.firebase:firebase-crashlytics-ktx:18.2.13'
110 | implementation 'com.google.firebase:firebase-analytics-ktx:21.1.1'
111 | implementation "com.google.firebase:firebase-ads:21.2.0"
112 | implementation "com.google.firebase:firebase-core:21.1.1"
113 |
114 | // Chucker
115 | debugImplementation "com.github.chuckerteam.chucker:library:3.5.2"
116 | releaseImplementation "com.github.chuckerteam.chucker:library-no-op:3.5.2"
117 |
118 | // Testing
119 | testImplementation 'junit:junit:4.13.2'
120 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
121 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
122 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_ui_version"
123 | debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
124 | debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
125 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/which_one_logo.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/loftymr/whichone/feature/screen/survey/SurveyScreen.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(ExperimentalAnimationApi::class)
2 |
3 | package com.loftymr.whichone.feature.screen.survey
4 |
5 | import androidx.compose.animation.AnimatedContent
6 | import androidx.compose.animation.AnimatedContentScope
7 | import androidx.compose.animation.ExperimentalAnimationApi
8 | import androidx.compose.animation.core.TweenSpec
9 | import androidx.compose.animation.core.tween
10 | import androidx.compose.animation.with
11 | import androidx.compose.foundation.background
12 | import androidx.compose.foundation.layout.*
13 | import androidx.compose.foundation.rememberScrollState
14 | import androidx.compose.foundation.shape.RoundedCornerShape
15 | import androidx.compose.foundation.verticalScroll
16 | import androidx.compose.material.MaterialTheme
17 | import androidx.compose.material.Text
18 | import androidx.compose.material3.Card
19 | import androidx.compose.material3.CardDefaults
20 | import androidx.compose.runtime.*
21 | import androidx.compose.ui.Alignment
22 | import androidx.compose.ui.Modifier
23 | import androidx.compose.ui.platform.LocalContext
24 | import androidx.compose.ui.res.stringResource
25 | import androidx.compose.ui.text.style.TextAlign
26 | import androidx.compose.ui.unit.IntOffset
27 | import androidx.compose.ui.unit.dp
28 | import androidx.compose.ui.unit.sp
29 | import androidx.hilt.navigation.compose.hiltViewModel
30 | import com.loftymr.whichone.R
31 | import com.loftymr.whichone.data.model.RingsOfThePowerResponse
32 | import com.loftymr.whichone.data.model.SrcSet
33 | import com.loftymr.whichone.feature.component.*
34 | import com.loftymr.whichone.feature.theme.SurveyColor
35 |
36 | /**
37 | * Created by talhafaki on 9.09.2022.
38 | */
39 |
40 | @Composable
41 | fun SurveyScreen(
42 | viewModel: SurveyViewModel = hiltViewModel(),
43 | navigateToResult: (String, String, String) -> Unit
44 | ) {
45 | val viewState = viewModel.uiState.collectAsState().value
46 |
47 | when {
48 | viewState.isLoading -> {
49 | CircularProgressAnimated()
50 | }
51 | viewState.isError -> {
52 | ErrorView(
53 | clickToRetry = {
54 | viewModel.getRingsOfThePower()
55 | }
56 | )
57 | }
58 | viewState.data != null -> {
59 | WhichOneTemplate(
60 | topBar = {
61 | WhichOneTopBar(
62 | title = stringResource(id = R.string.survey_title),
63 | backButtonEnabled = false
64 | )
65 | },
66 | content = {
67 | SurveyContent(
68 | data = viewState.data,
69 | showResult = { title, srcSet, desc ->
70 | navigateToResult.invoke(title, srcSet?.nineHundred.orEmpty(), desc)
71 | },
72 | adMob = {
73 | viewModel.showLoading(it)
74 | }
75 | )
76 | }
77 | )
78 | }
79 | else -> {
80 | ErrorView {
81 | viewModel.getRingsOfThePower()
82 | }
83 | }
84 | }
85 | }
86 |
87 | @Composable
88 | fun SurveyContent(
89 | data: RingsOfThePowerResponse,
90 | showResult: (String, SrcSet?, String) -> Unit,
91 | adMob: (Boolean) -> Unit
92 | ) {
93 | val context = LocalContext.current
94 | var questionIndex by remember {
95 | mutableStateOf(0)
96 | }
97 | val questionState = remember(questionIndex) {
98 | questionIndex
99 | }
100 | Card(
101 | modifier = Modifier
102 | .fillMaxSize()
103 | .padding(start = 8.dp, end = 8.dp, top = 36.dp, bottom = 8.dp),
104 | shape = RoundedCornerShape(10.dp),
105 | colors = CardDefaults.cardColors(SurveyColor.Alabaster),
106 | elevation = CardDefaults.cardElevation(10.dp)
107 | ) {
108 | Column(
109 | modifier = Modifier
110 | .fillMaxSize()
111 | .verticalScroll(state = rememberScrollState())
112 | ) {
113 | Head(
114 | imageSource = data.backgroundPictures?.get(questionIndex).orEmpty(),
115 | numberOfSteps = data.questions?.lastIndex ?: 0,
116 | currentStep = questionIndex
117 | )
118 |
119 | AnimatedContent(
120 | targetState = questionState,
121 | transitionSpec = {
122 | val animationSpec: TweenSpec = tween(150)
123 | val direction =
124 | if (targetState > initialState) {
125 | AnimatedContentScope.SlideDirection.Left
126 | } else {
127 | AnimatedContentScope.SlideDirection.Right
128 | }
129 | slideIntoContainer(
130 | towards = direction,
131 | animationSpec = animationSpec
132 | ) with
133 | slideOutOfContainer(
134 | towards = direction,
135 | animationSpec = animationSpec
136 | )
137 | }
138 | ) {
139 | Column {
140 | Text(
141 | text = data.questions?.get(questionIndex)?.questionText.orEmpty(),
142 | modifier = Modifier
143 | .fillMaxWidth()
144 | .wrapContentWidth(Alignment.CenterHorizontally)
145 | .padding(horizontal = 16.dp, vertical = 8.dp),
146 | style = MaterialTheme.typography.h1.copy(
147 | fontSize = 18.sp,
148 | color = SurveyColor.Black,
149 | textAlign = TextAlign.Center
150 | )
151 | )
152 |
153 | data.questions?.get(questionIndex)?.choices?.let { choices ->
154 | choices.forEach {
155 | SelectionBox(
156 | modifier = Modifier
157 | .padding(horizontal = 12.dp),
158 | text = it,
159 | isSelected = {
160 | if (questionIndex < data.questions.lastIndex) {
161 | questionIndex++
162 | } else {
163 | adMob.invoke(true)
164 | loadInterstitial(
165 | context = context,
166 | isFinished = {
167 | adMob.invoke(false)
168 | showResult.invoke(
169 | data.character?.title.orEmpty(),
170 | data.character?.srcSet,
171 | data.character?.description.orEmpty()
172 | )
173 | }
174 | )
175 | }
176 | }
177 | )
178 | }
179 | Spacer(modifier = Modifier.height(8.dp))
180 | }
181 | }
182 | }
183 |
184 | Box(
185 | modifier = Modifier
186 | .fillMaxSize()
187 | .padding(bottom = 2.dp)
188 | .weight(1f),
189 | contentAlignment = Alignment.BottomCenter
190 | ) {
191 | AdvertView(modifier = Modifier.wrapContentSize())
192 | }
193 | }
194 | }
195 | }
196 |
197 | @Composable
198 | fun ErrorView(clickToRetry: () -> Unit) {
199 | Column(
200 | modifier = Modifier
201 | .fillMaxSize()
202 | .background(color = SurveyColor.SolidBlue),
203 | verticalArrangement = Arrangement.Top
204 | ) {
205 | WhichOneAnim(rawResId = R.raw.opps_anim)
206 |
207 | Text(
208 | text = stringResource(id = R.string.something_went_wrong),
209 | modifier = Modifier
210 | .fillMaxWidth()
211 | .wrapContentWidth(Alignment.CenterHorizontally)
212 | .padding(horizontal = 16.dp, vertical = 4.dp),
213 | style = MaterialTheme.typography.h1.copy(
214 | fontSize = 24.sp,
215 | color = SurveyColor.White
216 | )
217 | )
218 |
219 | Spacer(modifier = Modifier.height(16.dp))
220 |
221 | WhichOneButton(buttonText = stringResource(id = R.string.retry)) {
222 | clickToRetry.invoke()
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/force_update_store_anim.json:
--------------------------------------------------------------------------------
1 | {"v":"5.4.3","fr":25,"ip":0,"op":80,"w":1920,"h":1080,"nm":"PlayStore","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Vector_PlayStore contornos","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[960,540,0],"ix":2},"a":{"a":0,"k":[683,384,0],"ix":1},"s":{"a":0,"k":[124.816,124.816,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[55.112,-55.111]],"o":[[0,0],[-55.112,55.112],[0,0]],"v":[[-82.667,-165.335],[82.667,0.001],[-82.667,165.335]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.161000001197,0.670999983245,0.885999971278,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[579.667,368.082],"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":"Transformar"}],"nm":"Grupo 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.632,-3.55],[0,0],[0,0],[76.165,44.778],[1.816,-0.557]],"o":[[0,0],[0,0],[-76.165,-44.779],[-0.935,-0.262],[-2.995,0.918]],"v":[[-119.368,-178.956],[-119.368,186.829],[119.368,-51.936],[-109.126,-186.272],[-113.515,-186.272]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.736999990426,0.395999983245,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[616.368,346.588],"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":"Transformar"}],"nm":"Grupo 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[3.14,2.43],[0.085,0.898]],"o":[[0,0],[0,0],[-3.961,3.674],[-2.437,-1.885],[0,0]],"v":[[-124.452,-195.081],[124.452,53.808],[-109.095,190.949],[-121.526,192.651],[-124.452,186.798]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.277999997606,0.33300000359,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[621.452,397.829],"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":"Transformar"}],"nm":"Grupo 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[3.424,2.011],[0,0],[0,-4.022],[0,0],[-3.467,2.036],[0,0]],"o":[[0,0],[-3.467,-2.036],[0,0],[0,4.021],[0,0],[3.424,-2.01]],"v":[[183.214,-4.486],[-178.802,-217.064],[-186.638,-212.578],[-186.638,212.579],[-178.802,217.065],[183.214,4.486]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.984000052658,0.689999988032,0.231000010173,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[683.638,376.13],"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":"Transformar"}],"nm":"Grupo 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Vector_Android contornos","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[20]},{"t":25}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[864,532,0],"e":[948,404,0],"to":[14,-21.3333339691162,0],"ti":[-14,21.3333339691162,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":25,"s":[948,404,0],"e":[948,404,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":59,"s":[948,404,0],"e":[862,541,0],"to":[-14.3333330154419,22.8333339691162,0],"ti":[14.3333330154419,-22.8333339691162,0]},{"t":79}],"ix":2},"a":{"a":0,"k":[683,384,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[60,60,100],"e":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":25,"s":[100,100,100],"e":[100,100,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":59,"s":[100,100,100],"e":[57,57,100]},{"t":79}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.77,0],[0,0],[0,10.77],[0,0],[-10.769,0],[0,0],[0,-10.769],[0,0]],"o":[[0,0],[-10.769,0],[0,0],[0,-10.769],[0,0],[10.77,0],[0,0],[0,10.77]],"v":[[3.022,74.496],[-3.022,74.496],[-22.522,54.996],[-22.522,-54.995],[-3.022,-74.495],[3.022,-74.495],[22.522,-54.995],[22.522,54.996]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[848.954,342.374],"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":"Transformar"}],"nm":"Grupo 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.77,0],[0,0],[0,10.77],[0,0],[-10.77,0],[0,0],[0,-10.769],[0,0]],"o":[[0,0],[-10.77,0],[0,0],[0,-10.769],[0,0],[10.77,0],[0,0],[0,10.77]],"v":[[3.022,74.496],[-3.021,74.496],[-22.521,54.996],[-22.521,-54.995],[-3.021,-74.495],[3.022,-74.495],[22.522,-54.995],[22.522,54.996]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[562.648,291.95],"ix":2},"a":{"a":0,"k":[0.126,-50.424],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":21,"s":[0],"e":[174]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":30,"s":[174],"e":[130]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":36,"s":[130],"e":[174]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":41,"s":[174],"e":[130]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":46,"s":[130],"e":[174]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":51,"s":[174],"e":[130]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":55,"s":[130],"e":[0]},{"t":64}],"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformar"}],"nm":"BrazoAnimado","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.77,0],[0,0],[0,10.77],[0,0],[-10.769,0],[0,0],[0,-10.769],[0,0]],"o":[[0,0],[-10.769,0],[0,0],[0,-10.769],[0,0],[10.77,0],[0,0],[0,10.77]],"v":[[3.022,53.128],[-3.022,53.128],[-22.522,33.628],[-22.522,-33.629],[-3.022,-53.129],[3.022,-53.129],[22.522,-33.629],[22.522,33.628]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[751.936,498.872],"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":"Transformar"}],"nm":"Grupo 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[10.77,0],[0,0],[0,10.77],[0,0],[-10.77,0],[0,0],[0,-10.769],[0,0]],"o":[[0,0],[-10.77,0],[0,0],[0,-10.769],[0,0],[10.77,0],[0,0],[0,10.77]],"v":[[3.021,53.128],[-3.022,53.128],[-22.522,33.628],[-22.522,-33.629],[-3.022,-53.129],[3.021,-53.129],[22.521,-33.629],[22.521,33.628]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[661.849,498.872],"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":"Transformar"}],"nm":"Grupo 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[2.466,-2.098],[0.659,0.127],[0,0],[3.541,3.978],[0.11,1.248]],"o":[[0,0],[0,0],[-0.236,1.013],[-3.836,3.265],[0,0],[-1.069,-0.098],[-2.873,-3.229],[0,0]],"v":[[-109.722,-98.65],[109.722,-98.65],[109.722,89.611],[106.257,95.384],[97.017,97.694],[-97.017,97.694],[-106.257,93.076],[-109.722,84.991]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[706.315,372.303],"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":"Transformar"}],"nm":"Grupo 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.468],[7.468,0],[0,7.468],[-7.468,0]],"o":[[0,7.468],[-7.468,0],[0,-7.468],[7.468,0]],"v":[[13.522,0],[0,13.522],[-13.522,0],[0,-13.522]],"c":true},"ix":2},"nm":"Trazado 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":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[751.478,213.99],"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":"Transformar"}],"nm":"Grupo 6","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.468],[7.468,0],[0,7.468],[-7.468,0]],"o":[[0,7.468],[-7.468,0],[0,-7.468],[7.468,0]],"v":[[13.522,0],[0,13.522],[-13.522,0],[0,-13.522]],"c":true},"ix":2},"nm":"Trazado 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":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[666.484,213.99],"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":"Transformar"}],"nm":"Grupo 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.239,0.715],[0,0],[-0.715,1.239],[0,0],[-1.239,-0.716],[0,0],[0.714,-1.24],[0,0]],"o":[[0,0],[-1.238,-0.716],[0,0],[0.714,-1.238],[0,0],[1.24,0.715],[0,0],[-0.715,1.239]],"v":[[-8.153,18.181],[-11.669,16.152],[-12.617,12.613],[4.616,-17.234],[8.154,-18.181],[11.669,-16.151],[12.618,-12.612],[-4.615,17.233]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[765.413,165.692],"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":"Transformar"}],"nm":"Grupo 8","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.239,-0.715],[0,0],[0.716,1.238],[0,0],[-1.239,0.716],[0,0],[-0.715,-1.239],[0,0]],"o":[[0,0],[-1.239,0.715],[0,0],[-0.715,-1.239],[0,0],[1.239,-0.715],[0,0],[0.716,1.24]],"v":[[11.669,16.151],[8.154,18.181],[4.615,17.233],[-12.617,-12.613],[-11.669,-16.152],[-8.154,-18.181],[-4.616,-17.233],[12.617,12.613]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[645.297,163.382],"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":"Transformar"}],"nm":"Grupo 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.661,-6.85],[0,0],[37.683,27.006],[9.772,-0.321],[28.5,-21.398]],"o":[[0,0],[-0.783,-7.006],[-27.37,-19.615],[-9.089,-0.4],[-36.274,27.235]],"v":[[-109.722,48.235],[109.722,48.235],[65.833,-27.993],[0,-47.626],[-68.143,-26.837]],"c":true},"ix":2},"nm":"Trazado 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.522000002394,0.783999992819,0.030999998953,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Relleno 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[706.315,213.868],"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":"Transformar"}],"nm":"Grupo 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------
/app/src/main/res/raw/opps_anim.json:
--------------------------------------------------------------------------------
1 | {"v":"5.5.10","fr":30,"ip":0,"op":60,"w":512,"h":512,"nm":"Try Again","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Layer 3 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[256,314.669,0],"ix":2},"a":{"a":0,"k":[256,314.669,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":30,"s":[0,0,100]},{"t":38.5,"s":[100,100,100]}],"ix":6,"x":"var $bm_rt;\nvar n, n, t, t, v, amp, freq, decay;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n}\nif (n == 0) {\n $bm_rt = t = 0;\n} else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n}\nif (n > 0) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = $bm_div(effect('Amplitude')('Slider'), 100);\n freq = effect('Frequency')('Slider');\n decay = effect('Decay')('Slider');\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n} else {\n $bm_rt = value;\n}"}},"ao":0,"ef":[{"ty":5,"nm":"Amplitude","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":3,"ix":1}}]},{"ty":5,"nm":"Frequency","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":2.5,"ix":1}}]},{"ty":5,"nm":"Decay","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":5,"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.753,0.004],[-0.122,4.039],[-4.559,-0.014],[0.031,-3.637]],"o":[[-4.836,-0.004],[0.112,-3.729],[4.237,0.014],[-0.034,3.987]],"v":[[-0.044,7.47],[-8.87,-0.097],[0.391,-7.46],[8.96,-0.024]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[455.324,339.988],"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":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-6.436,-0.475],[2.258,-12.861],[3.659,0.266]],"o":[[6.027,0.444],[-2.227,12.672],[-4.012,-0.293],[0,0]],"v":[[-9.022,-19.59],[9.021,-18.26],[2.372,19.59],[-9.022,18.758]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[459.752,306.977],"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":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.028,0.81],[-0.834,-4.509],[6.31,-0.519],[-0.636,-14.316],[6.15,-1.14],[0,0],[4.162,-0.329],[0.004,0.286],[-11.661,0.875]],"o":[[0.912,4.926],[-5.497,0.452],[0.605,13.641],[-5.356,0.993],[0,0],[-4.852,0.385],[-0.375,-0.809],[-0.181,-12.017],[10.592,-0.795]],"v":[[20.692,-29.766],[23.185,-16.298],[6.285,-14.906],[8.127,26.59],[-9,29.766],[-9,-14.174],[-22.383,-13.116],[-23.004,-14.492],[-11.523,-27.397]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[66.269,311.646],"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":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.706],[-1.663,1.623],[0.496,1.97],[3.076,-0.87],[0.269,-1.429]],"o":[[2.651,-1.343],[2.159,-2.108],[-1.003,-3.985],[-1.352,0.381],[-0.508,2.711]],"v":[[-7.68,-4.21],[-0.788,-7.857],[4.157,-15.255],[-4.336,-17.194],[-7.534,-13.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[3.472,-3.02],[-5.454,-6.342],[4.797,-3.665],[6.299,8.301],[0,0],[5.433,-1.146],[-0.11,7.114],[-0.166,10.313],[-1.001,0.116],[-8.922,0.369],[-2.147,-5.408],[3.712,-4.241]],"o":[[4.958,5.764],[-4.381,3.346],[-5.724,-7.544],[0,0],[-4.761,1.004],[0.411,-7.745],[0.159,-10.314],[0.021,-1.283],[8.875,-1.025],[5.442,-0.226],[2.138,5.389],[-2.48,2.834]],"v":[[7.633,0.966],[23.012,18.852],[9.557,29.133],[-8.081,5.886],[-8.081,26.409],[-23.012,29.556],[-21.9,7.591],[-21.855,-23.356],[-19.348,-27.01],[7.355,-29.331],[19.891,-21.973],[16.766,-7.106]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[115.047,311.635],"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":"Group 4","np":5,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.871,17.784],[5.908,-0.764],[0,0],[0.739,-0.096],[3.449,11.455],[6.067,-0.814],[0,0],[-4.981,0.987],[0,0],[0,0]],"o":[[0.888,-18.12],[-5.382,0.696],[0,0],[-0.738,0.098],[-3.279,-10.893],[-5.175,0.695],[0,0],[4.798,-0.952],[0,0],[0,0],[0,0]],"v":[[20.123,23.997],[22.745,-29.516],[6.236,-27.382],[6.236,3.021],[4.02,3.313],[-5.987,-29.929],[-22.745,-27.68],[-22.745,29.929],[-8.204,27.046],[-8.204,7.641],[3.349,25.639]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[418.762,316.126],"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":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-5.243,0.656],[0.802,-18.23],[5.034,-0.983]],"o":[[5.936,-0.743],[-0.782,17.766],[-4.213,0.823],[0,0]],"v":[[-8.13,-26.132],[8.13,-28.167],[5.77,25.453],[-8.13,28.167]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[380.834,315.719],"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":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.466,-18.783],[5.647,0.48],[-1.618,4.746],[0.821,1.792],[5.078,10.452],[-5.912,2.107],[-1.72,-6.847],[0,0],[-2.174,5.637],[-2.879,-0.605],[-4.358,-0.541]],"o":[[-4.049,-0.345],[2.125,-4.993],[0.648,-1.902],[-4.614,-10.065],[6.131,-2.184],[1.839,7.32],[0,0],[2.278,-5.597],[0.89,-2.308],[4.166,0.874],[-8.402,18.641]],"v":[[-0.874,29.301],[-15.344,28.071],[-9.396,13.788],[-9.558,7.449],[-24.206,-22.977],[-6.452,-29.301],[-1.173,-8.289],[-0.14,-8.303],[6.659,-25.108],[11.388,-28.022],[24.206,-26.34]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[163.107,312.134],"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":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.493,7.721],[0.247,0.019],[1.507,-8.076],[0,0]],"o":[[-0.247,-0.018],[-1.441,7.725],[0,0],[-1.552,-8.029]],"v":[[0.233,-14.082],[-0.508,-14.136],[-4.897,9.389],[4.77,9.389]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-4.084,0.381],[-4.69,-18.437],[5.206,-1.013],[15.003,-2.118],[0.857,-3.483],[5.399,1.143],[-3.553,12.559],[-0.467,2.106],[-8.856,0.845]],"o":[[4.712,18.523],[-5.001,0.974],[-3.946,-11.582],[-0.703,2.861],[-5.735,-1.214],[3.72,-13.065],[0.587,-2.074],[1.963,-8.853],[4.425,-0.423]],"v":[[11.087,-29.441],[25.059,25.484],[9.571,28.498],[-6.201,20.094],[-8.5,29.441],[-25.058,25.935],[-14.201,-12.241],[-12.66,-18.527],[-1.849,-28.231]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[233.78,313.672],"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":"Group 8","np":5,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.463,7.392],[0.259,0.019],[1.454,-7.772],[0,0]],"o":[[-0.26,-0.019],[-1.402,7.491],[0,0],[-1.566,-7.915]],"v":[[0.099,-13.798],[-0.681,-13.855],[-4.937,8.899],[4.591,8.899]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-5.168,0.539],[-4.715,-18.566],[4.573,-0.874],[6.94,0.384],[-0.232,-8.456],[5.08,1.07],[-3.704,15.791],[-4.484,0.227]],"o":[[4.694,18.484],[-4.999,0.956],[-3.955,-2.587],[-7.623,-0.421],[-6.133,-1.293],[4.315,-16.024],[1.172,-4.995],[5.121,-0.258]],"v":[[10.948,-29.52],[24.923,25.507],[10.078,28.345],[3.087,18.877],[-8.273,29.521],[-24.922,26.012],[-12.359,-21.399],[-4.437,-27.979]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[342.92,315.31],"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":"Group 9","np":5,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.441,-5.359],[2.73,-2.518],[5.699,-5.019],[-2.501,-6.968],[-4.57,-0.443],[-3.605,4.695],[-0.91,1.971],[5.743,-0.82],[-0.241,3.367],[-9.971,1.321],[8.273,-7.117],[8.792,10.465],[-2.69,9.66],[-13.698,-1.616]],"o":[[-3.136,2.893],[-8.362,-4.234],[-6.47,5.697],[1.686,4.694],[5.886,0.57],[0.87,-1.133],[-5.48,0.782],[0.242,-3.398],[9.877,-1.308],[1.381,11.96],[-11.281,9.705],[-6.88,-8.189],[4.205,-15.101],[6.154,0.725]],"v":[[21.756,-21.925],[13.111,-13.949],[-5.728,-12.862],[-12.673,9.718],[-2.829,16.945],[11.538,10.561],[13.714,5.959],[-2.391,8.257],[-1.686,-1.645],[27.51,-5.513],[15.828,22.414],[-21.992,20.823],[-26.201,-6.553],[5.867,-30.503]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.054999998504,0,0.451000019148,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","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":[288.577,315.228],"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":"Group 10","np":3,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":450,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Layer 2 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[133]},{"t":23.5,"s":[0]}],"ix":10,"x":"var $bm_rt;\nvar n, n, t, t, v, amp, freq, decay;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n}\nif (n == 0) {\n $bm_rt = t = 0;\n} else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n}\nif (n > 0) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = $bm_div(effect('Amplitude')('Slider'), 100);\n freq = effect('Frequency')('Slider');\n decay = effect('Decay')('Slider');\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n} else {\n $bm_rt = value;\n}"},"p":{"a":0,"k":[256.839,378.218,0],"ix":2},"a":{"a":0,"k":[256.839,378.218,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":15,"s":[0,0,100]},{"t":23.5,"s":[100,100,100]}],"ix":6,"x":"var $bm_rt;\nvar n, n, t, t, v, amp, freq, decay;\n$bm_rt = n = 0;\nif (numKeys > 0) {\n $bm_rt = n = nearestKey(time).index;\n if (key(n).time > time) {\n n--;\n }\n}\nif (n == 0) {\n $bm_rt = t = 0;\n} else {\n $bm_rt = t = $bm_sub(time, key(n).time);\n}\nif (n > 0) {\n v = velocityAtTime($bm_sub(key(n).time, $bm_div(thisComp.frameDuration, 10)));\n amp = $bm_div(effect('Amplitude')('Slider'), 100);\n freq = effect('Frequency')('Slider');\n decay = effect('Decay')('Slider');\n $bm_rt = $bm_sum(value, $bm_div($bm_mul($bm_mul(v, amp), Math.sin($bm_mul($bm_mul($bm_mul(freq, t), 2), Math.PI))), Math.exp($bm_mul(decay, t))));\n} else {\n $bm_rt = value;\n}"}},"ao":0,"ef":[{"ty":5,"nm":"Amplitude","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":3,"ix":1}}]},{"ty":5,"nm":"Frequency","np":3,"mn":"ADBE Slider Control","ix":2,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":2.5,"ix":1}}]},{"ty":5,"nm":"Decay","np":3,"mn":"ADBE Slider Control","ix":3,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":5,"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.223,1.562],[-1.561,0],[-0.446,-0.446],[0,0],[0.224,-1.784],[1.562,0],[1.339,0.224],[0,1.562]],"o":[[2.9,-0.446],[1.786,0],[0,0],[0,2.231],[-2.008,0.224],[-1.562,0],[0.223,-1.561],[0,-1.562]],"v":[[-4.853,9.874],[1.84,9.204],[5.188,9.874],[5.188,13.221],[4.853,19.245],[-0.502,19.58],[-4.853,19.245],[-4.519,14.56]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[1.339,16.067],[-1.561,0],[-1.339,-0.446],[0.224,-4.463],[0.223,-4.463],[1.338,0],[0.892,-0.446]],"o":[[2.231,-0.446],[1.786,0],[0,2.902],[-0.446,5.578],[-1.339,-0.446],[-1.116,0],[0,-1.339]],"v":[[-5.188,-18.911],[0.501,-19.58],[5.188,-18.911],[4.853,-7.865],[3.849,7.196],[-0.167,6.526],[-3.18,7.196]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[330.372,254.271],"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":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.115,4.648],[-5.615,0.056],[-0.892,-0.521],[-1.004,0],[-0.763,0.223],[-0.558,0.855],[0,0.745],[0.149,0.52],[2.212,0.205],[0.576,0],[0.688,-0.037],[0.464,0],[0,0],[2.511,2.176],[0,2.566],[-0.094,0.521],[-3.124,2.176],[-3.906,0],[0,0],[-3.347,-1.859],[-1.451,-3.273],[1.859,0],[0.168,0.038],[1.154,0.409],[0.93,0],[0.408,-0.056],[0.399,-0.539],[0,-0.706],[-0.131,-0.372],[-1.507,-0.502],[-1.655,-0.148],[-0.595,-0.074],[-1.636,-1.227],[0,-3.569],[3.328,-2.511],[4.574,-0.241],[0.465,0],[3.254,1.654]],"o":[[2.882,-0.539],[0.744,1.804],[1.097,0.335],[0.818,0],[0.724,-0.204],[0.595,-0.91],[0,-0.463],[-0.446,-1.507],[-0.428,-0.037],[-0.557,0],[-1.135,0.037],[0,0],[-3.311,-0.112],[-2.287,-1.989],[0,-0.483],[0.651,-4.035],[2.752,-1.914],[0,0],[3.868,0.037],[3.533,1.971],[-5.913,1.004],[-0.354,0],[-0.502,-0.873],[-0.874,-0.279],[-0.39,0],[-0.781,0.279],[-0.401,0.539],[0,0.335],[0.539,1.543],[0.892,0.168],[2.175,0.186],[3.384,0.409],[2.213,1.655],[0,4.11],[-3.013,2.287],[-0.484,0.019],[-3.96,0],[-3.979,-2.213]],"v":[[-18.13,8.242],[-5.384,7.349],[-2.929,10.836],[0.223,11.338],[2.594,11.003],[4.518,9.413],[5.411,6.93],[5.187,5.453],[1.199,2.887],[-0.308,2.831],[-2.176,2.887],[-4.574,2.943],[-4.909,2.943],[-13.64,-0.488],[-17.07,-7.322],[-16.931,-8.828],[-11.269,-18.144],[-1.283,-21.016],[-1.061,-21.016],[9.762,-18.172],[17.237,-10.306],[5.578,-8.8],[4.797,-8.856],[2.314,-10.78],[-0.391,-11.199],[-1.59,-11.115],[-3.361,-9.887],[-3.961,-8.019],[-3.766,-6.959],[-0.697,-3.891],[3.124,-3.417],[7.279,-3.026],[14.81,-0.572],[18.13,7.265],[13.137,17.195],[1.757,20.988],[0.334,21.016],[-10.488,18.534]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[305.059,253.114],"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":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-3.57],[0,0],[0,2.901],[3.57,0],[1.115,-0.223]],"o":[[0,0],[4.239,0],[-0.223,-2.677],[-1.115,0],[0.669,1.785]],"v":[[-3.515,-1.144],[-1.841,-1.144],[4.518,-5.495],[-1.172,-9.511],[-4.519,-9.177]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[2.008,-0.298],[0,4.016],[1.116,9.148],[0,0],[-2.678,-5.132],[0,-1.785],[2.678,-2.009],[6.47,0],[0,0],[0,0],[0.446,-4.426],[1.154,0],[0.743,-0.074]],"o":[[0.223,-4.202],[0,-9.148],[0,0],[5.132,0],[1.115,2.232],[0,2.678],[-3.57,2.677],[0,0],[0,0],[0,3.347],[-1.302,-0.149],[-0.818,0],[-2.231,0]],"v":[[-16.233,19.887],[-15.898,7.558],[-17.572,-19.887],[4.183,-19.887],[15.898,-12.189],[17.572,-6.165],[13.555,0.865],[-1.506,4.881],[-3.18,4.881],[-3.18,7.893],[-3.85,19.552],[-7.532,19.328],[-9.874,19.44]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[268.198,253.686],"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":"Group 3","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.569,0],[-0.222,3.588],[0,0],[4.017,0],[0,-4.854],[-0.223,-1.284]],"o":[[3.348,-0.261],[0,0],[0,-5.373],[-4.017,0.261],[0,1.022],[0.67,3.588]],"v":[[0.335,8.535],[5.689,2.762],[5.689,0.083],[-0.335,-7.977],[-6.359,-0.306],[-6.025,3.152]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[1.116,13.389],[0,0],[-3.123,3.348],[-4.463,0],[0,0],[-3.348,-3.347],[0,-5.801],[0,0],[10.487,0],[0,0]],"o":[[0,0],[0,-5.802],[2.902,-3.347],[0,0],[4.686,0.224],[3.569,3.57],[0,0],[-0.222,13.835],[0,0],[-10.71,-0.223]],"v":[[-17.07,0.167],[-17.07,-1.84],[-12.385,-15.564],[-1.339,-20.585],[-0.335,-20.585],[11.715,-15.229],[17.07,-1.172],[17.07,-0.168],[1.005,20.585],[0.669,20.585]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[231.28,253.266],"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":"Group 4","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.569,0],[-0.222,3.588],[0,0],[4.017,0],[0,-4.854],[-0.223,-1.284]],"o":[[3.348,-0.261],[0,0],[0,-5.373],[-4.017,0.261],[0,1.022],[0.67,3.588]],"v":[[0.335,8.535],[5.689,2.762],[5.689,0.083],[-0.335,-7.977],[-6.359,-0.306],[-6.025,3.152]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[1.116,13.389],[0,0],[-3.123,3.348],[-4.463,0],[0,0],[-3.348,-3.347],[0,-5.801],[0,0],[10.487,0],[0,0]],"o":[[0,0],[0,-5.802],[2.902,-3.347],[0,0],[4.686,0.224],[3.569,3.57],[0,0],[-0.222,13.835],[0,0],[-10.71,-0.223]],"v":[[-17.07,0.167],[-17.07,-1.84],[-12.385,-15.564],[-1.339,-20.585],[-0.335,-20.585],[11.715,-15.229],[17.07,-1.172],[17.07,-0.168],[1.005,20.585],[0.669,20.585]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[194.865,253.266],"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":"Group 5","np":4,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.032,0],[1.06,-1.025],[0,0],[-2.162,-2.236],[0,0],[-2.234,2.162],[0,0],[2.162,2.235],[0,0],[1.507,0.025]],"o":[[-1.471,0],[0,0],[-2.236,2.162],[0,0],[2.162,2.236],[0,0],[2.236,-2.162],[0,0],[-1.047,-1.083],[-0.033,-0.001]],"v":[[2.336,-107.939],[-1.582,-106.352],[-105.635,-5.741],[-105.769,2.234],[-5.157,106.289],[2.818,106.42],[106.871,5.81],[107.005,-2.165],[6.393,-106.219],[2.433,-107.938]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[3.294,0],[0.073,0.002],[2.348,2.428],[0,0],[-5.01,4.845],[0,0],[-3.416,-0.07],[-2.347,-2.427],[0,0],[0.057,-3.376],[2.428,-2.346],[0,0]],"o":[[-0.072,0],[-3.376,-0.056],[0,0],[-4.845,-5.011],[0,0],[2.426,-2.347],[3.376,0.057],[0,0],[2.348,2.427],[-0.057,3.375],[0,0],[-2.375,2.295]],"v":[[-1.097,115.007],[-1.315,115.004],[-10.19,111.154],[-110.801,7.1],[-110.501,-10.773],[-6.448,-111.384],[2.551,-114.936],[11.426,-111.085],[112.037,-7.031],[115.589,1.967],[111.736,10.842],[7.684,111.454]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.102000000898,0.102000000898,0.102000000898,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":[256.221,255.966],"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":"Group 6","np":4,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.315,-8.041],[0,0],[-8.04,-8.316],[0,0],[-8.315,8.041],[0,0],[8.041,8.316],[0,0]],"o":[[0,0],[-8.315,8.04],[0,0],[8.041,8.315],[0,0],[8.316,-8.04],[0,0],[-8.04,-8.315]],"v":[[-12.856,-116.331],[-115.834,-16.759],[-116.332,12.856],[-16.76,115.833],[12.855,116.331],[115.832,16.759],[116.331,-12.856],[16.758,-115.833]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.905999995213,0.776000019148,0.226999993418,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":[256.839,256],"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":"Group 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":450,"st":0,"bm":0}],"markers":[]}
--------------------------------------------------------------------------------