diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/MainActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/MainActivity.kt index 17a7b0d0..b7bd3e8e 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/MainActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/MainActivity.kt @@ -8,16 +8,32 @@ import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.lifecycleScope +import com.jeeldobariya.passcodes.core.domain.usecases.CheckForUpdateUseCase import com.jeeldobariya.passcodes.core.feature_flags.FeatureFlagsSettings import com.jeeldobariya.passcodes.core.feature_flags.featureFlagsDatastore import com.jeeldobariya.passcodes.design_system.theme.PasscodesTheme import com.jeeldobariya.passcodes.navigation.NavigationRoot +import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject +import kotlin.getValue class MainActivity : ComponentActivity() { + + private val checkForUpdateUseCase: CheckForUpdateUseCase by inject() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - enableEdgeToEdge() + lifecycleScope.launch { + checkForUpdateUseCase( + currentVersion = BuildConfig.VERSION_NAME, + githubReleaseApiUrl = Constant.GITHUB_RELEASE_API_URL, + telegramCommunityUrl = Constant.TELEGRAM_COMMUNITY_URL + ) + } + + enableEdgeToEdge() setContent { PasscodesTheme { val featureFlagState by featureFlagsDatastore.data.collectAsState( diff --git a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt index b8c3a0b2..6e2a18ff 100644 --- a/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt +++ b/app/src/main/kotlin/com/jeeldobariya/passcodes/oldui/MainActivity.kt @@ -12,7 +12,6 @@ import com.jeeldobariya.passcodes.core.domain.usecases.CheckForUpdateUseCase import com.jeeldobariya.passcodes.core.feature_flags.featureFlagsDatastore import com.jeeldobariya.passcodes.databinding.ActivityMainBinding import com.jeeldobariya.passcodes.password_manager.oldui.PasswordManagerActivity -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -36,7 +35,7 @@ class MainActivity : AppCompatActivity() { binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - lifecycleScope.launch(Dispatchers.IO) { + lifecycleScope.launch { checkForUpdateUseCase( currentVersion = BuildConfig.VERSION_NAME, githubReleaseApiUrl = Constant.GITHUB_RELEASE_API_URL, diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e81002e2..867c226b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -53,7 +53,8 @@ dependencies { implementation(libs.kotlinx.serialization.json) // Networking/Parsing - implementation(libs.okhttp) + implementation(libs.ktor.client.core) + implementation(libs.ktor.cilent.cio) implementation(libs.json) // Concurrency (Coroutines Bundle) diff --git a/core/src/main/kotlin/com/jeeldobariya/passcodes/core/di/CoreModule.kt b/core/src/main/kotlin/com/jeeldobariya/passcodes/core/di/CoreModule.kt index e344dcdf..938b37b0 100644 --- a/core/src/main/kotlin/com/jeeldobariya/passcodes/core/di/CoreModule.kt +++ b/core/src/main/kotlin/com/jeeldobariya/passcodes/core/di/CoreModule.kt @@ -1,7 +1,8 @@ package com.jeeldobariya.passcodes.core.di import com.jeeldobariya.passcodes.core.domain.usecases.CheckForUpdateUseCase -import okhttp3.OkHttpClient +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO import org.koin.android.ext.koin.androidContext import org.koin.dsl.module @@ -9,7 +10,7 @@ val coreModule = module { //TODO: It must be turn to single.. If in future it is required by multiple things and not just `CheckForUpdateUseCase()`. factory { - OkHttpClient() + HttpClient(CIO) } factory { diff --git a/core/src/main/kotlin/com/jeeldobariya/passcodes/core/domain/usecases/CheckForUpdateUseCase.kt b/core/src/main/kotlin/com/jeeldobariya/passcodes/core/domain/usecases/CheckForUpdateUseCase.kt index 30f71984..833f0397 100644 --- a/core/src/main/kotlin/com/jeeldobariya/passcodes/core/domain/usecases/CheckForUpdateUseCase.kt +++ b/core/src/main/kotlin/com/jeeldobariya/passcodes/core/domain/usecases/CheckForUpdateUseCase.kt @@ -1,86 +1,72 @@ package com.jeeldobariya.passcodes.core.domain.usecases import android.content.Context -import android.os.Handler import android.widget.Toast import com.jeeldobariya.passcodes.core.domain.utils.SemVerUtils -import okhttp3.Call -import okhttp3.Callback -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import java.io.IOException +import io.ktor.client.HttpClient +import io.ktor.client.request.get +import io.ktor.client.statement.bodyAsText +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext -// TODO: Refactor the code to use ktor client. -@Suppress("RedundantSuspendModifier") class CheckForUpdateUseCase( - val context: Context, - val client: OkHttpClient + private val context: Context, + private val client: HttpClient, + private val dispatcher: CoroutineContext = Dispatchers.IO ) { suspend operator fun invoke( currentVersion: String, githubReleaseApiUrl: String, telegramCommunityUrl: String - ) { + ) = withContext(dispatcher) { val currNormalizedVersion = SemVerUtils.normalize(currentVersion) - val request = Request.Builder() - .url(githubReleaseApiUrl) - .build() + try { + val response = client.get(githubReleaseApiUrl) + val body = response.bodyAsText() + val releases = SemVerUtils.parseReleases(body) - client.newCall(request).enqueue(object : Callback { - override fun onFailure(call: Call, e: IOException) { - e.printStackTrace() - } - - override fun onResponse(call: Call, response: Response) { - val body = response.body.string() - val releases = SemVerUtils.parseReleases(body) - - var userReleaseFound = false - var latestStable: String? = null + var userReleaseFound = false + var latestStable: String? = null - for (release in releases) { - if (release.draft) continue // ignore drafts - - if (release.tag == currNormalizedVersion) { - userReleaseFound = true - if (release.prerelease) { - showToast( - context, - "⚠️ You are using a PRE-RELEASE ($currNormalizedVersion). Not safe for use! Join telegram community ($telegramCommunityUrl)" - ) - } - } + for (release in releases) { + if (release.draft) continue - if (!release.prerelease) { - if (latestStable == null || - SemVerUtils.compare(release.tag, latestStable) > 0 - ) { - latestStable = release.tag - } + if (release.tag == currNormalizedVersion) { + userReleaseFound = true + if (release.prerelease) { + showToast("⚠️ You are using a PRE-RELEASE ($currNormalizedVersion). Not safe for use!!") + showToast("Join telegram @ ($telegramCommunityUrl)") } } - latestStable?.let { - if (SemVerUtils.compare(currNormalizedVersion, it) < 0) { - showToast(context, "New Update available: $it... Visit our website...") + if (!release.prerelease) { + if (latestStable == null || + SemVerUtils.compare(release.tag, latestStable) > 0 + ) { + latestStable = release.tag } } + } - if (!userReleaseFound) { - showToast( - context, - "⚠️ Version ($currNormalizedVersion) not found on GitHub releases... Join telegram community ($telegramCommunityUrl)" - ) + latestStable?.let { + if (SemVerUtils.compare(currNormalizedVersion, it) < 0) { + showToast("New Update available: $it... Visit our website...") } } - }) - } - private fun showToast(context: Context, message: String) { - Handler(context.mainLooper).post { - Toast.makeText(context, message, Toast.LENGTH_LONG).show() + if (!userReleaseFound) { + showToast("⚠️ Version ($currNormalizedVersion) not found on GitHub releases...") + showToast("Join telegram @ ($telegramCommunityUrl)") + } + } catch (e: Exception) { + e.printStackTrace() } } + + private suspend fun showToast(message: String) = withContext(Dispatchers.Main) { + Toast.makeText(context, message, Toast.LENGTH_LONG).show() + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 85430d93..08984e24 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -18,6 +18,7 @@ androidx-junit = "1.3.0" coroutines = "1.10.2" lifecycle = "2.10.0" koin = "4.2.0" +ktor = "3.4.2" composeMultiplatform = "1.10.3" composeBom = "2026.03.01" compose-activity = "1.13.0" @@ -76,6 +77,8 @@ androidx-room-testing = { module = "androidx.room:room-testing", version.ref = " # Networking okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } +ktor-cilent-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" } # Coroutines coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }