Skip to content

Feat/foss things - #9

Merged
SurjitSahoo merged 3 commits into
mainfrom
feat/foss-things
Feb 8, 2026
Merged

Feat/foss things#9
SurjitSahoo merged 3 commits into
mainfrom
feat/foss-things

Conversation

@SurjitSahoo

@SurjitSahoo SurjitSahoo commented Feb 8, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • App rebranded to "Kahani" with updated store metadata and refined feature descriptions.
    • Two distribution variants (FOSS and Play) with distribution-specific analytics, crash-reporting behavior, and UI gating for Play-only controls.
    • Added initialization state reporting to library loading for improved loading indicators.
  • Chores

    • CI/build updated to produce separate FOSS and Play artifacts and adjusted release workflow.
    • Centralized crash-reporting abstraction and replaced direct vendor calls with distribution-aware implementations.

@coderabbitai

coderabbitai Bot commented Feb 8, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

The PR introduces flavor-based build variants (FOSS and Play) with flavor-specific analytics and crash reporting implementations. It abstracts crash reporting behind a CrashReporter interface, adds FOSS no-op and Play Firebase implementations, updates DI bindings and UI to be distribution-aware, adjusts CI to build both flavors, and renames app branding from "Lissen" to "Kahani."

Changes

Cohort / File(s) Summary
CI / Gradle
\.github/workflows/build_app.yml, \.github/workflows/release.yml, app/build.gradle.kts
CI tasks changed to run assembleFossRelease and assemblePlayRelease; release workflow uses assemblePlayRelease. Added flavor dimension distribution with foss and play; moved Clarity/Firebase/Crashlytics deps to playImplementation and disabled Google Services/Crashlytics tasks for FOSS.
Crash reporting core
app/src/main/kotlin/org/grakovne/lissen/common/CrashReporter.kt
Added CrashReporter interface with setCollectionEnabled and recordException.
FOSS flavor: analytics & crash
app/src/foss/kotlin/org/grakovne/lissen/analytics/ClarityComponent.kt, app/src/foss/kotlin/org/grakovne/lissen/analytics/ClarityTracker.kt, app/src/foss/kotlin/org/grakovne/lissen/common/NoOpCrashReporter.kt, app/src/foss/kotlin/org/grakovne/lissen/common/CrashReporterModule.kt, app/src/foss/kotlin/org/grakovne/lissen/common/CrashHandler.kt, app/src/foss/kotlin/org/grakovne/lissen/common/AnalyticsExtensions.kt
Added no-op analytics components, NoOpCrashReporter, crash handler that shows a toast on uncaught exceptions, DI module binding NoOp to CrashReporter, and a no-op maskForAnalytics() extension for FOSS.
Play flavor: analytics & crash
app/src/play/kotlin/org/grakovne/lissen/analytics/AnalyticsModule.kt, app/src/play/kotlin/org/grakovne/lissen/common/FirebaseCrashReporter.kt, app/src/play/kotlin/org/grakovne/lissen/common/CrashReporterModule.kt, app/src/play/kotlin/org/grakovne/lissen/common/AnalyticsExtensions.kt
Added FirebaseCrashReporter delegating to Firebase Crashlytics, DI bindings to provide it as CrashReporter, binds ClarityComponent into RunningComponent set, and a maskForAnalytics() extension that delegates to clarityMask().
Application wiring
app/src/main/kotlin/org/grakovne/lissen/LissenApplication.kt, app/src/main/kotlin/org/grakovne/lissen/content/cache/persistent/ContentCachingManager.kt, app/src/main/kotlin/org/grakovne/lissen/persistence/preferences/LissenSharedPreferences.kt, app/src/main/kotlin/org/grakovne/lissen/playback/MediaRepository.kt
Injected CrashReporter into application and repositories; replaced direct Firebase Crashlytics calls with crashReporter.recordException / setCollectionEnabled. Adjusted preference clearing and decryption error reporting to use CrashReporter.
UI updates & analytics masking
app/src/main/kotlin/org/grakovne/lissen/ui/screens/library/LibraryScreen.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/login/LoginScreen.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/player/ChapterSearchActionComposable.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/settings/.../*.kt, app/src/main/kotlin/org/grakovne/lissen/ui/components/VerticalScrollbar.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/settings/composable/LicenseFooterComposable.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/settings/composable/ServerSettingsComposable.kt, app/src/main/kotlin/org/grakovne/lissen/ui/screens/settings/advanced/.../*.kt
Replaced clarityMask() uses with maskForAnalytics() extension across UI. Made analytics-consent sheet and crash-report toggle conditional on BuildConfig.DISTRIBUTION == "play". Removed Crashlytics call from VerticalScrollbar. App name now appends BuildConfig.APP_NAME_SUFFIX.
ViewModel changes
app/src/main/kotlin/org/grakovne/lissen/viewmodel/LibraryViewModel.kt
Added isInitializing StateFlow; wrapped refreshLibrary in try/finally to clear initialization flag; moved repository syncing and added targeted syncLibraryPage when applicable.
Metadata / Branding
metadata/en-US/title.txt, metadata/en-US/short_description.txt, metadata/en-US/full_description.txt
Renamed app title to "Kahani" and updated short/long descriptions with brand-specific feature list and messaging.
Minor text/log updates
app/src/main/kotlin/org/grakovne/lissen/content/AuthRepository.kt
Adjusted an error log message text (removed explicit "to Clarity").

Sequence Diagram(s)

sequenceDiagram
  rect rgba(200,200,255,0.5)
    participant App
    participant DI
    participant UI
  end
  rect rgba(200,255,200,0.5)
    participant CrashReporter
    participant Firebase
    participant Clarity
  end

  App->>DI: inject CrashReporter (at startup)
  DI-->>App: CrashReporter impl (Play: FirebaseCrashReporter / FOSS: NoOpCrashReporter)
  UI->>App: user action / uncaught exception
  App->>CrashReporter: recordException(ex) / setCollectionEnabled(flag)
  alt Play flavor
    CrashReporter->>Firebase: recordException / setCrashlyticsCollectionEnabled
    App->>Clarity: clarity tracking via ClarityComponent (bound into RunningComponent)
  else FOSS flavor
    CrashReporter-->>App: no-op logging (local only)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
Two flavors hop into the light,
FOSS stays quiet, Play tracks the flight,
Crash reports tucked behind an interface neat,
Masking whispers where inputs meet,
Kahani hops on—short, sweet, complete.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/foss things' is vague and generic, using non-descriptive terms like 'things' that don't convey meaningful information about the substantial changes in the PR. Provide a more descriptive title that captures the main change, such as 'Add FOSS build variant with Firebase dependency abstraction' or 'Create FOSS and Play flavors with distribution-specific modules'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/foss-things

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.github/workflows/release.yml:
- 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.

In
`@app/src/main/kotlin/org/grakovne/lissen/persistence/preferences/LissenSharedPreferences.kt`:
- Around line 639-654: The decrypt function currently only catches exceptions
from cipher.doFinal, so Base64.decode, iv/cipherText slicing,
Cipher.getInstance, GCMParameterSpec, cipher.init or getSecretKey() failures can
crash callers (getToken/getAccessToken/getRefreshToken); wrap the entire body of
decrypt(...) in a try-catch that records the exception via
crashReporter.recordException(ex) and returns null on any failure, ensuring all
pre-doFinal errors are handled and callers safely receive null.

In `@metadata/en-US/full_description.txt`:
- Line 17: Remove the trailing whitespace at the end of the sentence "Kahani is
focused on simplicity, privacy, and the joy of a good story." in the
full_description entry so the line ends exactly after the period (no space or
invisible characters), which will eliminate lint/diff noise.
🧹 Nitpick comments (7)
.github/workflows/build_app.yml (1)

20-20: Consider upgrading action versions to match release.yml.

release.yml uses actions/checkout@v4 and actions/setup-java@v4, while this workflow still uses @v3 for both. Aligning versions avoids subtle behavioral differences between workflows.

app/src/main/kotlin/org/grakovne/lissen/ui/screens/settings/advanced/AdvancedSettingsComposable.kt (1)

114-120: Consider extracting the "play" magic string to a constant.

The string "play" is used here and in LibraryScreen.kt (Line 504) for distribution checks. A shared constant (e.g., const val PLAY_DISTRIBUTION = "play" in a common location) would reduce the risk of typos and make distribution checks easier to find and maintain.

app/src/main/kotlin/org/grakovne/lissen/ui/screens/library/LibraryScreen.kt (1)

112-112: Replace collectAsState(true) with collectAsState() for simpler state management.

Since libraryViewModel.isInitializing is a StateFlow<Boolean> already initialized to true in the ViewModel, calling collectAsState() without the parameter will automatically use the StateFlow's current value. This is cleaner and more maintainable, as it eliminates redundancy and ensures the composable automatically adapts if the ViewModel's initialization logic changes in the future.

app/src/foss/kotlin/org/grakovne/lissen/common/CrashHandler.kt (1)

35-36: Consider logging the swallowed exception for debuggability.

The catch block silently discards exceptions occurring within the crash handler itself. While ignoring them is reasonable to avoid recursive crashes, logging with Timber.e (or Log.e to avoid Timber dependency issues in a crash path) would aid debugging if the toast display ever fails silently.

Proposed fix
     } catch (e: Exception) {
-      // Ignore errors in the crash handler itself
+      // Best-effort log; avoid rethrowing to prevent recursive crashes
+      android.util.Log.e("CrashHandler", "Error in crash handler", e)
     } finally {
app/src/main/kotlin/org/grakovne/lissen/viewmodel/LibraryViewModel.kt (1)

64-65: _isInitializing can be prematurely cleared when concurrent refreshLibrary calls overlap.

refreshLibrary is called from checkRefreshNeeded, the init server-availability collector, and potentially from the UI (with forceRefresh). Each call launches a separate coroutine with its own finally { _isInitializing.value = false }. If two calls overlap, the first to finish will clear the flag while the second is still running.

For a loading indicator this is likely tolerable, but worth noting if the initializing state is used to gate important UI behavior (e.g., preventing user interaction).

Also applies to: 238-273

app/build.gradle.kts (2)

99-99: Hardcoded Clarity project ID in the build file.

CLARITY_PROJECT_ID is embedded directly in the Gradle config. While not a secret (it's a client-side analytics identifier), consider managing it via local.properties or an environment variable for consistency with how signing config is handled, and to make it easier to change per-environment without modifying the build script.


145-152: Task-name-based filtering is fragile but pragmatic.

Disabling Google Services / Crashlytics tasks by matching on task name strings (contains("Foss"), contains("GoogleServices")) is a well-known workaround for flavor-aware plugin disabling. Just be aware this can break if AGP or the Google Services plugin renames tasks in a future version.

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.

• Home Widget: Control your current story directly from your home screen.
• Network Aware: Intelligently manages offline/online states and server availability.

Kahani is focused on simplicity, privacy, and the joy of a good story.

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

Remove trailing whitespace.
Minor cleanup to avoid diff noise and lint warnings in some pipelines.

🧹 Proposed fix
-Kahani is focused on simplicity, privacy, and the joy of a good story. 
+Kahani is focused on simplicity, privacy, and the joy of a good story.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Kahani is focused on simplicity, privacy, and the joy of a good story.
Kahani is focused on simplicity, privacy, and the joy of a good story.
🤖 Prompt for AI Agents
In `@metadata/en-US/full_description.txt` at line 17, Remove the trailing
whitespace at the end of the sentence "Kahani is focused on simplicity, privacy,
and the joy of a good story." in the full_description entry so the line ends
exactly after the period (no space or invisible characters), which will
eliminate lint/diff noise.

@SurjitSahoo
SurjitSahoo merged commit 8932d8a into main Feb 8, 2026
1 of 2 checks passed
@SurjitSahoo
SurjitSahoo deleted the feat/foss-things branch February 8, 2026 18:32
@coderabbitai coderabbitai Bot mentioned this pull request Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant