Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion app/src/main/kotlin/com/jeeldobariya/passcodes/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
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

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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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()
}
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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" }
Expand Down
Loading