diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index be02827..4e2dae5 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -5,7 +5,6 @@ plugins {
alias(libs.plugins.googlePlayServices)
alias(libs.plugins.googleOssServices)
alias(libs.plugins.googleFirebase)
- alias(libs.plugins.googleDaggerHilt)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.devToolsKsp)
}
@@ -144,9 +143,6 @@ dependencies {
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.room.runtime)
- ksp(libs.hilt.android.compiler)
- implementation(libs.hilt.android)
- implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
// Kotlin
implementation(libs.kotlinx.coroutines.android)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 184d8cb..7f98d19 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,7 @@
+
@@ -139,7 +140,7 @@
+ android:value="ca-app-pub-5294151573817700~8003610653" />
{
- Utils.openActivity(
+ IntentUtils.openActivity(
context, SettingsActivity::class.java
)
}
R.string.help_and_feedback -> {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, HelpActivity::class.java
)
}
R.string.updates -> {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://github.com/D4rK7355608/${context.packageName}/blob/master/CHANGELOG.md"
)
}
R.string.share -> {
- Utils.shareApp(context)
+ IntentUtils.shareApp(context)
}
}
scope.launch {
@@ -147,7 +147,7 @@ fun MainComposable() {
},
actions = {
IconButton(onClick = {
- Utils.openActivity(context, SupportActivity::class.java)
+ IntentUtils.openActivity(context, SupportActivity::class.java)
}) {
Icon(
Icons.Outlined.VolunteerActivism, contentDescription = "Support"
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/ads/AdsConstants.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/ads/AdsConstants.kt
index 8215b22..ee98491 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/ads/AdsConstants.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/ads/AdsConstants.kt
@@ -8,13 +8,13 @@ object AdsConstants {
get() = if (BuildConfig.DEBUG) {
"ca-app-pub-3940256099942544/6300978111"
} else {
- "ca-app-pub-5294151573817700/8040893463"
+ "ca-app-pub-5294151573817700/8479403125"
}
val APP_OPEN_UNIT_ID: String
get() = if (BuildConfig.DEBUG) {
"ca-app-pub-3940256099942544/9257395921"
} else {
- "ca-app-pub-5294151573817700/9208287867"
+ "ca-app-pub-5294151573817700/2885662643"
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/permissions/PermissionsConstants.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/permissions/PermissionsConstants.kt
new file mode 100644
index 0000000..94a2462
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/constants/permissions/PermissionsConstants.kt
@@ -0,0 +1,5 @@
+package com.d4rk.englishwithlidia.plus.constants.permissions
+
+object PermissionsConstants {
+ const val REQUEST_CODE_NOTIFICATION_PERMISSION = 2
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/data/model/ui/button/ButtonState.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/data/model/ui/button/ButtonState.kt
new file mode 100644
index 0000000..e9b43f9
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/data/model/ui/button/ButtonState.kt
@@ -0,0 +1,3 @@
+package com.d4rk.englishwithlidia.plus.data.model.ui.button
+
+enum class ButtonState { Pressed , Idle }
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/dialogs/VersionInfoDialogComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/dialogs/VersionInfoDialogComposable.kt
index 10ca790..8f05030 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/dialogs/VersionInfoDialogComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/dialogs/VersionInfoDialogComposable.kt
@@ -1,11 +1,5 @@
package com.d4rk.englishwithlidia.plus.ui.dialogs
-import android.content.res.Resources
-import android.graphics.Bitmap
-import android.graphics.Canvas
-import android.graphics.drawable.AdaptiveIconDrawable
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -25,6 +19,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.d4rk.englishwithlidia.plus.BuildConfig
import com.d4rk.englishwithlidia.plus.R
+import com.d4rk.englishwithlidia.plus.utils.drawable.toBitmapDrawable
@Composable
fun VersionInfoDialog(onDismiss: () -> Unit) {
@@ -73,20 +68,4 @@ fun VersionInfoContent() {
)
}
}
-}
-
-fun Drawable.toBitmapDrawable(): BitmapDrawable {
- return when (this) {
- is BitmapDrawable -> this
- is AdaptiveIconDrawable -> {
- val bitmap =
- Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
- val canvas = Canvas(bitmap)
- setBounds(0, 0, canvas.width, canvas.height)
- draw(canvas)
- BitmapDrawable(Resources.getSystem(), bitmap)
- }
-
- else -> throw IllegalArgumentException("Unsupported drawable type: ${this::class.java.name}")
- }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpActivity.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpActivity.kt
index 6c20c50..2863a92 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpActivity.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpActivity.kt
@@ -3,56 +3,27 @@ package com.d4rk.englishwithlidia.plus.ui.help
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.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.d4rk.englishwithlidia.plus.ui.settings.display.theme.style.AppTheme
-import com.d4rk.englishwithlidia.plus.utils.Utils
-import com.google.android.play.core.review.ReviewManager
-import com.google.android.play.core.review.ReviewManagerFactory
class HelpActivity : AppCompatActivity() {
- private lateinit var reviewManager: ReviewManager
- override fun onCreate(savedInstanceState: Bundle?) {
+ private val viewModel: HelpViewModel by viewModels()
+ override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
Surface(
- modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background
+ modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background
) {
- HelpComposable(this@HelpActivity)
+ HelpComposable(this@HelpActivity, viewModel)
}
}
}
-
- }
-
- /**
- * Initiates the feedback process for the app.
- *
- * This function uses the Google Play In-App Review API to prompt the user for feedback.
- * If the request to launch the in-app review flow is successful, the review dialog is displayed.
- * If the request fails, it opens the Google Play Store page for the app's reviews.
- *
- * @see com.google.android.play.core.review.ReviewManagerFactory
- * @see com.google.android.play.core.review.ReviewManager
- * @param context The context used to create the ReviewManager instance and launch review flows.
- */
- fun feedback() {
- reviewManager = ReviewManagerFactory.create(this)
- val task = reviewManager.requestReviewFlow()
- task.addOnSuccessListener { reviewInfo ->
- reviewManager.launchReviewFlow(this, reviewInfo)
- }.addOnFailureListener {
- Utils.openUrl(
- this,
- "https://play.google.com/store/apps/details?id=${this.packageName}&showAllReviews=true"
- )
- }.addOnFailureListener {
- Utils.sendEmailToDeveloper(this)
- }
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpComposable.kt
index 3a6ae3f..b019d17 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpComposable.kt
@@ -33,6 +33,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -46,80 +47,88 @@ import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.ui.dialogs.VersionInfoDialog
-import com.d4rk.englishwithlidia.plus.utils.Utils
-import com.d4rk.englishwithlidia.plus.utils.bounceClick
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.bounceClick
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun HelpComposable(activity: HelpActivity) {
+fun HelpComposable(activity : HelpActivity, viewModel: HelpViewModel) {
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
var showMenu by remember { mutableStateOf(false) }
val context = LocalContext.current
val showDialog = remember { mutableStateOf(false) }
- Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
- LargeTopAppBar(title = { Text(stringResource(R.string.help)) }, navigationIcon = {
+ val reviewInfo = viewModel.reviewInfo.value
+
+ if (reviewInfo != null) {
+ LaunchedEffect(key1 = reviewInfo) {
+ viewModel.requestReviewFlow()
+ }
+ }
+
+ Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = {
+ LargeTopAppBar(title = { Text(stringResource(R.string.help)) } , navigationIcon = {
IconButton(onClick = {
activity.finish()
}) {
- Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
+ Icon(Icons.AutoMirrored.Filled.ArrowBack , contentDescription = null)
}
- }, actions = {
+ } , actions = {
IconButton(onClick = { showMenu = true }) {
- Icon(Icons.Default.MoreVert, contentDescription = "Localized description")
+ Icon(Icons.Default.MoreVert , contentDescription = "Localized description")
}
- DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
- DropdownMenuItem(text = { Text(stringResource(R.string.view_in_google_play_store)) },
+ DropdownMenu(expanded = showMenu , onDismissRequest = { showMenu = false }) {
+ DropdownMenuItem(text = { Text(stringResource(R.string.view_in_google_play_store)) } ,
onClick = {
- Utils.openUrl(
- context,
+ IntentUtils.openUrl(
+ context ,
"https://play.google.com/store/apps/details?id=${activity.packageName}"
)
})
- DropdownMenuItem(text = { Text(stringResource(R.string.version_info)) },
+ DropdownMenuItem(text = { Text(stringResource(R.string.version_info)) } ,
onClick = { showDialog.value = true })
- DropdownMenuItem(text = { Text(stringResource(R.string.beta_program)) },
+ DropdownMenuItem(text = { Text(stringResource(R.string.beta_program)) } ,
onClick = {
- Utils.openUrl(
- context,
+ IntentUtils.openUrl(
+ context ,
"https://play.google.com/apps/testing/${activity.packageName}"
)
})
- DropdownMenuItem(text = { Text(stringResource(R.string.terms_of_service)) },
+ DropdownMenuItem(text = { Text(stringResource(R.string.terms_of_service)) } ,
onClick = {
- Utils.openUrl(
- context,
+ IntentUtils.openUrl(
+ context ,
"https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service"
)
})
- DropdownMenuItem(text = { Text(stringResource(R.string.privacy_policy)) },
+ DropdownMenuItem(text = { Text(stringResource(R.string.privacy_policy)) } ,
onClick = {
- Utils.openUrl(
- context,
+ IntentUtils.openUrl(
+ context ,
"https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy"
)
})
- DropdownMenuItem(text = { Text(stringResource(com.google.android.gms.oss.licenses.R.string.oss_license_title)) },
+ DropdownMenuItem(text = { Text(stringResource(com.google.android.gms.oss.licenses.R.string.oss_license_title)) } ,
onClick = {
- Utils.openActivity(
- context, OssLicensesMenuActivity::class.java
+ IntentUtils.openActivity(
+ context , OssLicensesMenuActivity::class.java
)
})
}
if (showDialog.value) {
VersionInfoDialog(onDismiss = { showDialog.value = false })
}
- }, scrollBehavior = scrollBehavior)
+ } , scrollBehavior = scrollBehavior)
}) { paddingValues ->
Box(
modifier = Modifier
- .padding(start = 16.dp, end = 16.dp)
+ .padding(start = 16.dp , end = 16.dp)
.fillMaxSize()
.safeDrawingPadding()
) {
ConstraintLayout(modifier = Modifier.padding(paddingValues)) {
- val (faqTitle, faqCard) = createRefs()
- Text(text = stringResource(R.string.faq),
+ val (faqTitle , faqCard) = createRefs()
+ Text(text = stringResource(R.string.faq) ,
modifier = Modifier
.padding(bottom = 24.dp)
.constrainAs(faqTitle) {
@@ -136,19 +145,21 @@ fun HelpComposable(activity: HelpActivity) {
}
}
ExtendedFloatingActionButton(
- text = { Text(stringResource(id = R.string.feedback)) },
+ text = { Text(stringResource(id = R.string.feedback)) } ,
onClick = {
- activity.feedback()
+ viewModel.reviewInfo.value?.let { safeReviewInfo ->
+ viewModel.launchReviewFlow(activity, safeReviewInfo)
+ }
},
icon = {
Icon(
- Icons.Default.MailOutline, contentDescription = null
+ Icons.Default.MailOutline , contentDescription = null
)
- },
+ } ,
modifier = Modifier
.bounceClick()
.padding(bottom = 16.dp)
- .align(Alignment.BottomEnd),
+ .align(Alignment.BottomEnd) ,
)
}
}
@@ -159,55 +170,55 @@ fun FAQComposable() {
LazyColumn {
item {
QuestionComposable(
- title = stringResource(R.string.question_1),
+ title = stringResource(R.string.question_1) ,
summary = stringResource(R.string.summary_preference_faq_1)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_2),
+ title = stringResource(R.string.question_2) ,
summary = stringResource(R.string.summary_preference_faq_2)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_3),
+ title = stringResource(R.string.question_3) ,
summary = stringResource(R.string.summary_preference_faq_3)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_4),
+ title = stringResource(R.string.question_4) ,
summary = stringResource(R.string.summary_preference_faq_4)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_5),
+ title = stringResource(R.string.question_5) ,
summary = stringResource(R.string.summary_preference_faq_5)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_6),
+ title = stringResource(R.string.question_6) ,
summary = stringResource(R.string.summary_preference_faq_6)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_7),
+ title = stringResource(R.string.question_7) ,
summary = stringResource(R.string.summary_preference_faq_7)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_8),
+ title = stringResource(R.string.question_8) ,
summary = stringResource(R.string.summary_preference_faq_8)
)
}
item {
QuestionComposable(
- title = stringResource(R.string.question_9),
+ title = stringResource(R.string.question_9) ,
summary = stringResource(R.string.summary_preference_faq_9)
)
}
@@ -215,27 +226,27 @@ fun FAQComposable() {
}
@Composable
-fun QuestionComposable(title: String, summary: String) {
+fun QuestionComposable(title : String , summary : String) {
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(16.dp),
+ .padding(16.dp) ,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
- Icons.Outlined.QuestionAnswer,
- contentDescription = null,
+ Icons.Outlined.QuestionAnswer ,
+ contentDescription = null ,
modifier = Modifier
.size(48.dp)
.background(
- color = MaterialTheme.colorScheme.primaryContainer, shape = CircleShape
+ color = MaterialTheme.colorScheme.primaryContainer , shape = CircleShape
)
.padding(8.dp)
)
Spacer(modifier = Modifier.width(16.dp))
Column {
Text(
- text = title, style = MaterialTheme.typography.titleMedium
+ text = title , style = MaterialTheme.typography.titleMedium
)
Spacer(modifier = Modifier.height(4.dp))
Text(text = summary)
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpViewModel.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpViewModel.kt
new file mode 100644
index 0000000..5ce0899
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/help/HelpViewModel.kt
@@ -0,0 +1,35 @@
+package com.d4rk.englishwithlidia.plus.ui.help
+
+import android.app.Application
+import androidx.compose.runtime.*
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.viewModelScope
+import com.google.android.play.core.review.ReviewInfo
+import com.google.android.play.core.review.ReviewManagerFactory
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class HelpViewModel(application: Application) : AndroidViewModel(application) {
+
+ private var _reviewInfo: MutableState = mutableStateOf(null)
+ val reviewInfo: State = _reviewInfo
+
+ fun requestReviewFlow() {
+ viewModelScope.launch(Dispatchers.IO) {
+ val reviewManager = ReviewManagerFactory.create(getApplication())
+ val request = reviewManager.requestReviewFlow()
+ request.addOnCompleteListener { task ->
+ if (task.isSuccessful) {
+ _reviewInfo.value = task.result
+ } else {
+ task.exception?.printStackTrace()
+ }
+ }
+ }
+ }
+
+ fun launchReviewFlow(activity: HelpActivity, reviewInfo: ReviewInfo) {
+ val reviewManager = ReviewManagerFactory.create(activity)
+ reviewManager.launchReviewFlow(activity, reviewInfo)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/home/HomeComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/home/HomeComposable.kt
index 3af4d6a..1d1aa1b 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/home/HomeComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/home/HomeComposable.kt
@@ -1,7 +1,6 @@
package com.d4rk.englishwithlidia.plus.ui.home
import android.content.Intent
-import com.d4rk.englishwithlidia.plus.utils.drawable.homeBanner
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@@ -45,8 +44,9 @@ import com.d4rk.englishwithlidia.plus.ads.BannerAdsComposable
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
import com.d4rk.englishwithlidia.plus.ui.home.repository.LessonRepository
import com.d4rk.englishwithlidia.plus.ui.lessons.LessonsActivity
-import com.d4rk.englishwithlidia.plus.utils.Utils
-import com.d4rk.englishwithlidia.plus.utils.bounceClick
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.bounceClick
+import com.d4rk.englishwithlidia.plus.utils.drawable.homeBanner
@Composable
fun HomeComposable() {
@@ -78,7 +78,7 @@ fun HomeComposable() {
.padding(start = 24.dp, end = 24.dp),
) {
OutlinedButton(onClick = {
- Utils.openUrl(context, "https://sites.google.com/view/englishwithlidia")
+ IntentUtils.openUrl(context, "https://sites.google.com/view/englishwithlidia")
}, modifier = Modifier
.weight(1f)
.bounceClick()) {
@@ -95,7 +95,7 @@ fun HomeComposable() {
OutlinedButton(
onClick = {
- Utils.openUrl(context, "https://www.facebook.com/lidia.melinte")
+ IntentUtils.openUrl(context, "https://www.facebook.com/lidia.melinte")
},
modifier = Modifier
.weight(1f)
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsComposable.kt
index 666e27d..9126488 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsComposable.kt
@@ -1,6 +1,8 @@
package com.d4rk.englishwithlidia.plus.ui.lessons
import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -46,7 +48,7 @@ import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.rememberLottieComposition
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.data.model.ui.lessons.UiLessonsAsset
-import com.d4rk.englishwithlidia.plus.utils.bounceClick
+import com.d4rk.englishwithlidia.plus.utils.compose.bounceClick
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -92,7 +94,7 @@ fun LessonsComposable(viewModel: LessonsViewModel) {
fun LessonContent(
modifier: Modifier = Modifier,
lessonDetails: UiLessonsAsset,
- viewModel: LessonsViewModel
+ viewModel: LessonsViewModel,
) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.anim_plant))
val context = LocalContext.current
@@ -149,8 +151,13 @@ fun AudioCardView(
onSeekChange: (Float) -> Unit,
sliderPosition: Float,
playbackDuration: Float,
- isPlaying: Boolean
+ isPlaying: Boolean,
) {
+ val cornerRadius = animateFloatAsState(
+ targetValue = if (isPlaying) 16f else 28f,
+ animationSpec = tween(durationMillis = 200), label = ""
+ ).value
+
OutlinedCard(
modifier = Modifier
.fillMaxWidth()
@@ -172,7 +179,8 @@ fun AudioCardView(
onClick = onPlayClick,
modifier = Modifier
.weight(1f)
- .bounceClick()
+ .bounceClick(),
+ shape = RoundedCornerShape(cornerRadius.dp)
) {
Icon(
imageVector = if (isPlaying) Icons.Filled.Pause else Icons.Filled.PlayArrow,
@@ -183,13 +191,15 @@ fun AudioCardView(
Spacer(modifier = Modifier.width(16.dp))
Slider(
- value = playbackDuration,
- onValueChange = {
-
+ value = sliderPosition,
+ onValueChange = { newValue ->
+ onSeekChange(newValue)
},
colors = SliderDefaults.colors(),
valueRange = 0f..playbackDuration,
- modifier = Modifier.fillMaxWidth().weight(4f)
+ modifier = Modifier
+ .fillMaxWidth()
+ .weight(4f)
)
}
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsViewModel.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsViewModel.kt
index 8205647..b4463b2 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsViewModel.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/lessons/LessonsViewModel.kt
@@ -3,7 +3,6 @@ package com.d4rk.englishwithlidia.plus.ui.lessons
import android.app.Application
import android.content.Context
import android.net.Uri
-import androidx.annotation.OptIn
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
@@ -11,24 +10,15 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
-import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import com.d4rk.englishwithlidia.plus.data.model.ui.lessons.UiLessonsAsset
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
-import javax.inject.Inject
-
-@HiltViewModel
-class LessonsViewModel @OptIn(UnstableApi::class)
-@Inject constructor(
- application: Application,
- lessonDetails: UiLessonsAsset?,
-) : AndroidViewModel(application) {
+
+class LessonsViewModel(application: Application, lessonDetails: UiLessonsAsset?) : AndroidViewModel(application) {
private val _isPlaying = MutableStateFlow(false)
val isPlaying: StateFlow = _isPlaying.asStateFlow()
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/SettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/SettingsComposable.kt
index 69819be..e1da44c 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/SettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/SettingsComposable.kt
@@ -28,8 +28,8 @@ import com.d4rk.englishwithlidia.plus.ui.settings.about.AboutSettingsActivity
import com.d4rk.englishwithlidia.plus.ui.settings.advanced.AdvancedSettingsActivity
import com.d4rk.englishwithlidia.plus.ui.settings.display.DisplaySettingsActivity
import com.d4rk.englishwithlidia.plus.ui.settings.privacy.PrivacySettingsActivity
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -55,7 +55,7 @@ fun SettingsComposable(activity: SettingsActivity) {
title = stringResource(R.string.display),
summary = stringResource(R.string.summary_preference_settings_display),
onClick = {
- Utils.openActivity(context, DisplaySettingsActivity::class.java)
+ IntentUtils.openActivity(context, DisplaySettingsActivity::class.java)
})
}
item {
@@ -63,7 +63,7 @@ fun SettingsComposable(activity: SettingsActivity) {
title = stringResource(R.string.notifications),
summary = stringResource(R.string.summary_preference_settings_notifications),
onClick = {
- Utils.openAppNotificationSettings(context)
+ IntentUtils.openAppNotificationSettings(context)
})
}
item {
@@ -71,7 +71,7 @@ fun SettingsComposable(activity: SettingsActivity) {
title = stringResource(R.string.advanced),
summary = stringResource(R.string.summary_preference_settings_advanced),
onClick = {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, AdvancedSettingsActivity::class.java
)
})
@@ -81,7 +81,7 @@ fun SettingsComposable(activity: SettingsActivity) {
title = stringResource(R.string.security_and_privacy),
summary = stringResource(R.string.summary_preference_settings_privacy_and_security),
onClick = {
- Utils.openActivity(context, PrivacySettingsActivity::class.java)
+ IntentUtils.openActivity(context, PrivacySettingsActivity::class.java)
})
}
item {
@@ -89,7 +89,7 @@ fun SettingsComposable(activity: SettingsActivity) {
title = stringResource(R.string.about),
summary = stringResource(R.string.summary_preference_settings_about),
onClick = {
- Utils.openActivity(context, AboutSettingsActivity::class.java)
+ IntentUtils.openActivity(context, AboutSettingsActivity::class.java)
})
}
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/about/AboutSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/about/AboutSettingsComposable.kt
index 6edcf72..93716dc 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/about/AboutSettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/about/AboutSettingsComposable.kt
@@ -24,9 +24,9 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.d4rk.englishwithlidia.plus.BuildConfig
import com.d4rk.englishwithlidia.plus.R
-import com.d4rk.englishwithlidia.plus.utils.PreferenceCategoryItem
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceCategoryItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
@OptIn(ExperimentalMaterial3Api::class)
@@ -62,7 +62,7 @@ fun AboutSettingsComposable(activity: AboutSettingsActivity) {
PreferenceItem(title = stringResource(com.google.android.gms.oss.licenses.R.string.oss_license_title),
summary = stringResource(R.string.summary_preference_settings_oss),
onClick = {
- Utils.openActivity(context , OssLicensesMenuActivity::class.java)
+ IntentUtils.openActivity(context , OssLicensesMenuActivity::class.java)
})
}
item {
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/advanced/AdvancedSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/advanced/AdvancedSettingsComposable.kt
index 9277bbe..c3e6a0d 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/advanced/AdvancedSettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/advanced/AdvancedSettingsComposable.kt
@@ -19,9 +19,9 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import com.d4rk.englishwithlidia.plus.R
-import com.d4rk.englishwithlidia.plus.utils.PreferenceCategoryItem
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceCategoryItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -49,7 +49,7 @@ fun AdvancedSettingsComposable(activity: AdvancedSettingsActivity) {
PreferenceItem(title = stringResource(R.string.bug_report),
summary = stringResource(R.string.summary_preference_settings_bug_report),
onClick = {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://github.com/D4rK7355608/${context.packageName}/issues/new"
)
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/DisplaySettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/DisplaySettingsComposable.kt
index dff799c..c77fa60 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/DisplaySettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/DisplaySettingsComposable.kt
@@ -34,11 +34,11 @@ import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
import com.d4rk.englishwithlidia.plus.ui.dialogs.LanguageDialog
import com.d4rk.englishwithlidia.plus.ui.settings.display.theme.ThemeSettingsActivity
-import com.d4rk.englishwithlidia.plus.utils.PreferenceCategoryItem
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.SwitchPreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.SwitchPreferenceItemWithDivider
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceCategoryItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.SwitchPreferenceItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.SwitchPreferenceItemWithDivider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -98,7 +98,7 @@ fun DisplaySettingsComposable(activity: DisplaySettingsActivity) {
}
},
onClick = {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, ThemeSettingsActivity::class.java
)
})
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/theme/ThemeSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/theme/ThemeSettingsComposable.kt
index 1cfc54a..d883471 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/theme/ThemeSettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/display/theme/ThemeSettingsComposable.kt
@@ -33,7 +33,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
-import com.d4rk.englishwithlidia.plus.utils.SwitchCardComposable
+import com.d4rk.englishwithlidia.plus.utils.compose.components.SwitchCardComposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/PrivacySettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/PrivacySettingsComposable.kt
index 1e28be8..53cab25 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/PrivacySettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/PrivacySettingsComposable.kt
@@ -22,9 +22,9 @@ import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.ui.settings.privacy.ads.AdsSettingsActivity
import com.d4rk.englishwithlidia.plus.ui.settings.privacy.permissions.PermissionsSettingsActivity
import com.d4rk.englishwithlidia.plus.ui.settings.privacy.usage.UsageAndDiagnosticsActivity
-import com.d4rk.englishwithlidia.plus.utils.PreferenceCategoryItem
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceCategoryItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -55,7 +55,7 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.privacy_policy),
summary = stringResource(id = R.string.summary_preference_settings_privacy_policy),
onClick = {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy"
)
@@ -63,7 +63,7 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.terms_of_service),
summary = stringResource(id = R.string.summary_preference_settings_terms_of_service),
onClick = {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://sites.google.com/view/d4rk7355608/more/apps/terms-of-service"
)
@@ -71,7 +71,7 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.code_of_conduct),
summary = stringResource(id = R.string.summary_preference_settings_code_of_conduct),
onClick = {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://sites.google.com/view/d4rk7355608/more/code-of-conduct"
)
@@ -79,21 +79,21 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.permissions),
summary = stringResource(id = R.string.summary_preference_settings_permissions),
onClick = {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, PermissionsSettingsActivity::class.java
)
})
PreferenceItem(title = stringResource(R.string.ads),
summary = stringResource(id = R.string.summary_preference_settings_ads),
onClick = {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, AdsSettingsActivity::class.java
)
})
PreferenceItem(title = stringResource(R.string.usage_and_diagnostics),
summary = stringResource(id = R.string.summary_preference_settings_usage_and_diagnostics),
onClick = {
- Utils.openActivity(
+ IntentUtils.openActivity(
context, UsageAndDiagnosticsActivity::class.java
)
})
@@ -103,7 +103,7 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.legal_notices),
summary = stringResource(id = R.string.summary_preference_settings_legal_notices),
onClick = {
- Utils.openUrl(
+ IntentUtils.openUrl(
context,
"https://sites.google.com/view/d4rk7355608/more/apps/legal-notices"
)
@@ -111,7 +111,7 @@ fun PrivacySettingsComposable(activity: PrivacySettingsActivity) {
PreferenceItem(title = stringResource(R.string.license),
summary = stringResource(R.string.summary_preference_settings_license),
onClick = {
- Utils.openUrl(context, "https://www.gnu.org/licenses/gpl-3.0")
+ IntentUtils.openUrl(context, "https://www.gnu.org/licenses/gpl-3.0")
})
}
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/ads/AdsSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/ads/AdsSettingsComposable.kt
index 32315c9..a4b1192 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/ads/AdsSettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/ads/AdsSettingsComposable.kt
@@ -35,9 +35,9 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
-import com.d4rk.englishwithlidia.plus.utils.SwitchCardComposable
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.SwitchCardComposable
import com.google.android.ump.ConsentRequestParameters
import com.google.android.ump.UserMessagingPlatform
import kotlinx.coroutines.Dispatchers
@@ -126,7 +126,7 @@ fun AdsSettingsComposable(activity : AdsSettingsActivity) {
ClickableText(text = annotatedString , onClick = { offset ->
annotatedString.getStringAnnotations("URL" , offset , offset)
.firstOrNull()?.let { annotation ->
- Utils.openUrl(context , annotation.item)
+ IntentUtils.openUrl(context , annotation.item)
}
})
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt
index 9646b0f..c4f7edc 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/permissions/PermissionsSettingsComposable.kt
@@ -18,8 +18,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import com.d4rk.englishwithlidia.plus.R
-import com.d4rk.englishwithlidia.plus.utils.PreferenceCategoryItem
-import com.d4rk.englishwithlidia.plus.utils.PreferenceItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceCategoryItem
+import com.d4rk.englishwithlidia.plus.utils.compose.components.PreferenceItem
@OptIn(ExperimentalMaterial3Api::class)
@Composable
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt
index 4b00d8c..62e7fc4 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/settings/privacy/usage/UsageAndDiagnosticsComposable.kt
@@ -35,8 +35,8 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
-import com.d4rk.englishwithlidia.plus.utils.SwitchCardComposable
-import com.d4rk.englishwithlidia.plus.utils.Utils
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.components.SwitchCardComposable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -106,7 +106,7 @@ fun UsageAndDiagnosticsComposable(activity : UsageAndDiagnosticsActivity) {
ClickableText(text = annotatedString , onClick = { offset ->
annotatedString.getStringAnnotations("URL" , offset , offset)
.firstOrNull()?.let { annotation ->
- Utils.openUrl(context , annotation.item)
+ IntentUtils.openUrl(context , annotation.item)
}
})
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupActivity.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupActivity.kt
index 790a1cd..8b79562 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupActivity.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupActivity.kt
@@ -1,7 +1,5 @@
package com.d4rk.englishwithlidia.plus.ui.startup
-import android.Manifest
-import android.os.Build
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -15,30 +13,31 @@ import com.google.android.ump.ConsentForm
import com.google.android.ump.ConsentInformation
import com.google.android.ump.ConsentRequestParameters
import com.google.android.ump.UserMessagingPlatform
+import kotlinx.coroutines.flow.MutableStateFlow
class StartupActivity : AppCompatActivity() {
- private lateinit var consentInformation: ConsentInformation
- private lateinit var consentForm: ConsentForm
- override fun onCreate(savedInstanceState: Bundle?) {
+ private lateinit var consentInformation : ConsentInformation
+ private lateinit var consentForm : ConsentForm
+ val consentFormShown = MutableStateFlow(false)
+ override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
Surface(
- modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background
+ modifier = Modifier.fillMaxSize() , color = MaterialTheme.colorScheme.background
) {
- StartupComposable()
+ StartupComposable(this@StartupActivity)
}
}
}
val params = ConsentRequestParameters.Builder().setTagForUnderAgeOfConsent(false).build()
consentInformation = UserMessagingPlatform.getConsentInformation(this)
- consentInformation.requestConsentInfoUpdate(this, params, {
+ consentInformation.requestConsentInfoUpdate(this , params , {
if (consentInformation.isConsentFormAvailable) {
loadForm()
}
- }, {})
- requestPermissions()
+ } , {})
}
/**
@@ -53,29 +52,14 @@ class StartupActivity : AppCompatActivity() {
* @see com.google.ads.consent.ConsentInformation
*/
private fun loadForm() {
- UserMessagingPlatform.loadConsentForm(this, { consentForm ->
+ UserMessagingPlatform.loadConsentForm(this , { consentForm ->
this.consentForm = consentForm
if (consentInformation.consentStatus == ConsentInformation.ConsentStatus.REQUIRED) {
+ consentFormShown.value = true
consentForm.show(this) {
loadForm()
}
}
- }, {})
- }
-
- /**
- * Handles the application's permission requirements.
- *
- * This function is responsible for checking and requesting the necessary permissions for the application. It takes into account the Android version to manage specific permission scenarios.
- * For Android versions Tiramisu or later, it requests the POST_NOTIFICATIONS permission.
- *
- * @see android.Manifest.permission.POST_NOTIFICATIONS
- * @see android.os.Build.VERSION.SDK_INT
- * @see android.os.Build.VERSION_CODES.TIRAMISU
- */
- private fun requestPermissions() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1)
- }
+ } , {})
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupComposable.kt
index e0e91c5..46adc7b 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/startup/StartupComposable.kt
@@ -1,5 +1,6 @@
package com.d4rk.englishwithlidia.plus.ui.startup
+import android.app.Activity
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -12,6 +13,7 @@ import androidx.compose.material.icons.outlined.CheckCircle
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
+import androidx.compose.material3.FloatingActionButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
@@ -20,8 +22,12 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color.Companion.Gray
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
@@ -33,83 +39,100 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import com.d4rk.englishwithlidia.plus.MainActivity
import com.d4rk.englishwithlidia.plus.R
-import com.d4rk.englishwithlidia.plus.utils.Utils
-import com.d4rk.englishwithlidia.plus.utils.bounceClick
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.PermissionsUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.bounceClick
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun StartupComposable() {
+fun StartupComposable(activity: StartupActivity) {
val context = LocalContext.current
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
- Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection) , topBar = {
- LargeTopAppBar(title = { Text(stringResource(R.string.welcome)) } ,
- scrollBehavior = scrollBehavior
+ val fabEnabled = remember { mutableStateOf(false) }
+ LaunchedEffect(context) {
+ if (!PermissionsUtils.hasNotificationPermission(context)) {
+ PermissionsUtils.requestNotificationPermission(context as Activity)
+ }
+ activity.consentFormShown.collect { shown ->
+ fabEnabled.value = shown
+ }
+ }
+
+ Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
+ LargeTopAppBar(
+ title = { Text(stringResource(R.string.welcome)) },
+ scrollBehavior = scrollBehavior
)
}) { innerPadding ->
Box(
modifier = Modifier
- .fillMaxSize()
- .padding(24.dp)
- .safeDrawingPadding()
+ .fillMaxSize()
+ .padding(24.dp)
+ .safeDrawingPadding()
) {
LazyColumn(
modifier = Modifier
- .fillMaxSize()
- .padding(innerPadding) ,
+ .fillMaxSize()
+ .padding(innerPadding),
) {
item {
Image(
- painter = painterResource(id = R.drawable.il_startup) ,
+ painter = painterResource(id = R.drawable.il_startup),
contentDescription = null
)
Icon(
- Icons.Outlined.Info , contentDescription = null
+ Icons.Outlined.Info, contentDescription = null
)
}
item {
Text(
- text = stringResource(R.string.summary_browse_terms_of_service_and_privacy_policy) ,
- modifier = Modifier.padding(top = 24.dp , bottom = 24.dp)
+ text = stringResource(R.string.summary_browse_terms_of_service_and_privacy_policy),
+ modifier = Modifier.padding(top = 24.dp, bottom = 24.dp)
)
val annotatedString = buildAnnotatedString {
withStyle(
style = SpanStyle(
- color = MaterialTheme.colorScheme.primary ,
+ color = MaterialTheme.colorScheme.primary,
textDecoration = TextDecoration.Underline
)
) {
append(stringResource(R.string.browse_terms_of_service_and_privacy_policy))
}
addStringAnnotation(
- tag = "URL" ,
- annotation = "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy" ,
- start = 0 ,
+ tag = "URL",
+ annotation = "https://sites.google.com/view/d4rk7355608/more/apps/privacy-policy",
+ start = 0,
end = stringResource(R.string.browse_terms_of_service_and_privacy_policy).length
)
}
- ClickableText(text = annotatedString , onClick = { offset ->
- annotatedString.getStringAnnotations("URL" , offset , offset).firstOrNull()
- ?.let { annotation ->
- Utils.openUrl(context , annotation.item)
- }
+ ClickableText(text = annotatedString, onClick = { offset ->
+ annotatedString.getStringAnnotations("URL", offset, offset).firstOrNull()
+ ?.let { annotation ->
+ IntentUtils.openUrl(context, annotation.item)
+ }
})
}
}
ExtendedFloatingActionButton(modifier = Modifier
- .align(Alignment.BottomEnd)
- .bounceClick() ,
- text = { Text(stringResource(R.string.agree)) } ,
- onClick = {
- Utils.openActivity(
- context , MainActivity::class.java
- )
- } ,
- icon = {
- Icon(
- Icons.Outlined.CheckCircle ,
- contentDescription = null
- )
- })
+ .align(Alignment.BottomEnd)
+ .bounceClick(),
+ containerColor = if (fabEnabled.value) {
+ FloatingActionButtonDefaults.containerColor
+ } else {
+ Gray
+ },
+ text = { Text(stringResource(R.string.agree)) },
+ onClick = {
+ IntentUtils.openActivity(
+ context , MainActivity::class.java
+ )
+ },
+ icon = {
+ Icon(
+ Icons.Outlined.CheckCircle,
+ contentDescription = null
+ )
+ })
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportActivity.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportActivity.kt
index c5b5d9b..adf050f 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportActivity.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportActivity.kt
@@ -5,56 +5,42 @@ package com.d4rk.englishwithlidia.plus.ui.support
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.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
-import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingFlowParams
import com.android.billingclient.api.SkuDetails
-import com.android.billingclient.api.SkuDetailsParams
import com.d4rk.englishwithlidia.plus.ui.settings.display.theme.style.AppTheme
class SupportActivity : AppCompatActivity() {
+ private val viewModel: SupportViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
AppTheme {
Surface(
- modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
) {
- SupportComposable(this@SupportActivity)
+ SupportComposable(viewModel, this@SupportActivity)
}
}
}
}
fun initiatePurchase(
- sku: String, skuDetailsMap: Map, billingClient: BillingClient
+ sku : String , skuDetailsMap : Map , billingClient : BillingClient
) {
val skuDetails = skuDetailsMap[sku]
if (skuDetails != null) {
val flowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build()
- billingClient.launchBillingFlow(this, flowParams)
- }
- }
-
- fun querySkuDetails(
- billingClient: BillingClient, skuDetailsMap: SnapshotStateMap
- ) {
- val skuList =
- listOf("low_donation", "normal_donation", "high_donation", "extreme_donation")
- val params = SkuDetailsParams.newBuilder().setSkusList(skuList)
- .setType(BillingClient.SkuType.INAPP).build()
- billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList ->
- if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
- for (skuDetails in skuDetailsList) {
- skuDetailsMap[skuDetails.sku] = skuDetails
- }
- }
+ billingClient.launchBillingFlow(this , flowParams)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportComposable.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportComposable.kt
index ba3c41f..b93f0a9 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportComposable.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportComposable.kt
@@ -30,10 +30,7 @@ import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
@@ -42,23 +39,18 @@ import androidx.compose.ui.unit.dp
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingClientStateListener
import com.android.billingclient.api.BillingResult
-import com.android.billingclient.api.SkuDetails
import com.d4rk.englishwithlidia.plus.R
import com.d4rk.englishwithlidia.plus.ads.LargeBannerAdsComposable
import com.d4rk.englishwithlidia.plus.data.datastore.DataStore
-import com.d4rk.englishwithlidia.plus.utils.Utils
-import com.d4rk.englishwithlidia.plus.utils.bounceClick
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
+import com.d4rk.englishwithlidia.plus.utils.IntentUtils
+import com.d4rk.englishwithlidia.plus.utils.compose.bounceClick
@OptIn(ExperimentalMaterial3Api::class)
@Composable
-fun SupportComposable(activity: SupportActivity) {
+fun SupportComposable(viewModel: SupportViewModel, activity: SupportActivity) {
val context = LocalContext.current
val dataStore = DataStore.getInstance(context)
- val coroutineScope = rememberCoroutineScope()
- val skuDetailsMap = remember { mutableStateMapOf() }
- val billingClient = rememberBillingClient(context, coroutineScope, activity, skuDetailsMap)
+ val billingClient = rememberBillingClient(context, viewModel)
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
LargeTopAppBar(title = { Text(stringResource(R.string.support_us)) }, navigationIcon = {
@@ -69,8 +61,7 @@ fun SupportComposable(activity: SupportActivity) {
Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null
)
}
- }, scrollBehavior = scrollBehavior
- )
+ }, scrollBehavior = scrollBehavior)
}) { paddingValues ->
Box(
modifier = Modifier
@@ -109,7 +100,9 @@ fun SupportComposable(activity: SupportActivity) {
.bounceClick(),
onClick = {
activity.initiatePurchase(
- "low_donation", skuDetailsMap, billingClient
+ "low_donation",
+ viewModel.skuDetails,
+ billingClient,
)
},
) {
@@ -119,7 +112,7 @@ fun SupportComposable(activity: SupportActivity) {
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
- Text(skuDetailsMap["low_donation"]?.price ?: "")
+ Text(viewModel.skuDetails["low_donation"]?.price ?: "")
}
}
item {
@@ -129,7 +122,9 @@ fun SupportComposable(activity: SupportActivity) {
.bounceClick(),
onClick = {
activity.initiatePurchase(
- "normal_donation", skuDetailsMap, billingClient
+ "normal_donation",
+ viewModel.skuDetails,
+ billingClient,
)
},
) {
@@ -139,7 +134,7 @@ fun SupportComposable(activity: SupportActivity) {
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
- Text(skuDetailsMap["normal_donation"]?.price ?: "")
+ Text(viewModel.skuDetails["normal_donation"]?.price ?: "")
}
}
}
@@ -156,7 +151,9 @@ fun SupportComposable(activity: SupportActivity) {
.bounceClick(),
onClick = {
activity.initiatePurchase(
- "high_donation", skuDetailsMap, billingClient
+ "high_donation",
+ viewModel.skuDetails,
+ billingClient,
)
},
) {
@@ -166,7 +163,7 @@ fun SupportComposable(activity: SupportActivity) {
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
- Text(skuDetailsMap["high_donation"]?.price ?: "")
+ Text(viewModel.skuDetails["high_donation"]?.price ?: "")
}
}
item {
@@ -177,7 +174,9 @@ fun SupportComposable(activity: SupportActivity) {
.bounceClick(),
onClick = {
activity.initiatePurchase(
- "extreme_donation", skuDetailsMap, billingClient
+ "extreme_donation",
+ viewModel.skuDetails,
+ billingClient,
)
},
) {
@@ -187,7 +186,7 @@ fun SupportComposable(activity: SupportActivity) {
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
- Text(skuDetailsMap["extreme_donation"]?.price ?: "")
+ Text(viewModel.skuDetails["extreme_donation"]?.price ?: "")
}
}
}
@@ -204,9 +203,8 @@ fun SupportComposable(activity: SupportActivity) {
item {
FilledTonalButton(
onClick = {
- Utils.openUrl(
- context,
- "https://direct-link.net/548212/agOqI7123501341"
+ IntentUtils.openUrl(
+ context, "https://direct-link.net/548212/agOqI7123501341"
)
},
modifier = Modifier
@@ -225,8 +223,7 @@ fun SupportComposable(activity: SupportActivity) {
}
item {
LargeBannerAdsComposable(
- modifier = Modifier.padding(bottom = 12.dp),
- dataStore = dataStore
+ modifier = Modifier.padding(bottom = 12.dp), dataStore = dataStore
)
}
}
@@ -237,20 +234,20 @@ fun SupportComposable(activity: SupportActivity) {
@Composable
fun rememberBillingClient(
context: Context,
- coroutineScope: CoroutineScope,
- activity: SupportActivity,
- skuDetailsMap: SnapshotStateMap
+ viewModel: SupportViewModel
): BillingClient {
val billingClient = remember {
- BillingClient.newBuilder(context).setListener { _, _ -> }.enablePendingPurchases().build()
+ BillingClient.newBuilder(context)
+ .setListener { _, _ -> }
+ .enablePendingPurchases()
+ .build()
}
+
DisposableEffect(billingClient) {
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
- coroutineScope.launch {
- activity.querySkuDetails(billingClient, skuDetailsMap)
- }
+ viewModel.querySkuDetails(billingClient)
}
}
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportViewModel.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportViewModel.kt
new file mode 100644
index 0000000..b6b665b
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/ui/support/SupportViewModel.kt
@@ -0,0 +1,37 @@
+@file:Suppress("DEPRECATION")
+
+package com.d4rk.englishwithlidia.plus.ui.support
+
+import androidx.compose.runtime.mutableStateMapOf
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.android.billingclient.api.BillingClient
+import com.android.billingclient.api.SkuDetails
+import com.android.billingclient.api.SkuDetailsParams
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+
+class SupportViewModel : ViewModel() {
+ private val _skuDetails = mutableStateMapOf()
+ val skuDetails: Map = _skuDetails
+
+ fun querySkuDetails(billingClient: BillingClient) {
+ viewModelScope.launch(Dispatchers.IO) {
+ val skuList = listOf(
+ "low_donation", "normal_donation", "high_donation", "extreme_donation"
+ )
+ val params = SkuDetailsParams.newBuilder()
+ .setSkusList(skuList)
+ .setType(BillingClient.SkuType.INAPP)
+ .build()
+
+ billingClient.querySkuDetailsAsync(params) { billingResult, skuDetailsList ->
+ if (billingResult.responseCode == BillingClient.BillingResponseCode.OK && skuDetailsList != null) {
+ skuDetailsList.forEach { skuDetails ->
+ _skuDetails[skuDetails.sku] = skuDetails
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/Utils.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/IntentUtils.kt
similarity index 99%
rename from app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/Utils.kt
rename to app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/IntentUtils.kt
index 9613d2d..8b749ee 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/Utils.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/IntentUtils.kt
@@ -12,7 +12,7 @@ import com.d4rk.englishwithlidia.plus.R
* This object provides functions to open a URL in the default browser, open an activity, and open the app's notification settings.
* All operations are performed in the context of an Android application.
*/
-object Utils {
+object IntentUtils {
/**
* Opens a specified URL in the default browser.
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/PermissionsUtils.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/PermissionsUtils.kt
new file mode 100644
index 0000000..b8a0049
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/PermissionsUtils.kt
@@ -0,0 +1,48 @@
+package com.d4rk.englishwithlidia.plus.utils
+
+import android.Manifest
+import android.app.Activity
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.Build
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.d4rk.englishwithlidia.plus.constants.permissions.PermissionsConstants
+
+/**
+ * Utility class for handling runtime permissions.
+ */
+object PermissionsUtils {
+
+ /**
+ * Checks if the app has permission to post notifications.
+ *
+ * @param context The application context.
+ * @return True if the permission is granted, false otherwise.
+ */
+ fun hasNotificationPermission(context: Context): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ ContextCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED
+ } else {
+ true
+ }
+ }
+
+ /**
+ * Requests the notification permission.
+ *
+ * @param activity The Activity instance required to request the permission.
+ */
+ fun requestNotificationPermission(activity: Activity) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ ActivityCompat.requestPermissions(
+ activity,
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS),
+ PermissionsConstants.REQUEST_CODE_NOTIFICATION_PERMISSION
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/AnimationUtils.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/AnimationUtils.kt
new file mode 100644
index 0000000..ae96c35
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/AnimationUtils.kt
@@ -0,0 +1,47 @@
+package com.d4rk.englishwithlidia.plus.utils.compose
+
+import android.annotation.SuppressLint
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.gestures.awaitFirstDown
+import androidx.compose.foundation.gestures.waitForUpOrCancellation
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.composed
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInput
+import com.d4rk.englishwithlidia.plus.data.model.ui.button.ButtonState
+
+@SuppressLint("ReturnFromAwaitPointerEventScope")
+@Composable
+fun Modifier.bounceClick() = composed {
+ var buttonState by remember { mutableStateOf(ButtonState.Idle) }
+ val scale by animateFloatAsState(
+ if (buttonState == ButtonState.Pressed) 0.95f else 1f , label = ""
+ )
+ this
+ .graphicsLayer {
+ scaleX = scale
+ scaleY = scale
+ }
+ .clickable(interactionSource = remember { MutableInteractionSource() } ,
+ indication = null ,
+ onClick = { })
+ .pointerInput(buttonState) {
+ awaitPointerEventScope {
+ buttonState = if (buttonState == ButtonState.Pressed) {
+ waitForUpOrCancellation()
+ ButtonState.Idle
+ }
+ else {
+ awaitFirstDown(false)
+ ButtonState.Pressed
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/ComposablesUtils.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/components/SettingsComposablesUtils.kt
similarity index 70%
rename from app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/ComposablesUtils.kt
rename to app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/components/SettingsComposablesUtils.kt
index 28d1599..1fe4089 100644
--- a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/ComposablesUtils.kt
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/compose/components/SettingsComposablesUtils.kt
@@ -1,11 +1,6 @@
-package com.d4rk.englishwithlidia.plus.utils
+package com.d4rk.englishwithlidia.plus.utils.compose.components
-import android.annotation.SuppressLint
-import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.awaitFirstDown
-import androidx.compose.foundation.gestures.waitForUpOrCancellation
-import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -28,17 +23,10 @@ import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -54,34 +42,35 @@ import androidx.compose.ui.unit.dp
*/
@Composable
fun SwitchCardComposable(
- title: String, switchState: State, onSwitchToggled: (Boolean) -> Unit
+ title : String , switchState : State , onSwitchToggled : (Boolean) -> Unit
) {
Card(modifier = Modifier
.fillMaxWidth()
.padding(24.dp)
.clip(RoundedCornerShape(28.dp))
.clickable {
- onSwitchToggled(!switchState.value)
+ onSwitchToggled(! switchState.value)
}) {
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(16.dp),
- horizontalArrangement = Arrangement.SpaceBetween,
+ .padding(16.dp) ,
+ horizontalArrangement = Arrangement.SpaceBetween ,
verticalAlignment = Alignment.CenterVertically
) {
Text(text = title)
- Switch(checked = switchState.value,
- onCheckedChange = onSwitchToggled,
+ Switch(checked = switchState.value ,
+ onCheckedChange = onSwitchToggled ,
thumbContent = if (switchState.value) {
{
Icon(
- Icons.Filled.Check,
- contentDescription = null,
- modifier = Modifier.size(SwitchDefaults.IconSize),
+ Icons.Filled.Check ,
+ contentDescription = null ,
+ modifier = Modifier.size(SwitchDefaults.IconSize) ,
)
}
- } else {
+ }
+ else {
null
})
}
@@ -97,13 +86,13 @@ fun SwitchCardComposable(
*/
@Composable
fun PreferenceCategoryItem(
- title: String
+ title : String
) {
Text(
- text = title,
- color = MaterialTheme.colorScheme.primary,
- style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold),
- modifier = Modifier.padding(start = 16.dp, top = 16.dp)
+ text = title ,
+ color = MaterialTheme.colorScheme.primary ,
+ style = MaterialTheme.typography.bodyMedium.copy(fontWeight = FontWeight.SemiBold) ,
+ modifier = Modifier.padding(start = 16.dp , top = 16.dp)
)
}
@@ -127,9 +116,9 @@ fun PreferenceItem(
) {
Row(
modifier = Modifier
- .fillMaxWidth()
- .clip(RoundedCornerShape(16.dp))
- .clickable(enabled = enabled , onClick = onClick) ,
+ .fillMaxWidth()
+ .clip(RoundedCornerShape(16.dp))
+ .clickable(enabled = enabled , onClick = onClick) ,
verticalAlignment = Alignment.CenterVertically
) {
icon?.let {
@@ -172,22 +161,22 @@ fun PreferenceItem(
*/
@Composable
fun SwitchPreferenceItem(
- icon: ImageVector? = null,
- title: String,
- summary: String? = null,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit
+ icon : ImageVector? = null ,
+ title : String ,
+ summary : String? = null ,
+ checked : Boolean ,
+ onCheckedChange : (Boolean) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
- .clickable(onClick = { onCheckedChange(!checked) }),
+ .clickable(onClick = { onCheckedChange(! checked) }) ,
verticalAlignment = Alignment.CenterVertically
) {
icon?.let {
Spacer(modifier = Modifier.width(16.dp))
- Icon(it, contentDescription = null)
+ Icon(it , contentDescription = null)
Spacer(modifier = Modifier.width(16.dp))
}
Column(
@@ -195,14 +184,14 @@ fun SwitchPreferenceItem(
.padding(16.dp)
.weight(1f)
) {
- Text(text = title, style = MaterialTheme.typography.titleLarge)
+ Text(text = title , style = MaterialTheme.typography.titleLarge)
summary?.let {
- Text(text = it, style = MaterialTheme.typography.bodyMedium)
+ Text(text = it , style = MaterialTheme.typography.bodyMedium)
}
}
Switch(
- checked = checked,
- onCheckedChange = onCheckedChange,
+ checked = checked ,
+ onCheckedChange = onCheckedChange ,
modifier = Modifier.padding(16.dp)
)
}
@@ -225,23 +214,23 @@ fun SwitchPreferenceItem(
*/
@Composable
fun SwitchPreferenceItemWithDivider(
- icon: ImageVector? = null,
- title: String,
- summary: String,
- checked: Boolean,
- onCheckedChange: (Boolean) -> Unit,
- onClick: () -> Unit,
- onSwitchClick: (Boolean) -> Unit
+ icon : ImageVector? = null ,
+ title : String ,
+ summary : String ,
+ checked : Boolean ,
+ onCheckedChange : (Boolean) -> Unit ,
+ onClick : () -> Unit ,
+ onSwitchClick : (Boolean) -> Unit
) {
Row(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
- .clickable(onClick = onClick), verticalAlignment = Alignment.CenterVertically
+ .clickable(onClick = onClick) , verticalAlignment = Alignment.CenterVertically
) {
icon?.let {
Spacer(modifier = Modifier.width(16.dp))
- Icon(it, contentDescription = null)
+ Icon(it , contentDescription = null)
Spacer(modifier = Modifier.width(16.dp))
}
Column(
@@ -249,53 +238,21 @@ fun SwitchPreferenceItemWithDivider(
.padding(16.dp)
.weight(1f)
) {
- Text(text = title, style = MaterialTheme.typography.titleLarge)
- Text(text = summary, style = MaterialTheme.typography.bodyMedium)
+ Text(text = title , style = MaterialTheme.typography.titleLarge)
+ Text(text = summary , style = MaterialTheme.typography.bodyMedium)
}
VerticalDivider(
modifier = Modifier
.height(32.dp)
- .align(Alignment.CenterVertically),
- color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f),
+ .align(Alignment.CenterVertically) ,
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f) ,
thickness = 1.dp
)
- Switch(
- checked = checked, onCheckedChange = { isChecked ->
- onCheckedChange(isChecked)
- onSwitchClick(isChecked)
- }, modifier = Modifier.padding(16.dp)
- )
+ Switch(checked = checked , onCheckedChange = { isChecked ->
+ onCheckedChange(isChecked)
+ onSwitchClick(isChecked)
+ } , modifier = Modifier.padding(16.dp))
}
-}
-
-enum class ButtonState { Pressed, Idle }
-
-@SuppressLint("ReturnFromAwaitPointerEventScope")
-@Composable
-fun Modifier.bounceClick() = composed {
- var buttonState by remember { mutableStateOf(ButtonState.Idle) }
- val scale by animateFloatAsState(
- if (buttonState == ButtonState.Pressed) 0.95f else 1f, label = ""
- )
- this
- .graphicsLayer {
- scaleX = scale
- scaleY = scale
- }
- .clickable(interactionSource = remember { MutableInteractionSource() },
- indication = null,
- onClick = { })
- .pointerInput(buttonState) {
- awaitPointerEventScope {
- buttonState = if (buttonState == ButtonState.Pressed) {
- waitForUpOrCancellation()
- ButtonState.Idle
- } else {
- awaitFirstDown(false)
- ButtonState.Pressed
- }
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/drawable/ImageUtils.kt b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/drawable/ImageUtils.kt
new file mode 100644
index 0000000..7c4698d
--- /dev/null
+++ b/app/src/main/kotlin/com/d4rk/englishwithlidia/plus/utils/drawable/ImageUtils.kt
@@ -0,0 +1,24 @@
+package com.d4rk.englishwithlidia.plus.utils.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+
+fun Drawable.toBitmapDrawable(resources: Resources = Resources.getSystem()): BitmapDrawable {
+ return when (this) {
+ is BitmapDrawable -> this
+ is AdaptiveIconDrawable -> {
+ val bitmap =
+ Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bitmap)
+ setBounds(0, 0, canvas.width, canvas.height)
+ draw(canvas)
+ BitmapDrawable(resources, bitmap)
+ }
+
+ else -> throw IllegalArgumentException("Unsupported drawable type: ${this::class.java.name}")
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 690ed07..29569b6 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -7,6 +7,5 @@ plugins {
alias(libs.plugins.googlePlayServices) apply false
alias(libs.plugins.googleFirebase) apply false
alias(libs.plugins.googleOssServices) apply false
- alias(libs.plugins.googleDaggerHilt) apply false
alias(libs.plugins.devToolsKsp) apply false
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b76bb1a..361137f 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,7 +8,6 @@ billing = "7.0.0"
datastoreCore = "1.1.1"
glide = "4.16.0"
graphicsShapes = "1.0.0-beta01"
-hilt = "2.44"
lifecycle = "2.8.3"
lottieCompose = "4.0.0"
material = "1.12.0"
@@ -67,8 +66,6 @@ androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomKtx"
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomKtx" }
androidx-ui = { module = "androidx.compose.ui:ui" }
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
-hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" }
-hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
@@ -97,7 +94,6 @@ jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "k
jetbrainsKotlinParcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
googlePlayServices = { id = "com.google.gms.google-services", version.ref = "google-services" }
googleOssServices = { id = "com.google.android.gms.oss-licenses-plugin", version.ref = "google-oss-services" }
-googleDaggerHilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
googleFirebase = { id = "com.google.firebase.crashlytics", version.ref = "google-firebase-crashlytics" }
devToolsKsp = { id = "com.google.devtools.ksp", version.ref = "google-devtools-ksp" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
\ No newline at end of file