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
2 changes: 1 addition & 1 deletion .github/workflows/build_app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ jobs:

# Run Build Project
- name: Build gradle project
run: ./gradlew build
run: ./gradlew assembleFossRelease assemblePlayRelease
31 changes: 3 additions & 28 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,20 @@ jobs:
echo "${{ secrets.RELEASE_KEYSTORE_BASE64 }}" | base64 --decode > app/kahani-release.jks

- name: Build Release APK
run: ./gradlew assembleRelease
run: ./gradlew assemblePlayRelease
env:
RELEASE_STORE_FILE: kahani-release.jks
RELEASE_STORE_PASSWORD: ${{ secrets.RELEASE_PASSWORD }}
RELEASE_KEY_ALIAS: ${{ secrets.RELEASE_KEY_ALIAS }}
RELEASE_KEY_PASSWORD: ${{ secrets.RELEASE_KEY_PASSWORD }}

- name: Build Changelog
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
configuration: |
{
"categories": [
{
"title": "## 🚀 Features",
"labels": ["feature", "enhancement"]
},
{
"title": "## 🐛 Bug Fixes",
"labels": ["fix", "bug"]
},
{
"title": "## 📦 Dependencies & Maintenance",
"labels": ["chore", "deps", "dependency", "refactor"]
}
],
"template": "{{CHANGELOG}}"
}

- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: app/build/outputs/apk/release/app-release.apk
files: app/build/outputs/apk/play/release/app-play-release.apk
tag_name: v${{ steps.get_version.outputs.version }}
name: Kahani v${{ steps.get_version.outputs.version }}
body: ${{ steps.build_changelog.outputs.changelog }}
body: "Update the Changelog"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Placeholder release body — intended?

"Update the Changelog" appears to be a TODO placeholder rather than actual release notes. The previous workflow apparently generated a changelog automatically. Consider restoring automated changelog generation or adding a reminder to update this before tagging a release.

🤖 Prompt for AI Agents
In @.github/workflows/release.yml at line 53, The release workflow currently
hardcodes the release body as body: "Update the Changelog" which is a
placeholder; replace this with the automated changelog output used previously
(e.g., reference the output from the changelog generation step like body: ${{
steps.generate_changelog.outputs.changelog }}) or add a pre-release check that
fails or prompts if the changelog is empty; locate the hardcoded body string in
the release.yml and wire it to the changelog generation step (or replace it with
a clear reminder/validation step) so actual release notes are included
automatically.

