diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e004982..4789362 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,6 +18,7 @@ jobs: build: # The type of runner that the job will run on runs-on: macos-latest + timeout-minutes: 120 # Steps represent a sequence of tasks that will be executed as part of the job steps: @@ -30,6 +31,9 @@ jobs: distribution: 'zulu' # See 'Supported distributions' for available options java-version: '17' + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -45,30 +49,15 @@ jobs: fileDir: './' encodedString: ${{ secrets.SIGNING_KEY }} - - name: Generate baseline profile - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 33 - avd-name: baselineProfGenerator - target: google_apis - arch: x86_64 - emulator-build: 9322596 - script: ./gradlew :benchmark:connectedBenchmarkAndroidTest -P android.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile - - - name: Move generated baseline profile to target folder - run: mv -f './benchmark/build/outputs/connected_android_test_additional_output/benchmark/connected/baselineProfGenerator(AVD) - 13/BaselineProfileGenerator_generate-baseline-prof.txt' ./app/src/main/baseline-prof.txt - - - name: Check baseline-prof file status - run: stat ./app/src/main/baseline-prof.txt - - - name: View some lines of baseline-prof file - run: head ./app/src/main/baseline-prof.txt - - - name: Build with Gradle - run: ./gradlew assemble + - name: Build release variant including baseline profile generation + run: ./gradlew :app:assembleRelease + -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile + -Pandroid.testoptions.manageddevices.emulator.gpu="swiftshader_indirect" + -Pandroid.experimental.testOptions.managedDevices.emulator.showKernelLogging=true + -Pandroid.experimental.androidTest.numManagedDeviceShards=1 + -Pandroid.experimental.testOptions.managedDevices.maxConcurrentDevices=1 - name: Build Release AAB - id: buildRelease run: ./gradlew bundleRelease - name: Upload Android Release to Play Store diff --git a/.gitignore b/.gitignore index c567692..c44e4c7 100644 --- a/.gitignore +++ b/.gitignore @@ -78,7 +78,7 @@ captures/ *.keystore # Google Services (e.g. APIs or Firebase) -google-services.json +# google-services.json # Android Patch gen-external-apklibs @@ -120,6 +120,8 @@ obj/ .idea/jarRepositories.xml .idea/navEditor.xml .idea/inspectionProfiles +.idea/appInsightsSettings.xml +.idea/deploymentTargetDropDown.xml # Legacy Eclipse project files .classpath diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..23504e4 --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,45 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index ea9dbd0..0c0c338 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -1,17 +1,10 @@ - - - - - - - - - - - - + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..ae3f30a --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/baseline-profiles-rules.pro b/app/baseline-profiles-rules.pro deleted file mode 100644 index 0674e77..0000000 --- a/app/baseline-profiles-rules.pro +++ /dev/null @@ -1 +0,0 @@ --dontobfuscate \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index aa143c7..1fb13e6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,16 +1,17 @@ @Suppress("DSL_SCOPE_VIOLATION") plugins { - id("jumpkking.android.application") - id("jumpkking.android.application.compose") - id("jumpkking.android.hilt") + alias(libs.plugins.jumpkking.android.application) + alias(libs.plugins.jumpkking.android.application.compose) + alias(libs.plugins.jumpkking.android.hilt) alias(libs.plugins.gms.google.services) id("kotlin-parcelize") alias(libs.plugins.firebase.crashlytics) + alias(libs.plugins.androidx.baselineprofile) } kotlin { jvmToolchain { - languageVersion.set(JavaLanguageVersion.of(11)) + languageVersion.set(JavaLanguageVersion.of(17)) } } @@ -19,8 +20,9 @@ android { defaultConfig { applicationId = "com.joeloewi.jumpkking" - versionCode = 14 - versionName = "1.0.14" + versionCode = 15 + versionName = "1.0.15" + targetSdk = 34 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { @@ -50,14 +52,6 @@ android { ) signingConfig = signingConfigs.getByName("release") } - - val benchmark by creating { - initWith(release) - signingConfig = signingConfigs.getByName("release") - matchingFallbacks += listOf("release") - isDebuggable = false - proguardFiles("baseline-profiles-rules.pro") - } } packaging { @@ -67,6 +61,10 @@ android { } } +baselineProfile { + automaticGenerationDuringBuild = true +} + dependencies { implementation(project(":data")) implementation(project(":domain")) @@ -92,11 +90,9 @@ dependencies { //hilt implementation(libs.hilt.android) - kapt(libs.hilt.compiler) //hilt-extension implementation(libs.hilt.ext.work) - kapt(libs.hilt.ext.compiler) //compose implementation(libs.androidx.compose.foundation) @@ -140,9 +136,9 @@ dependencies { ///firebase implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.analytics.ktx) - implementation(libs.firebase.crashlytics.ktx) - implementation(libs.firebase.firestore.ktx) + implementation(libs.firebase.analytics) + implementation(libs.firebase.crashlytics) + implementation(libs.firebase.firestore) implementation(libs.tts) @@ -154,8 +150,6 @@ dependencies { implementation(libs.kotlinx.coroutines.rx3) implementation(libs.androidx.profileinstaller) -} -hilt { - enableAggregatingTask = true + implementation(libs.kotlinx.collections.immutable) } \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..038cae4 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "YourProjectId", + "project_id": "abc", + "storage_bucket": "abc" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "Your:App:Id", + "android_client_info": { + "package_name": "com.joeloewi.jumpkking" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "APlaceholderAPIKeyWith-ThirtyNineCharsX" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/androidTest/java/com/joeloewi/jumpkking/ExampleInstrumentedTest.kt b/app/src/androidTest/kotlin/com/joeloewi/jumpkking/ExampleInstrumentedTest.kt similarity index 100% rename from app/src/androidTest/java/com/joeloewi/jumpkking/ExampleInstrumentedTest.kt rename to app/src/androidTest/kotlin/com/joeloewi/jumpkking/ExampleInstrumentedTest.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9e108b7..d1e5e6e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,15 +22,9 @@ android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> - - - - diff --git a/app/src/main/java/com/joeloewi/jumpkking/di/UseCaseModule.kt b/app/src/main/java/com/joeloewi/jumpkking/di/UseCaseModule.kt deleted file mode 100644 index 6521231..0000000 --- a/app/src/main/java/com/joeloewi/jumpkking/di/UseCaseModule.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.joeloewi.jumpkking.di - -import com.joeloewi.domain.repository.FirebaseAuthRepository -import com.joeloewi.domain.repository.ReportCardRepository -import com.joeloewi.domain.repository.ValuesRepository -import com.joeloewi.domain.usecase.FirebaseAuthUseCase -import com.joeloewi.domain.usecase.ReportCardUseCase -import com.joeloewi.domain.usecase.ValuesUseCase -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object UseCaseModule { - - @Provides - @Singleton - fun provideGetValuesUseCase(valuesRepository: ValuesRepository): ValuesUseCase.GetValues = - ValuesUseCase.GetValues(valuesRepository) - - @Provides - @Singleton - fun provideSetJumpCountValuesUseCase(valuesRepository: ValuesRepository): ValuesUseCase.SetJumpCount = - ValuesUseCase.SetJumpCount(valuesRepository) - - @Provides - @Singleton - fun provideGetAllPagedReportCardUseCase(reportCardRepository: ReportCardRepository): ReportCardUseCase.GetAllPaged = - ReportCardUseCase.GetAllPaged(reportCardRepository) - - @Provides - @Singleton - fun provideInsertReportCardUseCase(reportCardRepository: ReportCardRepository): ReportCardUseCase.Insert = - ReportCardUseCase.Insert(reportCardRepository) - - @Provides - @Singleton - fun provideGetOneReportCardUseCase(reportCardRepository: ReportCardRepository): ReportCardUseCase.GetOne = - ReportCardUseCase.GetOne(reportCardRepository) - - @Provides - @Singleton - fun provideGetCurrentUserFirebaseAuthUseCase(firebaseAuthRepository: FirebaseAuthRepository): FirebaseAuthUseCase.GetCurrentUser = - FirebaseAuthUseCase.GetCurrentUser(firebaseAuthRepository) - - @Provides - @Singleton - fun provideSignInAnonymouslyFirebaseAuthUseCase(firebaseAuthRepository: FirebaseAuthRepository): FirebaseAuthUseCase.SignInAnonymously = - FirebaseAuthUseCase.SignInAnonymously(firebaseAuthRepository) -} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/initializer/ComposeViewInitializer.kt b/app/src/main/java/com/joeloewi/jumpkking/initializer/ComposeViewInitializer.kt deleted file mode 100644 index c3a12bd..0000000 --- a/app/src/main/java/com/joeloewi/jumpkking/initializer/ComposeViewInitializer.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.joeloewi.jumpkking.initializer - -import android.content.Context -import androidx.compose.ui.platform.ComposeView -import androidx.lifecycle.ProcessLifecycleInitializer -import androidx.startup.Initializer - -class ComposeViewInitializer : Initializer { - override fun create(context: Context): ComposeView { - return ComposeView(context) - } - - override fun dependencies(): MutableList>> = mutableListOf( - ProcessLifecycleInitializer::class.java - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/state/FriendsState.kt b/app/src/main/java/com/joeloewi/jumpkking/state/FriendsState.kt deleted file mode 100644 index b8a1594..0000000 --- a/app/src/main/java/com/joeloewi/jumpkking/state/FriendsState.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.joeloewi.jumpkking.state - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable -import androidx.compose.runtime.remember -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation.NavController -import com.google.firebase.crashlytics.internal.model.ImmutableList -import com.joeloewi.jumpkking.ui.navigation.friends.FriendsDestination -import com.joeloewi.jumpkking.viewmodel.FriendsViewModel - -@Stable -class FriendsState( - private val navController: NavController, - val friends: ImmutableList, - private val friendsViewModel: FriendsViewModel -) { - val insertReportCardState - @Composable get() = friendsViewModel.insertReportCardState.collectAsStateWithLifecycle().value - - val jumpCount - @Composable get() = friendsViewModel.jumpCount.collectAsStateWithLifecycle().value - - val textToSpeech - @Composable get() = friendsViewModel.textToSpeech.collectAsStateWithLifecycle().value - - fun increaseJumpCount() { - friendsViewModel.increaseJumpCount() - } - - fun onViewRankingButtonClick() { - navController.navigate(FriendsDestination.RankingScreen.route) - } -} - -enum class Friend { - Hamster, Cat -} - -@Composable -fun rememberFriendsState( - navController: NavController, - friends: ImmutableList = ImmutableList.from(*Friend.values()), - friendsViewModel: FriendsViewModel -) = remember( - navController, - friends, - friendsViewModel -) { - FriendsState( - navController = navController, - friends = friends, - friendsViewModel = friendsViewModel - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/state/RankingState.kt b/app/src/main/java/com/joeloewi/jumpkking/state/RankingState.kt deleted file mode 100644 index 06ae002..0000000 --- a/app/src/main/java/com/joeloewi/jumpkking/state/RankingState.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.joeloewi.jumpkking.state - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable -import androidx.compose.runtime.remember -import androidx.navigation.NavController -import androidx.paging.compose.collectAsLazyPagingItems -import com.joeloewi.jumpkking.viewmodel.RankingViewModel -import kotlinx.coroutines.Dispatchers - -@Stable -class RankingState( - private val navController: NavController, - private val rankingViewModel: RankingViewModel -) { - val androidId: String - get() = rankingViewModel.androidId - - val pagedReportCards - @Composable get() = rankingViewModel.pagedReportCards.collectAsLazyPagingItems(Dispatchers.IO) - - fun onCloseButtonClick() { - navController.navigateUp() - } -} - -@Composable -fun rememberRankingState( - navController: NavController, - rankingViewModel: RankingViewModel -) = remember( - navController, - rankingViewModel -) { - RankingState( - navController = navController, - rankingViewModel = rankingViewModel - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/theme/Theme.kt b/app/src/main/java/com/joeloewi/jumpkking/ui/theme/Theme.kt deleted file mode 100644 index 21f218c..0000000 --- a/app/src/main/java/com/joeloewi/jumpkking/ui/theme/Theme.kt +++ /dev/null @@ -1,32 +0,0 @@ -package com.joeloewi.jumpkking.ui.theme - -import android.view.Window -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect -import androidx.compose.ui.platform.LocalView -import androidx.core.view.WindowCompat -import com.google.accompanist.themeadapter.material3.Mdc3Theme - -@Composable -fun JumpKkingTheme( - window: Window, - content: @Composable () -> Unit -) { - val useDarkIcons = !isSystemInDarkTheme() - val view = LocalView.current - - if (!view.isInEditMode) { - SideEffect { - WindowCompat.setDecorFitsSystemWindows(window, false) - WindowCompat.getInsetsController(window, view).apply { - isAppearanceLightStatusBars = useDarkIcons - isAppearanceLightNavigationBars = useDarkIcons - } - } - } - - Mdc3Theme( - content = content - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/JumpKkingApplication.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/JumpKkingApplication.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/JumpKkingApplication.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/JumpKkingApplication.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/MainActivity.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/MainActivity.kt similarity index 87% rename from app/src/main/java/com/joeloewi/jumpkking/MainActivity.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/MainActivity.kt index 3a770ca..f1fd0a1 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/MainActivity.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/MainActivity.kt @@ -2,6 +2,7 @@ package com.joeloewi.jumpkking import android.os.Bundle import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.shape.CornerSize @@ -17,7 +18,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle @@ -37,9 +37,7 @@ import com.joeloewi.jumpkking.ui.navigation.friends.screen.FriendsScreen import com.joeloewi.jumpkking.ui.navigation.friends.screen.RankingScreen import com.joeloewi.jumpkking.ui.theme.JumpKkingTheme import com.joeloewi.jumpkking.util.LocalActivity -import com.joeloewi.jumpkking.viewmodel.FriendsViewModel import com.joeloewi.jumpkking.viewmodel.MainViewModel -import com.joeloewi.jumpkking.viewmodel.RankingViewModel import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach @@ -53,6 +51,9 @@ class MainActivity : AppCompatActivity() { val splashScreen = installSplashScreen() super.onCreate(savedInstanceState) + DynamicColors.applyToActivityIfAvailable(this) + enableEdgeToEdge() + var currentUser by mutableStateOf>(Lce.Loading) lifecycleScope.launch { @@ -67,12 +68,8 @@ class MainActivity : AppCompatActivity() { currentUser.isLoading } - DynamicColors.applyToActivityIfAvailable(this) - setContent { - JumpKkingTheme( - window = window - ) { + JumpKkingTheme { CompositionLocalProvider(LocalActivity provides this) { JumpKkingApp() } @@ -90,6 +87,7 @@ fun JumpKkingApp() { ) val bottomSheetNavigator = remember(sheetState) { BottomSheetNavigator(sheetState) } val navController = rememberNavController(bottomSheetNavigator) + val activity = LocalActivity.current ModalBottomSheetLayout( sheetShape = MaterialTheme.shapes.large.copy( @@ -103,7 +101,7 @@ fun JumpKkingApp() { ) { NavHost( navController = navController, - route = "main", + route = activity::class.java.simpleName, startDestination = JumpKkingNavigation.Friends.route ) { navigation( @@ -111,20 +109,18 @@ fun JumpKkingApp() { route = JumpKkingNavigation.Friends.route ) { composable(route = FriendsDestination.FriendsScreen.route) { - val friendsViewModel: FriendsViewModel = hiltViewModel() - FriendsScreen( - navController = navController, - friendsViewModel = friendsViewModel + onViewRankingButtonClick = { + navController.navigate(FriendsDestination.RankingScreen.route) + } ) } bottomSheet(route = FriendsDestination.RankingScreen.route) { - val rankingViewModel: RankingViewModel = hiltViewModel() - RankingScreen( - navController = navController, - rankingViewModel = rankingViewModel + onCloseButtonClick = { + navController.navigateUp() + } ) } } diff --git a/app/src/main/java/com/joeloewi/jumpkking/di/InitializerEntryPoint.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/di/InitializerEntryPoint.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/di/InitializerEntryPoint.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/di/InitializerEntryPoint.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/di/UtilModule.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/di/UtilModule.kt similarity index 67% rename from app/src/main/java/com/joeloewi/jumpkking/di/UtilModule.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/di/UtilModule.kt index e592e58..0219531 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/di/UtilModule.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/di/UtilModule.kt @@ -7,12 +7,19 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent +import nl.marc_apps.tts.TextToSpeechEngine +import nl.marc_apps.tts.TextToSpeechFactory import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) class UtilModule { + @Provides + fun provideTextToSpeechFactory( + @ApplicationContext context: Context + ): TextToSpeechFactory = TextToSpeechFactory(context, TextToSpeechEngine.SystemDefault) + @Provides @Singleton fun provideImageLoader(@ApplicationContext context: Context): ImageLoader = diff --git a/app/src/main/java/com/joeloewi/jumpkking/initializer/CoilInitializer.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/initializer/CoilInitializer.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/initializer/CoilInitializer.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/initializer/CoilInitializer.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/initializer/DynamicColorInitializer.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/initializer/DynamicColorInitializer.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/initializer/DynamicColorInitializer.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/initializer/DynamicColorInitializer.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/state/Lce.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/state/Lce.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/state/Lce.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/state/Lce.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/JumpKkingNavigation.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/JumpKkingNavigation.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/ui/navigation/JumpKkingNavigation.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/JumpKkingNavigation.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/FriendsDestination.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/FriendsDestination.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/FriendsDestination.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/FriendsDestination.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt similarity index 66% rename from app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt index 684e8a5..6f4a2f4 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/FriendsScreen.kt @@ -1,37 +1,70 @@ package com.joeloewi.jumpkking.ui.navigation.friends.screen -import androidx.compose.animation.* +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.SizeTransform +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.togetherWith import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.absoluteOffset +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PageSize import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Leaderboard -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.composed import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.navigation.NavController +import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil.compose.AsyncImage import coil.request.ImageRequest import com.google.accompanist.pager.HorizontalPagerIndicator import com.joeloewi.jumpkking.R -import com.joeloewi.jumpkking.state.Friend -import com.joeloewi.jumpkking.state.FriendsState import com.joeloewi.jumpkking.state.Lce -import com.joeloewi.jumpkking.state.rememberFriendsState -import com.joeloewi.jumpkking.util.* +import com.joeloewi.jumpkking.util.RoundTripState +import com.joeloewi.jumpkking.util.RoundTripValue +import com.joeloewi.jumpkking.util.animateRoundTripByDpAsState +import com.joeloewi.jumpkking.util.castToQuotaReachedExceptionAndGetMessage +import com.joeloewi.jumpkking.util.rememberRoundTripState +import com.joeloewi.jumpkking.viewmodel.Friend import com.joeloewi.jumpkking.viewmodel.FriendsViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import nl.marc_apps.tts.TextToSpeechInstance @@ -39,35 +72,39 @@ import java.text.DecimalFormat @Composable fun FriendsScreen( - navController: NavController, + onViewRankingButtonClick: () -> Unit, friendsViewModel: FriendsViewModel = hiltViewModel() ) { - val friendsState = rememberFriendsState( - navController = navController, - friendsViewModel = friendsViewModel - ) + val jumpCount by friendsViewModel.jumpCount.collectAsStateWithLifecycle() + val textToSpeech by friendsViewModel.textToSpeech.collectAsStateWithLifecycle() + val insertReportCardState by friendsViewModel.insertReportCardState.collectAsStateWithLifecycle() - FriendsContent(friendsState = friendsState) + FriendsContent( + jumpCount = { jumpCount }, + textToSpeech = { textToSpeech }, + insertReportCardState = { insertReportCardState }, + onViewRankingButtonClick = onViewRankingButtonClick, + onCountChange = friendsViewModel::increaseJumpCount + ) } -@OptIn( - ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class, -) +@OptIn(ExperimentalFoundationApi::class) @Composable private fun FriendsContent( - friendsState: FriendsState, + jumpCount: () -> Long, + textToSpeech: () -> Lce, + insertReportCardState: () -> Lce, + onViewRankingButtonClick: () -> Unit, + onCountChange: () -> Unit ) { val snackbarHostState = remember { SnackbarHostState() } - val jumpCount = friendsState.jumpCount - val textToSpeech = friendsState.textToSpeech - val pagerState = rememberPagerState() - val insertReportCardState = friendsState.insertReportCardState + val pagerState = rememberPagerState { Friend.entries.size } - LaunchedEffect(insertReportCardState) { - with(insertReportCardState) { - when (this) { + LaunchedEffect(Unit) { + snapshotFlow(insertReportCardState).catch { }.flowOn(Dispatchers.IO).collect { + when (it) { is Lce.Error -> { - val message = error.castToQuotaReachedExceptionAndGetMessage() + val message = it.error.castToQuotaReachedExceptionAndGetMessage() with(snackbarHostState) { currentSnackbarData?.dismiss() @@ -101,8 +138,8 @@ private fun FriendsContent( .fillMaxWidth(), horizontalArrangement = Arrangement.Center ) { - AnimatedCount(count = jumpCount) - IconButton(onClick = friendsState::onViewRankingButtonClick) { + AnimatedCount(count = jumpCount()) + IconButton(onClick = onViewRankingButtonClick) { Icon( imageVector = Icons.Default.Leaderboard, contentDescription = Icons.Default.Leaderboard.name @@ -115,11 +152,10 @@ private fun FriendsContent( ) { HorizontalPager( state = pagerState, - pageCount = friendsState.friends.size, pageSize = PageSize.Fill, - key = { Friend.values()[it].name } + key = { Friend.entries[it].name } ) { page -> - when (Friend.values()[page]) { + when (Friend.entries[page]) { Friend.Hamster -> { val configuration = LocalConfiguration.current val maxOffset by remember(configuration) { @@ -132,14 +168,14 @@ private fun FriendsContent( HamsterCard( textToSpeech = textToSpeech, roundTripState = roundTripState, - onCountChange = friendsState::increaseJumpCount + onCountChange = onCountChange ) } Friend.Cat -> { CatCard( textToSpeech = textToSpeech, - onCountChange = friendsState::increaseJumpCount + onCountChange = onCountChange ) } } @@ -151,14 +187,13 @@ private fun FriendsContent( ) { HorizontalPagerIndicator( pagerState = pagerState, - pageCount = friendsState.friends.size + pageCount = Friend.entries.size ) } } } } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun AnimatedCount( count: Long, @@ -167,15 +202,15 @@ private fun AnimatedCount( targetState = count, transitionSpec = { if (targetState > initialState) { - slideInVertically { height -> height } + fadeIn() with + slideInVertically { height -> height } + fadeIn() togetherWith slideOutVertically { height -> -height } + fadeOut() } else { - slideInVertically { height -> -height } + fadeIn() with + slideInVertically { height -> -height } + fadeIn() togetherWith slideOutVertically { height -> height } + fadeOut() }.using( SizeTransform(clip = false) ) - } + }, label = "" ) { targetCount -> Text( modifier = Modifier, @@ -188,7 +223,7 @@ private fun AnimatedCount( @Composable private fun HamsterCard( - textToSpeech: Lce, + textToSpeech: () -> Lce, roundTripState: RoundTripState, onCountChange: () -> Unit ) { @@ -215,7 +250,7 @@ private fun HamsterCard( @Composable private fun CatCard( - textToSpeech: Lce, + textToSpeech: () -> Lce, onCountChange: () -> Unit ) { Card( @@ -240,7 +275,7 @@ private fun CatCard( @Composable private fun CatImage( - textToSpeech: Lce, + textToSpeech: () -> Lce, onCountChange: () -> Unit ) { val meowing = remember { "뫼애앵" } @@ -269,14 +304,14 @@ private fun CatImage( .clickable( indication = null, interactionSource = remember { MutableInteractionSource() }, - enabled = textToSpeech is Lce.Content && !isTtsPlaying + enabled = textToSpeech() is Lce.Content && !isTtsPlaying ) { onCountChange() coroutineScope.launch(Dispatchers.IO) { onIsTtsPlayingChange(true) - textToSpeech.content?.runCatching { + textToSpeech().content?.runCatching { say( text = meowing, clearQueue = true, @@ -297,39 +332,35 @@ private fun CatImage( @Composable private fun HamsterImage( - textToSpeech: Lce, + textToSpeech: () -> Lce, roundTripState: RoundTripState, onCountChange: () -> Unit ) { val kking = remember { "끼잉!" } val coroutineScope = rememberCoroutineScope() - val lifecycleOwner = LocalLifecycleOwner.current val context = LocalContext.current val roundTripValue = roundTripState.roundTripValue - val roundTripAnimationOffset by animateRoundTripByDpAsState(roundTripState = roundTripState) - val idleHamster = remember(context, lifecycleOwner) { - ImageRequest.Builder(context) - .data(R.drawable.idle_hamster) - .lifecycle(lifecycleOwner) - .build() - } - val jumpingHamster = remember(context, lifecycleOwner) { - ImageRequest.Builder(context) - .data(R.drawable.jumping_hamster) - .lifecycle(lifecycleOwner) - .build() - } + val idleHamster = ImageRequest.Builder(context) + .data(R.drawable.idle_hamster) + .build() + val jumpingHamster = ImageRequest.Builder(context) + .data(R.drawable.jumping_hamster) + .build() AsyncImage( modifier = Modifier .fillMaxWidth(0.4f) .aspectRatio(1.0f) .padding(bottom = 16.dp) - .absoluteOffset(y = roundTripAnimationOffset) + .composed { + val roundTripAnimationOffset by animateRoundTripByDpAsState(roundTripState = roundTripState) + + absoluteOffset(y = roundTripAnimationOffset) + } .clickable( indication = null, interactionSource = remember { MutableInteractionSource() }, - enabled = roundTripValue.isIdle && textToSpeech is Lce.Content + enabled = roundTripValue.isIdle && textToSpeech() is Lce.Content ) { onCountChange() @@ -338,16 +369,13 @@ private fun HamsterImage( roundTripState.start() } - textToSpeech.content + textToSpeech().content ?.runCatching { say( text = kking, clearQueue = true ) } - ?.onFailure { cause -> - cause.printStackTrace() - } } }, model = when (roundTripValue) { diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt similarity index 72% rename from app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt index e4783ea..199dbbb 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/navigation/friends/screen/RankingScreen.kt @@ -1,53 +1,80 @@ package com.joeloewi.jumpkking.ui.navigation.friends.screen import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.* -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Leaderboard +import androidx.compose.material.icons.filled.Refresh +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import androidx.navigation.NavController +import androidx.hilt.navigation.compose.hiltViewModel import androidx.paging.LoadState -import androidx.paging.compose.itemsIndexed +import androidx.paging.compose.LazyPagingItems +import androidx.paging.compose.collectAsLazyPagingItems +import androidx.paging.compose.itemKey import coil.compose.AsyncImage import coil.request.ImageRequest import com.google.accompanist.placeholder.PlaceholderHighlight import com.google.accompanist.placeholder.fade import com.google.accompanist.placeholder.placeholder -import com.joeloewi.jumpkking.state.RankingState -import com.joeloewi.jumpkking.state.rememberRankingState +import com.joeloewi.domain.entity.ReportCard import com.joeloewi.jumpkking.util.castToQuotaReachedExceptionAndGetMessage import com.joeloewi.jumpkking.viewmodel.RankingViewModel import java.text.DecimalFormat @Composable fun RankingScreen( - navController: NavController, - rankingViewModel: RankingViewModel + onCloseButtonClick: () -> Unit, + rankingViewModel: RankingViewModel = hiltViewModel() ) { - val rankingState = rememberRankingState( - navController = navController, - rankingViewModel = rankingViewModel - ) + val pagedReportCards = rankingViewModel.pagedReportCards.collectAsLazyPagingItems() + val androidId = rankingViewModel.androidId RankingContent( - rankingState = rankingState + pagedReportCards = pagedReportCards, + androidId = androidId, + onCloseButtonClick = onCloseButtonClick ) } @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable private fun RankingContent( - rankingState: RankingState + pagedReportCards: LazyPagingItems, + androidId: String, + onCloseButtonClick: () -> Unit ) { val snackbarHostState = remember { SnackbarHostState() } - val pagedReportCards = rankingState.pagedReportCards LaunchedEffect(pagedReportCards.loadState) { val loadStates = mutableListOf() @@ -120,7 +147,7 @@ private fun RankingContent( }, actions = { IconButton( - onClick = rankingState::onCloseButtonClick + onClick = onCloseButtonClick ) { Icon( imageVector = Icons.Default.Close, @@ -137,13 +164,14 @@ private fun RankingContent( .padding(innerPadding) .fillMaxSize() ) { - itemsIndexed( - pagedReportCards, - key = { _, item -> item.androidId } - ) { index, item -> + items( + count = pagedReportCards.itemCount, + key = pagedReportCards.itemKey { it.androidId } + ) { index -> + val item = runCatching { pagedReportCards[index] }.getOrNull() + if (item != null) { - val isMyReportCard = - item.androidId == rankingState.androidId + val isMyReportCard = item.androidId == androidId val backgroundColor = if (isMyReportCard) { @@ -160,10 +188,10 @@ private fun RankingContent( leadingContent = { Text(text = "${index + 1}") }, - headlineText = { + headlineContent = { Text(text = DecimalFormat.getInstance().format(item.jumpCount)) }, - supportingText = if (isMyReportCard) { + supportingContent = if (isMyReportCard) { { Text( text = "나" @@ -181,7 +209,6 @@ private fun RankingContent( } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ReportCardListItemPlaceHolder( isPlaceholderVisible: Boolean = true @@ -206,7 +233,7 @@ private fun ReportCardListItemPlaceHolder( contentDescription = null ) }, - headlineText = { + headlineContent = { Text( modifier = Modifier .fillMaxWidth() @@ -220,7 +247,7 @@ private fun ReportCardListItemPlaceHolder( text = "" ) }, - supportingText = { + supportingContent = { Text( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/java/com/joeloewi/jumpkking/ui/theme/ContentAlpha.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/theme/ContentAlpha.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/ui/theme/ContentAlpha.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/ui/theme/ContentAlpha.kt diff --git a/app/src/main/kotlin/com/joeloewi/jumpkking/ui/theme/Theme.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/theme/Theme.kt new file mode 100644 index 0000000..e148989 --- /dev/null +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/ui/theme/Theme.kt @@ -0,0 +1,33 @@ +package com.joeloewi.jumpkking.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +fun JumpKkingTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> darkColorScheme() + else -> lightColorScheme() + } + + MaterialTheme( + colorScheme = colorScheme, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/util/LifecycleExtensions.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/util/LifecycleExtensions.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/util/LifecycleExtensions.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/util/LifecycleExtensions.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/util/LocalActivity.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/util/LocalActivity.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/util/LocalActivity.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/util/LocalActivity.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt similarity index 94% rename from app/src/main/java/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt index e9cafe5..f19380a 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/util/RoundTripOffsetAnimation.kt @@ -19,12 +19,12 @@ import kotlinx.coroutines.suspendCancellableCoroutine sealed class RoundTripValue { open val isIdle: Boolean = false - object Idle : RoundTripValue() { + data object Idle : RoundTripValue() { override val isIdle: Boolean = true } - object Going : RoundTripValue() - object TurningBack : RoundTripValue() + data object Going : RoundTripValue() + data object TurningBack : RoundTripValue() } @Stable @@ -97,5 +97,5 @@ fun animateRoundTripByDpAsState( coroutineScope.launch { roundTripState.doTurnBackOrEnterIdle(it) } - } + }, label = "" ) \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/util/ThrowableExtensions.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/util/ThrowableExtensions.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/util/ThrowableExtensions.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/util/ThrowableExtensions.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt similarity index 90% rename from app/src/main/java/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt index d739c6c..ae10f11 100644 --- a/app/src/main/java/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt +++ b/app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/FriendsViewModel.kt @@ -1,6 +1,5 @@ package com.joeloewi.jumpkking.viewmodel -import android.app.Application import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.firebase.crashlytics.FirebaseCrashlytics @@ -25,14 +24,14 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.rx3.asFlowable import kotlinx.coroutines.rx3.asScheduler -import nl.marc_apps.tts.TextToSpeech +import nl.marc_apps.tts.TextToSpeechFactory import okhttp3.internal.closeQuietly import java.util.concurrent.TimeUnit import javax.inject.Inject @HiltViewModel class FriendsViewModel @Inject constructor( - private val application: Application, + private val textToSpeechFactory: TextToSpeechFactory, private val getValuesUseCase: ValuesUseCase.GetValues, private val setJumpCountUseCase: ValuesUseCase.SetJumpCount, private val setReportCardUseCase: ReportCardUseCase.Insert, @@ -45,7 +44,7 @@ class FriendsViewModel @Inject constructor( private val _jumpCount = _values.map { it.jumpCount } private val _throttledJumpCount = _jumpCount .flowOn(Dispatchers.IO) - .asFlowable(viewModelScope.coroutineContext) + .asFlowable(Dispatchers.IO) .observeOn(_ioScheduler) .throttleLatest(5, TimeUnit.SECONDS) .subscribeOn(_ioScheduler) @@ -74,19 +73,19 @@ class FriendsViewModel @Inject constructor( Lce.Error(cause) } ) - }.flowOn(Dispatchers.IO).stateIn( + }.catch { }.flowOn(Dispatchers.IO).stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(), initialValue = Lce.Loading ) - val jumpCount = _jumpCount.stateIn( + val jumpCount = _jumpCount.catch { }.flowOn(Dispatchers.IO).stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(), initialValue = Values().jumpCount ) val textToSpeech = callbackFlow { - val textToSpeechInstance = TextToSpeech.runCatching { - createOrThrow(application) + val textToSpeechInstance = textToSpeechFactory.runCatching { + createOrThrow() }.fold( onSuccess = { Lce.Content(it) @@ -105,7 +104,7 @@ class FriendsViewModel @Inject constructor( } FirebaseCrashlytics.getInstance().recordException(cause) - }.stateIn( + }.flowOn(Dispatchers.IO).stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(), initialValue = Lce.Loading @@ -116,4 +115,8 @@ class FriendsViewModel @Inject constructor( setJumpCountUseCase(getValuesUseCase().first().jumpCount + 1) } } +} + +enum class Friend { + Hamster, Cat } \ No newline at end of file diff --git a/app/src/main/java/com/joeloewi/jumpkking/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/MainViewModel.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/viewmodel/MainViewModel.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/MainViewModel.kt diff --git a/app/src/main/java/com/joeloewi/jumpkking/viewmodel/RankingViewModel.kt b/app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/RankingViewModel.kt similarity index 100% rename from app/src/main/java/com/joeloewi/jumpkking/viewmodel/RankingViewModel.kt rename to app/src/main/kotlin/com/joeloewi/jumpkking/viewmodel/RankingViewModel.kt diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 4bdceec..f75a2f2 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,10 +1,7 @@ - +