diff --git a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/dto/BackendRepoResponse.kt b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/dto/BackendRepoResponse.kt index 2204d80fc..def195dc4 100644 --- a/core/data/src/commonMain/kotlin/zed/rainxch/core/data/dto/BackendRepoResponse.kt +++ b/core/data/src/commonMain/kotlin/zed/rainxch/core/data/dto/BackendRepoResponse.kt @@ -13,6 +13,7 @@ data class BackendRepoResponse( val htmlUrl: String, val stargazersCount: Int, val forksCount: Int, + val openIssuesCount: Int = 0, val language: String? = null, val topics: List = emptyList(), val releasesUrl: String? = null, diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json index 6b64c44b5..911ad71c0 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "Manual rescan surfaces every GitHub-style app on device.", - "Tighter auth handling — transient 401s no longer trigger spurious sign-outs." + "Tighter auth handling — transient 401s no longer trigger spurious sign-outs.", + "Open-issues count now shown to everyone, including signed-out users — the count now comes from the backend." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json index 6b45404ac..83857c6bf 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ar/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "إعادة المسح اليدوي تُظهر كل تطبيقات GitHub الموجودة على الجهاز دون تفويت أيّ منها.", - "معالجة أكثر صرامة للمصادقة: استجابات 401 العابرة لم تعد تتسبّب في تسجيل خروج خاطئ." + "معالجة أكثر صرامة للمصادقة: استجابات 401 العابرة لم تعد تتسبّب في تسجيل خروج خاطئ.", + "عداد المشكلات المفتوحة يظهر الآن للجميع بمن فيهم غير المسجَّلين — يأتي من الخادم الخلفي دون أي تكلفة لحصص GitHub." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json index c4c9b873b..94514310e 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/bn/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "ম্যানুয়াল রি-স্ক্যান এখন ডিভাইসে থাকা সব GitHub-ধাঁচের অ্যাপ তুলে আনে।", - "অথেনটিকেশন আরও সংযত: সাময়িক 401 আর ভুল করে সাইন-আউট ঘটায় না।" + "অথেনটিকেশন আরও সংযত: সাময়িক 401 আর ভুল করে সাইন-আউট ঘটায় না।", + "ওপেন ইস্যুর সংখ্যা এখন সবাইকে দেখানো হয়, এমনকি সাইন-ইন না করা ব্যবহারকারীদেরও — ব্যাকএন্ড থেকে আসে, GitHub কোটায় কোনো খরচ নেই।" ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json index 613fc5ffb..920817655 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/es/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "El reescaneo manual muestra todas las apps tipo GitHub presentes en el dispositivo.", - "Mejor manejo de autenticación: los 401 transitorios ya no provocan cierres de sesión espurios." + "Mejor manejo de autenticación: los 401 transitorios ya no provocan cierres de sesión espurios.", + "El número de incidencias abiertas ahora se muestra a todos, incluidos los usuarios sin sesión — viene del backend, sin coste de cuota de GitHub." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json index e6b846361..ec6e2922d 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/fr/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "Le rescan manuel fait remonter toutes les apps de type GitHub présentes sur l’appareil.", - "Gestion d’authentification renforcée : les 401 transitoires ne déconnectent plus à tort." + "Gestion d’authentification renforcée : les 401 transitoires ne déconnectent plus à tort.", + "Le nombre d’issues ouvertes s’affiche désormais pour tout le monde, y compris les utilisateurs déconnectés — fourni par le backend, sans coût de quota GitHub." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json index c1e170b0e..e5ce2f506 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/hi/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "मैन्युअल रीस्कैन डिवाइस पर मौजूद हर GitHub-शैली के ऐप को सामने ले आता है।", - "ऑथ हैंडलिंग पहले से बेहतर: अस्थायी 401 अब ग़लती से साइन-आउट नहीं कराते।" + "ऑथ हैंडलिंग पहले से बेहतर: अस्थायी 401 अब ग़लती से साइन-आउट नहीं कराते।", + "खुले इश्यू की संख्या अब सभी को दिखाई देती है, यहाँ तक कि साइन-आउट उपयोगकर्ताओं को भी — बैकएंड से आती है, GitHub कोटे पर कोई असर नहीं।" ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json index aa75ead28..50bbdfc5e 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/it/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "La rilevazione manuale mostra tutte le app di tipo GitHub presenti sul dispositivo.", - "Gestione dell’autenticazione più solida: i 401 transitori non causano più disconnessioni indebite." + "Gestione dell’autenticazione più solida: i 401 transitori non causano più disconnessioni indebite.", + "Il conteggio delle issue aperte ora è visibile a tutti, anche agli utenti non autenticati — arriva dal backend, senza costi di quota GitHub." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json index 83749c481..f4bff0d77 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ja/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "手動での再スキャンで、端末上の GitHub 系アプリをすべて検出するようになりました。", - "認証エラー処理を強化。一時的な 401 で誤ってサインアウトされなくなりました。" + "認証エラー処理を強化。一時的な 401 で誤ってサインアウトされなくなりました。", + "オープン Issue 数を未ログインユーザーを含む全員に表示。バックエンドから取得するため GitHub のクォータを消費しません。" ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json index b1dedc580..3747fe9de 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ko/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "수동 재스캔이 기기의 모든 GitHub 계열 앱을 빠짐없이 표시합니다.", - "인증 처리 강화: 일시적인 401로 인해 잘못 로그아웃되지 않습니다." + "인증 처리 강화: 일시적인 401로 인해 잘못 로그아웃되지 않습니다.", + "열린 이슈 수가 이제 로그아웃 사용자를 포함한 모두에게 표시됩니다 — 백엔드에서 제공되며 GitHub 할당량을 소비하지 않습니다." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json index 8aa365945..6b7eeb00e 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/pl/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "Ręczne ponowne skanowanie pokazuje wszystkie aplikacje z GitHuba obecne na urządzeniu.", - "Stabilniejsza obsługa autoryzacji — przejściowe 401 nie powodują już fałszywych wylogowań." + "Stabilniejsza obsługa autoryzacji — przejściowe 401 nie powodują już fałszywych wylogowań.", + "Liczba otwartych zgłoszeń jest teraz pokazywana wszystkim, także użytkownikom niezalogowanym — pochodzi z backendu, bez kosztów limitu GitHuba." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json index dd5061b92..b4a41ad98 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/ru/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "Ручное пересканирование показывает все приложения GitHub-типа на устройстве.", - "Аккуратная обработка авторизации: единичные 401 больше не вызывают ложный выход из аккаунта." + "Аккуратная обработка авторизации: единичные 401 больше не вызывают ложный выход из аккаунта.", + "Количество открытых задач теперь видно всем, в том числе неавторизованным пользователям — берётся из бэкенда, без расхода квоты GitHub." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json index dc44a42e2..33deac8de 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/tr/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "Manuel yeniden tarama, cihazdaki tüm GitHub tipi uygulamaları görünür kılıyor.", - "Daha sağlam kimlik doğrulama: geçici 401 yanıtları artık yanlışlıkla oturumu kapatmıyor." + "Daha sağlam kimlik doğrulama: geçici 401 yanıtları artık yanlışlıkla oturumu kapatmıyor.", + "Açık konu sayısı artık oturum açmamış kullanıcılar dahil herkese gösteriliyor — backend'den geliyor, GitHub kotası harcamıyor." ] }, { diff --git a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json index 3051e553a..5bd975615 100644 --- a/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json +++ b/core/presentation/src/commonMain/composeResources/files/whatsnew/zh-CN/16.json @@ -22,7 +22,8 @@ "type": "IMPROVED", "bullets": [ "手动重新扫描会列出设备上所有 GitHub 风格的应用,不再漏报。", - "更稳健的鉴权处理:偶发的 401 不会再让你被错误地踢出登录。" + "更稳健的鉴权处理:偶发的 401 不会再让你被错误地踢出登录。", + "未登录用户也能看到「Open Issues」数量了 — 数据来自后端,不消耗任何 GitHub 配额。" ] }, { diff --git a/feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/DetailsRepositoryImpl.kt b/feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/DetailsRepositoryImpl.kt index dd28bbf98..3de9ed257 100644 --- a/feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/DetailsRepositoryImpl.kt +++ b/feature/details/data/src/commonMain/kotlin/zed/rainxch/details/data/repository/DetailsRepositoryImpl.kt @@ -211,7 +211,7 @@ class DetailsRepositoryImpl( val cacheKey = "details:repo:$owner/$name" cacheManager.put(cacheKey, result, REPO_DETAILS) cacheManager.invalidate("details:repo_id:${result.id}") - cacheManager.invalidate("details:stats:$owner/$name") + cacheManager.invalidate("details:stats:v2:$owner/$name") cacheManager.invalidate("details:latest_release:$owner/$name") cacheManager.invalidate("details:releases:$owner/$name") return result @@ -517,16 +517,19 @@ class DetailsRepositoryImpl( owner: String, repo: String, ): RepoStats { - val cacheKey = "details:stats:$owner/$repo" + // v2 — backend now supplies openIssues; pre-PR entries had it pinned + // to 0 for anon users. Bumping the key forces re-fetch instead of + // serving stale zeros for the remainder of the 6h TTL after upgrade. + val cacheKey = "details:stats:v2:$owner/$repo" cacheManager.get(cacheKey)?.let { cached -> logger.debug("Cache hit for repo stats $owner/$repo") return cached } - // Try backend first — provides stars/forks/downloadCount. - // Backend doesn't have openIssues/license, so supplement with a - // best-effort GitHub call for those fields. If GitHub is blocked + // Try backend first — provides stars/forks/openIssues/downloadCount. + // Backend doesn't have license yet, so supplement with a best-effort + // GitHub call for that field when signed in. If GitHub is blocked // (e.g. for users in China), we still show the backend data. val backendResult = backendApiClient.getRepo(owner, repo) backendResult.fold( @@ -553,19 +556,22 @@ class DetailsRepositoryImpl( null } - // If the GitHub enrichment didn't land, reuse the stale - // cached openIssues/license from a previous successful - // resolve. Prevents a transient GitHub failure from - // clobbering real values with zeros/nulls. - val stale = if (githubInfo == null) cacheManager.getStale(cacheKey) else null + // Preserve last-known license when GitHub enrichment didn't + // land — backend doesn't supply license yet, so a transient + // failure would otherwise clobber a real value with null. + val staleLicense = if (githubInfo == null) { + cacheManager.getStale(cacheKey)?.license + } else { + null + } val result = RepoStats( stars = backendRepo.stargazersCount, forks = backendRepo.forksCount, - openIssues = githubInfo?.openIssues ?: stale?.openIssues ?: 0, + openIssues = backendRepo.openIssuesCount, license = githubInfo?.license?.spdxId ?: githubInfo?.license?.name - ?: stale?.license, + ?: staleLicense, totalDownloads = backendRepo.downloadCount, ) cacheManager.put(cacheKey, result, REPO_STATS)