Skip to content

Obtainium import/export (#444 ask 1/3)#502

Merged
rainxchzed merged 5 commits into
mainfrom
feat/444-obtainium-import-export
May 4, 2026
Merged

Obtainium import/export (#444 ask 1/3)#502
rainxchzed merged 5 commits into
mainfrom
feat/444-obtainium-import-export

Conversation

@rainxchzed
Copy link
Copy Markdown
Member

@rainxchzed rainxchzed commented May 4, 2026

First of three PRs for #444. Adds Obtainium JSON support to the existing import/export flow plus a richer summary sheet. See plan in roadmap/444_A_OBTAINIUM_IMPORT_EXPORT.md.

What's in here

  • Auto-detect import format. The existing Import from file entry now sniffs the JSON shape — native v4 or Obtainium — and routes accordingly. No format picker, no separate menu entry.
  • Pre-import summary bottom sheet with four buckets, each expandable: imported, already tracked, not GitHub-hosted (Obtainium libraries often contain GitLab/F-Droid/HTML — we surface them, never silently drop), failed.
  • Unknown-format affordance: when the file is neither schema, sheet shows the first 200 chars of the parsed content for triage.
  • Export for Obtainium added as a sibling menu item alongside the native export. Round-tripping is the trust signal — any user who wants to leave can leave.
  • A11y: bucket counts announced via LiveRegion. Sheet dismisses on button press, never on a timer.
  • Renamed labels: "Import" → "Import from file", "Export" → "Export library" (clearer with the new sibling).
  • What's-new bullet shipped in 16.json across 13 locales.

Tradeoffs

  • Detection looks at top-level apps[] shape only. Could be stricter (Obtainium has additionalSettings / overrideSource discriminators) but URL-pattern + key-shape catches the real-world cases without false positives on truncated v4 exports.
  • Obtainium export pins to a v2-ish schema (their format shifts; we mirror what their current importer accepts: id, url, author, name, additionalSettings, overrideSource: "GitHub"). If Obtainium breaks the schema, recovery is one mapper edit.
  • We don't round-trip Obtainium's per-app installerPackageName field. That's an explicit decoupling — the upcoming installer-attribution feature (Plan C) ships independently. Documented in plan A out-of-scope.

Test plan

  • Native v4 export → re-import works, summary shows all skipped (regression).
  • Obtainium export of 50 mixed-forge apps → summary shows GitHub apps imported, GitLab/F-Droid surfaced as "not GitHub" with names listed in the expander.
  • Random JSON / corrupted file → "Couldn't read this file" sheet with first-200-chars preview.
  • Export library → file passes Obtainium's importer (manual round-trip test).
  • Skipped/imported expanders show repo names; failed expander shows what didn't link.
  • TalkBack reads bucket counts after import completes.

Summary by CodeRabbit

  • New Features

    • One-tap Import from Obtainium with a detailed, dismissible import summary showing imported, already-tracked, non‑GitHub, and failed items; unknown-format preview supported
    • Export library to Obtainium format anytime; "Export Obtainium" added to the Apps menu and export flow shares an Obtainium-formatted file
  • UI / Text

    • Updated export/import labels and localized "What's New" entries announcing Obtainium support

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d8423892-dc75-4d59-a98e-6bdd5942ff5b

📥 Commits

Reviewing files that changed from the base of the PR and between a005fc5 and ab1e898.

📒 Files selected for processing (1)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt
✅ Files skipped from review due to trivial changes (1)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt

Walkthrough

Adds Obtainium import/export: new serializable domain models, mappers for conversion, repository export/import with format detection, enriched ImportResult, UI wiring (actions/state/viewmodel), ImportSummarySheet UI, localized strings, and release-note updates.

Changes

Obtainium Export/Import Feature

Layer / File(s) Summary
Domain Models
core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/ObtainiumExport.kt
New @Serializable ObtainiumExport and ObtainiumApp types for Obtainium-format payloads.
Data Mappers (export)
core/data/.../ObtainiumExportMapper.kt
Added InstalledApp.toObtainiumApp() building additionalSettingsRaw JSON and producing ObtainiumApp instances.
Data Mappers (import & parsing)
core/data/.../ObtainiumImportMapper.kt
Added parsing helpers: parseGithubOwnerRepo, parseAdditionalSettings, and ObtainiumApp.toExportedAppOrSkip(); introduced ObtainiumMapResult with unsupportedFailureLabel to distinguish unsupported inputs (e.g., inverted APK filters) from non-GitHub skips.
Repository Interface & Implementation
feature/apps/domain/.../AppsRepository.kt, feature/apps/data/.../AppsRepositoryImpl.kt
Interface gains exportObtainium(). Impl adds exportObtainium() (serialize installed apps to ObtainiumExport), refactors importApps(json) to detect format (NATIVE/OBTAINIUM/UNKNOWN), dispatch to importNative or importObtainium, link apps to repos, and return enriched ImportResult with item lists and format metadata.
Import Result Model
feature/apps/domain/.../ImportResult.kt
ImportResult expanded with defaulted counters, lists (importedItems, skippedItems, nonGitHubItems, failedItems), sourceFormat enum (NATIVE, OBTAINIUM, UNKNOWN), and unknownFormatPreview.
Presentation State & Actions
feature/apps/presentation/.../AppsState.kt, feature/apps/presentation/.../AppsAction.kt
AppsState adds optional importSummary: ImportResult?. AppsAction adds OnExportObtainium and OnDismissImportSummary.
ViewModel Logic
feature/apps/presentation/.../AppsViewModel.kt
Handles OnExportObtainium (calls repo export + share flow) and OnDismissImportSummary (clears summary). Import completion now stores raw ImportResult in state and emits ImportComplete event.
UI Components
feature/apps/presentation/.../AppsRoot.kt, feature/apps/presentation/.../components/ImportSummarySheet.kt
AppsRoot adds "Export Obtainium" menu item and conditionally renders ImportSummarySheet. New ImportSummarySheet composable shows format-specific title, expandable buckets for imported/skipped/non-GitHub/failed lists, unknown-format preview sheet, and close action.
Strings & Release Notes
core/presentation/.../values/strings.xml, core/presentation/.../whatsnew/*/16.json
Updated export/import UI labels, added Obtainium-specific export label and import-summary strings, and added Obtainium import/export bullet to localized whatsnew JSON files across languages.

Sequence Diagram

sequenceDiagram
    participant UI as UI (Compose)
    participant VM as AppsViewModel
    participant Repo as AppsRepository
    participant Mapper as ObtainiumImportMapper
    participant Share as ShareManager

    UI->>VM: OnExportObtainium
    VM->>Repo: exportObtainium()
    Repo->>Mapper: map InstalledApp -> ObtainiumApp
    Mapper-->>Repo: ObtainiumExport JSON
    Repo-->>VM: JSON string
    VM->>Share: share(filename, JSON)
    Share-->>VM: success/failure
    VM-->>UI: emit ShowError / share completed

    UI->>VM: OnImportApps(json)
    VM->>Repo: importApps(json)
    Repo->>Repo: detectFormat(json)
    alt OBTAINIUM
      Repo->>Mapper: parse ObtainiumExport -> toExportedAppOrSkip()
      Mapper-->>Repo: ExportedApp or skip labels
      Repo->>Repo: linkAppToRepo(...) per ExportedApp
    else NATIVE
      Repo->>Repo: decode native ExportedAppList
      Repo->>Repo: linkAppToRepo(...) per item
    else UNKNOWN
      Repo-->>VM: ImportResult(source=UNKNOWN, preview)
    end
    Repo-->>VM: ImportResult (detailed)
    VM-->>UI: update state.importSummary / emit ImportComplete
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

"🐰 I hopped through code with nimble paws and cheer,
Mapping apps to Obtainium, so imports are clear.
One tap to fetch, one tap to send, the library gleams —
This rabbit celebrates with bytes and tiny dreams! 🥕📦"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding Obtainium import/export functionality. It is concise, uses standard PR notation (#444), and accurately reflects the changeset's primary objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/444-obtainium-import-export

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
Review rate limit: 5/8 reviews remaining, refill in 17 minutes and 47 seconds.

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (3)
core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json (1)

14-15: ⚡ Quick win

Consider aligning the “What’s New” wording with the updated UI labels.

The new bullet uses “Obtainium 가져오기/내보내기”, but the PR objectives mention updated UI copy semantics like “Import from file” and “Export library”. If those distinctions matter for users (import source vs export destination/scope), consider tweaking the Korean bullet to match the same intent/terminology as the app’s action labels.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json`
around lines 14 - 15, The Korean bullet "Obtainium 가져오기/내보내기" should be
split/reworded to match the app UI semantics: replace that single string with
wording that distinguishes import source and export scope, e.g. use "파일에서
Obtainium 가져오기" to reflect "Import from file" and "Obtainium 형식으로 라이브러리 내보내기" to
reflect "Export library"; update the JSON entry that currently contains
"Obtainium 가져오기/내보내기" accordingly so users see the same intent/terminology as
the UI.
core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json (1)

14-15: ⚡ Quick win

TURKISH copy: “Obtainium içe/dışa aktarma” ifadesini biraz daha netleştirin.

Mevcut metin (“...tek dokunuşla getirin...”) “içe aktar” karşılığını tam taşımıyor; ayrıca “içe/dışa aktarma” başlığıyla daha tutarlı bir fiil kullanılırsa kullanıcı için anlaşılabilirlik artar. Örn. “getirin” yerine “içe aktarın” gibi.

🛠️ Önerilen metin güncellemesi
-        "Obtainium içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla getirin ya da istediğiniz zaman Obtainium biçiminde dışa aktarın."
+        "Obtainium içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla içe aktarın ya da istediğiniz zaman Obtainium biçiminde dışa aktarın."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json`
around lines 14 - 15, Update the Turkish copy string that currently reads
"Obtainium içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla getirin ya
da istediğiniz zaman Obtainium biçiminde dışa aktarın." to use consistent,
clearer verbs for import/export (e.g., replace "getirin" with "içe aktarın") so
the header "Obtainium içe/dışa aktarma" aligns with the action descriptions;
ensure the revised sentence mirrors the header structure such as "Obtainium
içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla içe aktarın veya
istediğiniz zaman Obtainium biçiminde dışa aktarın."
feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt (1)

76-78: ⚡ Quick win

Consider documenting the Obtainium export contract (schema + stability + unsupported fields).

Right now the interface exposes exportObtainium(): String but doesn’t say what schema version/shape callers can expect or what’s intentionally omitted for unsupported Obtainium fields. A short KDoc on the method would prevent downstream misuse/regressions when the schema evolves.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt`
around lines 76 - 78, Add KDoc to AppsRepository.exportObtainium(): String
describing the Obtainium export contract: state the schema version (e.g., "v1"),
the expected JSON shape/fields (required vs optional), which fields are
intentionally omitted or unsupported, stability/compatibility guarantees (what
may change and how), and any consumer expectations (encoding, size limits).
Reference the exportObtainium() method in the comment, include examples or a
link to the formal schema if available, and note how breaking changes will be
communicated so callers don’t misinterpret future exports.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt`:
- Around line 86-91: The current mapping treats invertFilter (derived from
apkFilterRegEx/invertAPKFilter) as no filter by setting effectiveFilter = null
which silently broadens assetFilterRegex; instead detect when invertFilter is
true and surface it explicitly by failing the import or returning a clear
sentinel/error value rather than null—update the logic around
invertFilter/effectiveFilter in ObtainiumImportMapper (where apkFilterRegEx and
invertAPKFilter are parsed) so that inverted filters are reported as unsupported
(e.g., throw a descriptive exception or return an explicit "inverted filter
unsupported" result alongside fallback) instead of returning a null
assetFilterRegex.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json`:
- Around line 14-15: Update the second bullet string so it explicitly reads
"Import from file" in Bengali: find the JSON entry currently starting with
"Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন, বা
যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।" and change the import phrase to
include "ফাইল থেকে" (e.g., "Obtainium ইম্পোর্ট/এক্সপোর্ট — একটি ক্লিকে ফাইল থেকে
Obtainium লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।") so
the wording matches the UI label renaming to “Import from file.”

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json`:
- Around line 14-15: Replace the misspelled product name "Dhizuku" with
"Shizuku" in the French whatsnew entry that starts with "Installation
silencieuse via Dhizuku : contournez les fenêtres d’installation des OEM..." so
it matches the other mention of "Shizuku" in the same file (the string value in
the JSON array for fr/16.json).

In
`@feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt`:
- Around line 275-280: exportObtainium() currently serializes an empty library
as {"apps":[]} which detectFormat() treats as UNKNOWN because it sniff-parses
the first app; add a stable top-level discriminator to the Obtainium export
(e.g. a format or version field on the ObtainiumExport data class) and populate
it from exportObtainium() when serializing, then update detectFormat() to check
that top-level discriminator (accepting an empty "apps" array if the
discriminator matches) so empty exports round-trip reliably.
- Around line 307-318: detectFormat currently only inspects apps.firstOrNull(),
causing mixed files to be misclassified; update detectFormat to iterate over the
apps JsonArray and evaluate each app JsonObject: if any app contains "repoOwner"
and "repoName" return ImportFormat.NATIVE, else if any app has the Obtainium
shape (contains "id" and "url" and the url jsonPrimitive contains "github.com")
return ImportFormat.OBTAINIUM, otherwise return ImportFormat.UNKNOWN; reference
the detectFormat function, the apps JsonArray, firstApp check, and
importObtainium path when making the change.

In
`@feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/ImportSummarySheet.kt`:
- Around line 279-283: The IconButton's Icon currently sets contentDescription
to null, making the expand/collapse control inaccessible; update the Icon in the
ImportSummarySheet component to provide a localized label derived from the
expanded boolean (e.g., use stringResource(R.string.collapse) when expanded is
true and stringResource(R.string.expand) when false) and pass that string as the
Icon's contentDescription so screen readers announce the control; reference the
IconButton/Icon and the expanded variable to locate where to inject the
localized string resources.
- Around line 102-121: The accessibility announcement currently builds a
hardcoded-English string in ImportSummarySheet.kt (the announcement variable
created via buildString and assigned to the Text semantics
contentDescription/liveRegion), which must be replaced with a localized string;
update the code to obtain a formatted, localized resource from the
core/presentation 13-language localization system (use the appropriate string
key that accepts imported, skipped, nonGitHubSkipped and failed counts, handle
the optional nonGitHubSkipped segment via plural/optional formatting in the
resource), format it with the numeric values, and assign that localized result
to the semantics contentDescription (instead of the hardcoded buildString) so
TalkBack/VoiceOver follows the active locale.

---

Nitpick comments:
In `@core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json`:
- Around line 14-15: The Korean bullet "Obtainium 가져오기/내보내기" should be
split/reworded to match the app UI semantics: replace that single string with
wording that distinguishes import source and export scope, e.g. use "파일에서
Obtainium 가져오기" to reflect "Import from file" and "Obtainium 형식으로 라이브러리 내보내기" to
reflect "Export library"; update the JSON entry that currently contains
"Obtainium 가져오기/내보내기" accordingly so users see the same intent/terminology as
the UI.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json`:
- Around line 14-15: Update the Turkish copy string that currently reads
"Obtainium içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla getirin ya
da istediğiniz zaman Obtainium biçiminde dışa aktarın." to use consistent,
clearer verbs for import/export (e.g., replace "getirin" with "içe aktarın") so
the header "Obtainium içe/dışa aktarma" aligns with the action descriptions;
ensure the revised sentence mirrors the header structure such as "Obtainium
içe/dışa aktarma — Obtainium kütüphanenizi tek dokunuşla içe aktarın veya
istediğiniz zaman Obtainium biçiminde dışa aktarın."

In
`@feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt`:
- Around line 76-78: Add KDoc to AppsRepository.exportObtainium(): String
describing the Obtainium export contract: state the schema version (e.g., "v1"),
the expected JSON shape/fields (required vs optional), which fields are
intentionally omitted or unsupported, stability/compatibility guarantees (what
may change and how), and any consumer expectations (encoding, size limits).
Reference the exportObtainium() method in the comment, include examples or a
link to the formal schema if available, and note how breaking changes will be
communicated so callers don’t misinterpret future exports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1ec37ac9-a5e5-4e21-9d9c-68570de46091

📥 Commits

Reviewing files that changed from the base of the PR and between 3c477cc and fb00c26.

📒 Files selected for processing (25)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumExportMapper.kt
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt
  • core/domain/src/commonMain/kotlin/zed/rainxch/core/domain/model/ObtainiumExport.kt
  • core/presentation/src/commonMain/composeResources/files/whatsnew/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json
  • core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt
  • feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/model/ImportResult.kt
  • feature/apps/domain/src/commonMain/kotlin/zed/rainxch/apps/domain/repository/AppsRepository.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsAction.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsState.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsViewModel.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/ImportSummarySheet.kt

Comment on lines +14 to +15
"Dhizuku সাইলেন্ট ইনস্টল — Device Owner-এর মাধ্যমে Xiaomi, OPPO, vivo, Huawei ডিভাইসে OEM ইনস্টল প্রম্পট এড়িয়ে যান।",
"Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the “Obtainium import” bullet explicitly “from file” to match the UI label change.

The added bullet says “এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন…”, which may read like importing from “Obtainium” generally, rather than from a file—whereas the PR intent is specifically to rename the UI to “Import from file”.

💡 Suggested wording tweak
-        "Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।"
+        "Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে ফাইল থেকে Obtainium লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।"
📝 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
"Dhizuku সাইলেন্ট ইনস্টল — Device Owner-এর মাধ্যমে Xiaomi, OPPO, vivo, Huawei ডিভাইসে OEM ইনস্টল প্রম্পট এড়িয়ে যান।",
"Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।"
"Dhizuku সাইলেন্ট ইনস্টল — Device Owner-এর মাধ্যমে Xiaomi, OPPO, vivo, Huawei ডিভাইসে OEM ইনস্টল প্রম্পট এড়িয়ে যান।",
"Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে ফাইল থেকে Obtainium লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json`
around lines 14 - 15, Update the second bullet string so it explicitly reads
"Import from file" in Bengali: find the JSON entry currently starting with
"Obtainium ইম্পোর্ট/এক্সপোর্ট — এক ট্যাপে Obtainium থেকে লাইব্রেরি আনুন, বা
যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।" and change the import phrase to
include "ফাইল থেকে" (e.g., "Obtainium ইম্পোর্ট/এক্সপোর্ট — একটি ক্লিকে ফাইল থেকে
Obtainium লাইব্রেরি আনুন, বা যেকোনো সময় Obtainium ফরম্যাটে এক্সপোর্ট করুন।") so
the wording matches the UI label renaming to “Import from file.”

Comment on lines +14 to +15
"Installation silencieuse via Dhizuku : contournez les fenêtres d’installation des OEM (Xiaomi, OPPO, vivo, Huawei) grâce au statut Propriétaire de l’appareil.",
"Import/Export Obtainium : récupérez votre bibliothèque depuis Obtainium en un toucher, ou exportez vers Obtainium quand vous voulez."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix likely typo/inconsistent naming: “Dhizuku” → “Shizuku”.

The new French bullet uses “Dhizuku”, but this same file already mentions “Shizuku” in the FIXED section (line ~29). If the intended product is “Shizuku”, this is a user-facing text bug that should be corrected for consistency and clarity.

Suggested diff
-        "Installation silencieuse via Dhizuku : contournez les fenêtres d’installation des OEM (Xiaomi, OPPO, vivo, Huawei) grâce au statut Propriétaire de l’appareil.",
+        "Installation silencieuse via Shizuku : contournez les fenêtres d’installation des OEM (Xiaomi, OPPO, vivo, Huawei) grâce au statut Propriétaire de l’appareil.",
📝 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
"Installation silencieuse via Dhizuku : contournez les fenêtres dinstallation des OEM (Xiaomi, OPPO, vivo, Huawei) grâce au statut Propriétaire de lappareil.",
"Import/Export Obtainium : récupérez votre bibliothèque depuis Obtainium en un toucher, ou exportez vers Obtainium quand vous voulez."
"Installation silencieuse via Shizuku : contournez les fenêtres d'installation des OEM (Xiaomi, OPPO, vivo, Huawei) grâce au statut Propriétaire de l'appareil.",
"Import/Export Obtainium : récupérez votre bibliothèque depuis Obtainium en un toucher, ou exportez vers Obtainium quand vous voulez."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json`
around lines 14 - 15, Replace the misspelled product name "Dhizuku" with
"Shizuku" in the French whatsnew entry that starts with "Installation
silencieuse via Dhizuku : contournez les fenêtres d’installation des OEM..." so
it matches the other mention of "Shizuku" in the same file (the string value in
the JSON array for fr/16.json).

…ction, stamp export discriminator, localize summary a11y
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt`:
- Around line 34-38: The current code in ObtainiumImportMapper sets a blank
package id into nonGitHubLabel which is wrong; instead route it to the failure
bucket. In the block that computes packageName (in ObtainiumImportMapper.kt)
replace the ObtainiumMapResult construction so exported = null, nonGitHubLabel =
null, and unsupportedFailureLabel = "$owner/$repo (missing package id)" (i.e.,
move the "(missing package id)" message from nonGitHubLabel into
unsupportedFailureLabel) so GitHub-hosted entries with a blank id are treated as
failures not "non-GitHub".
- Around line 68-88: The code stores the original rawUrl into repoUrl which can
include query strings, fragments or extra path segments; instead, after calling
parseGithubOwnerRepo(rawUrl) (the function defined in ObtainiumImportMapper),
reconstruct a canonical repository URL using the parsed owner and repo (e.g.
"https://github.com/{owner}/{repo}") and assign that canonical URL to repoUrl;
ensure this replacement happens only when parseGithubOwnerRepo returns a
non-null Pair and keep existing validation (owner/repo length checks) intact so
exported/open-in-browser links always point to the repo root.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dbb57672-090a-4b48-bf0a-33d51300e28c

📥 Commits

Reviewing files that changed from the base of the PR and between fb00c26 and a005fc5.

📒 Files selected for processing (4)
  • core/data/src/commonMain/kotlin/zed/rainxch/core/data/mappers/ObtainiumImportMapper.kt
  • core/presentation/src/commonMain/composeResources/values/strings.xml
  • feature/apps/data/src/commonMain/kotlin/zed/rainxch/apps/data/repository/AppsRepositoryImpl.kt
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/ImportSummarySheet.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/components/ImportSummarySheet.kt

@rainxchzed rainxchzed merged commit ec5fffb into main May 4, 2026
1 check passed
@rainxchzed rainxchzed deleted the feat/444-obtainium-import-export branch May 4, 2026 11:33
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