Skip to content

Commit

Permalink
Merge pull request #317 from joeloewi7178/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
joeloewi7178 committed Jan 3, 2024
2 parents 0209c9f + 0af760f commit 9ee5045
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 32 deletions.
6 changes: 2 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ android {

defaultConfig {
applicationId = "com.joeloewi.croissant"
versionCode = 44
versionCode = 45
versionName = "1.2.1"
targetSdk = 34

Expand Down Expand Up @@ -151,8 +151,6 @@ dependencies {

implementation(libs.androidx.profileinstaller)

implementation(libs.tts)

//open source license activity
implementation(libs.gms.play.services.oss.licenses)
}
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@

<data android:scheme="*" />
</intent>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>

<permission
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/kotlin/com/joeloewi/croissant/di/UtilModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.joeloewi.croissant.R
import com.joeloewi.croissant.util.AlarmScheduler
import com.joeloewi.croissant.util.NotificationGenerator
import com.joeloewi.croissant.util.TextToSpeechFactory
import com.joeloewi.croissant.util.impl.AlarmSchedulerImpl
import com.joeloewi.croissant.util.impl.RunnableSchedulerImpl
import dagger.Binds
Expand All @@ -18,8 +19,6 @@ 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 okhttp3.OkHttpClient
import javax.inject.Singleton

Expand All @@ -44,7 +43,7 @@ object UtilModule {
@Provides
fun provideTextToSpeechFactory(
@ApplicationContext context: Context
): TextToSpeechFactory = TextToSpeechFactory(context, TextToSpeechEngine.SystemDefault)
): TextToSpeechFactory = TextToSpeechFactory(context)

@Provides
fun provideNotificationGenerator(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.joeloewi.croissant.ui.navigation.main.global.screen

import android.app.AlarmManager
import android.content.pm.PackageManager
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
Expand All @@ -8,8 +10,13 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.joeloewi.croissant.util.CroissantPermission
import com.joeloewi.croissant.util.canScheduleExactAlarmsCompat
import com.joeloewi.croissant.viewmodel.EmptyViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
Expand Down Expand Up @@ -37,13 +44,25 @@ private fun EmptyContent(
onShowFirstLaunchScreen: () -> Unit,
onShowDefaultScreen: () -> Unit
) {
val context = LocalContext.current

LaunchedEffect(Unit) {
withContext(Dispatchers.IO) {
snapshotFlow { isFirstLaunch() }.catch { }.filterNotNull()
.collect { showFirstLaunchScreen ->
withContext(Dispatchers.Main) {
if (showFirstLaunchScreen) {
val anyOfPermissionsIsDenied = listOf(
CroissantPermission.AccessHoYoLABSession.permission,
CroissantPermission.PostNotifications.permission
).any {
ContextCompat.checkSelfPermission(
context,
it
) == PackageManager.PERMISSION_DENIED
} || context.getSystemService<AlarmManager>()
?.canScheduleExactAlarmsCompat() == false

if (showFirstLaunchScreen || anyOfPermissionsIsDenied) {
onShowFirstLaunchScreen()
} else {
onShowDefaultScreen()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionStatus
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.joeloewi.croissant.R
import com.joeloewi.croissant.ui.theme.DefaultDp
Expand Down Expand Up @@ -101,7 +102,7 @@ private fun FirstLaunchContent(
CroissantPermission.PostNotifications.permission
),
onPermissionsResult = {
if (scheduleExactAlarmPermissionState.status != PermissionStatus.Granted) {
if (!scheduleExactAlarmPermissionState.status.isGranted) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.joeloewi.croissant.ui.navigation.main.settings.screen

import android.content.Intent
import android.net.Uri
import android.speech.tts.TextToSpeech
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -37,6 +38,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.os.bundleOf
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
Expand All @@ -49,7 +51,6 @@ import com.joeloewi.croissant.util.navigationIconButton
import com.joeloewi.croissant.viewmodel.DeveloperInfoViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import nl.marc_apps.tts.TextToSpeechInstance

@Composable
fun DeveloperInfoScreen(
Expand All @@ -67,7 +68,7 @@ fun DeveloperInfoScreen(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun DeveloperInfoContent(
textToSpeech: () -> LCE<TextToSpeechInstance>,
textToSpeech: () -> LCE<TextToSpeech>,
onNavigateUp: () -> Unit
) {
val activity = LocalActivity.current
Expand Down Expand Up @@ -111,7 +112,12 @@ private fun DeveloperInfoContent(
) {
coroutineScope.launch(Dispatchers.IO) {
textToSpeech().content?.runCatching {
say("안아줘요", true)
speak(
"안아줘요",
TextToSpeech.QUEUE_FLUSH,
bundleOf(),
"hug_me"
)
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.joeloewi.croissant.util

import android.content.Context
import android.speech.tts.TextToSpeech
import com.joeloewi.croissant.state.foldAsLce
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import java.util.Locale
import javax.inject.Inject

class TextToSpeechFactory @Inject constructor(
@ApplicationContext private val context: Context
) {
val flow = callbackFlow {
var textToSpeech: TextToSpeech? = null

textToSpeech = TextToSpeech(context) { status ->
trySend(runCatching {
if (status != TextToSpeech.SUCCESS) {
throw IllegalStateException()
}
textToSpeech!!.apply {
val currentLocale = Locale.getDefault()
val targetLocale = if (availableLanguages.contains(currentLocale)) {
currentLocale
} else {
Locale.ENGLISH
}
language = targetLocale
}
}.foldAsLce())
}

awaitClose {
with(textToSpeech) {
stop()
shutdown()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,20 @@ package com.joeloewi.croissant.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.joeloewi.croissant.state.LCE
import com.joeloewi.croissant.util.TextToSpeechFactory
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
import nl.marc_apps.tts.TextToSpeechFactory
import javax.inject.Inject

@HiltViewModel
class DeveloperInfoViewModel @Inject constructor(
private val textToSpeechFactory: TextToSpeechFactory
textToSpeechFactory: TextToSpeechFactory
) : ViewModel() {
val textToSpeech = callbackFlow {
val textToSpeech = textToSpeechFactory.runCatching {
createOrThrow()
}.fold(
onSuccess = {
LCE.Content(it)
},
onFailure = {
LCE.Error(it)
}
)

trySend(textToSpeech)

awaitClose { textToSpeech.content?.close() }
}.catch { }.flowOn(Dispatchers.IO).stateIn(
val textToSpeech = textToSpeechFactory.flow.catch { }.flowOn(Dispatchers.IO).stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
initialValue = LCE.Loading
Expand Down

0 comments on commit 9ee5045

Please sign in to comment.