draft: false
prerelease: false
env:
Expand Down
36 changes: 30 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ android {

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

buildConfigField("String", "CLARITY_PROJECT_ID", "\"vc8bgk8nk9\"")

signingConfigs {
create("release") {
val envKeyStore = System.getenv("RELEASE_STORE_FILE")
Expand All @@ -85,6 +83,23 @@ android {
}
}

flavorDimensions += "distribution"

productFlavors {
create("foss") {
dimension = "distribution"
applicationIdSuffix = ".foss"
buildConfigField("String", "APP_NAME_SUFFIX", "\" (FOSS)\"")
buildConfigField("String", "DISTRIBUTION", "\"foss\"")
}
create("play") {
dimension = "distribution"
buildConfigField("String", "APP_NAME_SUFFIX", "\"\"")
buildConfigField("String", "DISTRIBUTION", "\"play\"")
buildConfigField("String", "CLARITY_PROJECT_ID", "\"vc8bgk8nk9\"")
}
}

buildTypes {
release {
val releaseSigningConfig = signingConfigs.getByName("release")
Expand Down Expand Up @@ -127,6 +142,15 @@ android {

}

// Disable Google Services and Crashlytics for FOSS flavor tasks
tasks.configureEach {
if (name.contains("Foss", ignoreCase = true)) {
if (name.contains("GoogleServices") || name.contains("Crashlytics") || name.contains("UploadCrashlyticsMappingFile")) {
enabled = false
}
}
}

dependencies {
implementation(project(":lib"))

Expand Down Expand Up @@ -188,11 +212,11 @@ dependencies {
implementation(libs.moshi)
implementation(libs.moshi.kotlin)

implementation(libs.microsoft.clarity)
"playImplementation"(libs.microsoft.clarity)

implementation(platform(libs.firebase.bom))
implementation(libs.firebase.crashlytics)
implementation(libs.firebase.analytics)
"playImplementation"(platform(libs.firebase.bom))
"playImplementation"(libs.firebase.crashlytics)
"playImplementation"(libs.firebase.analytics)

debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.grakovne.lissen.analytics

import org.grakovne.lissen.common.RunningComponent
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ClarityComponent
@Inject
constructor() : RunningComponent {
override fun onCreate() {}

fun updateConsent(accepted: Boolean) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.grakovne.lissen.analytics

import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ClarityTracker
@Inject
constructor() {
fun setUser(userId: String) {}

fun trackEvent(eventName: String) {}

fun trackEvent(
eventName: String,
value: String,
) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.grakovne.lissen.common

import androidx.compose.ui.Modifier

fun Modifier.maskForAnalytics(): Modifier = this
45 changes: 45 additions & 0 deletions app/src/foss/kotlin/org/grakovne/lissen/common/CrashHandler.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.grakovne.lissen.common

import android.content.Context
import android.os.Looper
import android.widget.Toast
import org.grakovne.lissen.R

class CrashHandler(
context: Context,
private val defaultHandler: Thread.UncaughtExceptionHandler?,
) : Thread.UncaughtExceptionHandler {
private val context = context.applicationContext

override fun uncaughtException(
thread: Thread,
ex: Throwable,
) {
try {
object : Thread() {
override fun run() {
Looper.prepare()
Toast.makeText(context, R.string.app_crash_toast, Toast.LENGTH_LONG).show()

// Schedule the looper to quit so the thread doesn't block indefinitely
android.os.Handler(Looper.myLooper()!!).postDelayed(
{ Looper.myLooper()?.quit() },
TOAST_TIMEOUT + 500,
)

Looper.loop()
}
}.start()

Thread.sleep(TOAST_TIMEOUT)
} catch (e: Exception) {
// Ignore errors in the crash handler itself
} finally {
defaultHandler?.uncaughtException(thread, ex)
}
}

companion object {
private const val TOAST_TIMEOUT = 1000L
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.grakovne.lissen.common

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
interface CrashReporterModule {
@Binds
fun bindCrashReporter(reporter: NoOpCrashReporter): CrashReporter
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.grakovne.lissen.common

import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NoOpCrashReporter
@Inject
constructor() : CrashReporter {
override fun setCollectionEnabled(enabled: Boolean) {
// Do nothing in FOSS
}

override fun recordException(ex: Throwable) {
Timber.e(ex, "Crash reported (FOSS mode - no remote reporting)")
}
}
11 changes: 5 additions & 6 deletions app/src/main/kotlin/org/grakovne/lissen/LissenApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class LissenApplication : Application() {
@Inject
lateinit var runningComponents: Set<@JvmSuppressWildcards RunningComponent>

@Inject
lateinit var crashReporter: org.grakovne.lissen.common.CrashReporter

override fun onCreate() {
super.onCreate()
appContext = applicationContext
Expand All @@ -26,9 +29,7 @@ class LissenApplication : Application() {
}

val isCrashReportingEnabled = preferences.getCrashReportingEnabled()
com.google.firebase.crashlytics.FirebaseCrashlytics
.getInstance()
.setCrashlyticsCollectionEnabled(isCrashReportingEnabled)
crashReporter.setCollectionEnabled(isCrashReportingEnabled)

val defaultHandler = Thread.getDefaultUncaughtExceptionHandler()

Expand All @@ -47,9 +48,7 @@ class LissenApplication : Application() {
it.onCreate()
} catch (ex: Exception) {
Timber.e(ex, "Unable to register Running component: ${ex.message}")
com.google.firebase.crashlytics.FirebaseCrashlytics
.getInstance()
.recordException(ex)
crashReporter.recordException(ex)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.grakovne.lissen.common

interface CrashReporter {
fun setCollectionEnabled(enabled: Boolean)

fun recordException(ex: Throwable)
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class AuthRepository
)
clarityTracker.trackEvent("login_success")
} catch (e: Exception) {
Timber.e(e, "Failed to send login analytics to Clarity")
Timber.e(e, "Failed to send login analytics")
}

// Trigger library fetch
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.grakovne.lissen.content.cache.persistent

import android.content.Context
import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
Expand All @@ -13,6 +11,7 @@ import org.grakovne.lissen.analytics.ClarityTracker
import org.grakovne.lissen.channel.audiobookshelf.common.api.RequestHeadersProvider
import org.grakovne.lissen.channel.common.MediaChannel
import org.grakovne.lissen.channel.common.createOkHttpClient
import org.grakovne.lissen.common.CrashReporter
import org.grakovne.lissen.content.cache.common.findRelatedFiles
import org.grakovne.lissen.content.cache.common.findRelatedFilesByStartTimes
import org.grakovne.lissen.content.cache.common.withBlur
Expand Down Expand Up @@ -43,6 +42,7 @@ class ContentCachingManager
private val preferences: LissenSharedPreferences,
private val clarityTracker: ClarityTracker,
private val localCacheRepository: LocalCacheRepository,
private val crashReporter: CrashReporter,
) {
fun cacheMediaItem(
mediaItem: DetailedItem,
Expand Down Expand Up @@ -270,7 +270,7 @@ class ContentCachingManager
}
}
} catch (ex: Exception) {
Firebase.crashlytics.recordException(ex)
crashReporter.recordException(ex)
return@withContext CacheState(CacheStatus.Error)
}
}
Expand Down Expand Up @@ -300,7 +300,7 @@ class ContentCachingManager
.withBlur(context, width = 300) // Trigger thumbnail transformation
.writeToFile(thumbFile)
} catch (ex: Exception) {
Firebase.crashlytics.recordException(ex)
crashReporter.recordException(ex)
return@fold CacheState(CacheStatus.Error)
}
},
Expand Down
Loading