From 346513c369364687c12578d486c7711dc021b7b4 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Fri, 20 Feb 2026 10:09:07 +0500 Subject: [PATCH 1/7] chore(android): Add `hasFragileUserData` to manifest This commit adds `android:hasFragileUserData="true"` to the `AndroidManifest.xml`. This ensures that when a user uninstalls the app, the system prompts them to confirm if they want to also remove the app's data. The change also includes `tools:targetApi="29"` to support this attribute. --- composeApp/src/androidMain/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index a8dd5c0d..560b02e1 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -19,6 +19,8 @@ android:networkSecurityConfig="@xml/network_security_config" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" + android:hasFragileUserData="true" + tools:targetApi="29" android:theme="@android:style/Theme.Material.Light.NoActionBar" android:usesCleartextTraffic="false"> From a69978df492978cb0a401729870c83c77e236b93 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Fri, 20 Feb 2026 20:36:08 +0500 Subject: [PATCH 2/7] feat(android): Handle shared URLs via Android Share Sheet This commit enables the application to receive and process shared URLs (for `github.com` and `github-store.org`) from other apps through the Android Share Sheet. When a user shares text containing a supported URL with the app, the app will now extract the URL and navigate to the corresponding repository details screen. - **feat(android)**: Added an `intent-filter` for `ACTION_SEND` in `AndroidManifest.xml` to accept `text/plain` and `text/html` content. - **feat(deeplink)**: Implemented `DeepLinkParser.extractSupportedUrl()` to find the first `github.com` or `github-store.org` URL within a given text string. - **refactor(android)**: Updated `MainActivity` to handle `ACTION_SEND` intents, extract the URL from the shared text, and trigger the deep link flow. - **fix(android)**: Corrected the `pathPattern` in the `AndroidManifest.xml` for `github.com` deep links to correctly match repository paths. --- .../baselineProfiles/0/composeApp-release.dm | Bin 17702 -> 18021 bytes .../baselineProfiles/1/composeApp-release.dm | Bin 17674 -> 17990 bytes .../src/androidMain/AndroidManifest.xml | 40 +++++++++++------- .../zed/rainxch/githubstore/MainActivity.kt | 25 ++++++++--- .../kotlin/zed/rainxch/githubstore/Main.kt | 3 +- .../app/deeplink/DeepLinkParser.kt | 5 +++ 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/composeApp/release/baselineProfiles/0/composeApp-release.dm b/composeApp/release/baselineProfiles/0/composeApp-release.dm index 07706a1ce2a757011dc6c365bb936ea428f2e6cf..5a9331cc31a4bb2fe2af177ef49eca294e9c76be 100644 GIT binary patch delta 15737 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 S_m(Xh`%;P$bzbT}cK#pI!rl4+ delta 15428 zcmYkDWmr_v*Y-gaB!^JC5fJGXm;vc-6_9R_l!gJ0Gzbh`lF}&M-O?~fGqiN)&;zgk z=Y5~&ea?05FX!6l!`XY?_c?2?-`b2qFZ_m%r=g7T^aa}U=g-k(P2%wAo-#`yI^(zn zp52R}p`FIrXkkyoxb9#?XlRvHJ=srzw3q|6cvTN#Mh?PiPmEV

dHJBMwxb6Mmiw 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 diff --git a/composeApp/release/baselineProfiles/1/composeApp-release.dm b/composeApp/release/baselineProfiles/1/composeApp-release.dm index 1ef032f7467792f12abcc4ad7c71c7c06f9bf61e..988904944fac4e42b8a4dcb086eafb56f8e795fe 100644 GIT binary patch delta 16864 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


oBrnyY<-l!xXeUsXgm*zG>O$=-SZW80d)G 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 diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index 560b02e1..2c6cc402 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -1,28 +1,30 @@ - + - - + android:usesCleartextTraffic="false" + tools:targetApi="29"> + + + + + + + - - + + + @@ -75,10 +82,11 @@ - + + + + + diff --git a/composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt b/composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt index 17334fc0..6624fe83 100644 --- a/composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.Preview import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.util.Consumer +import zed.rainxch.githubstore.app.deeplink.DeepLinkParser class MainActivity : ComponentActivity() { @@ -20,19 +21,16 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { installSplashScreen() - enableEdgeToEdge() super.onCreate(savedInstanceState) - deepLinkUri = intent?.data?.toString() + handleIncomingIntent(intent) setContent { DisposableEffect(Unit) { val listener = Consumer { newIntent -> - newIntent.data?.toString()?.let { - deepLinkUri = it - } + handleIncomingIntent(newIntent) } addOnNewIntentListener(listener) onDispose { @@ -43,6 +41,23 @@ class MainActivity : ComponentActivity() { App(deepLinkUri = deepLinkUri) } } + + private fun handleIncomingIntent(intent: Intent?) { + if (intent == null) return + + val uriString = when (intent.action) { + Intent.ACTION_VIEW -> intent.data?.toString() + + Intent.ACTION_SEND -> { + val sharedText = intent.getStringExtra(Intent.EXTRA_TEXT) + sharedText?.let { DeepLinkParser.extractSupportedUrl(it) } + } + + else -> null + } + + uriString?.let { deepLinkUri = it } + } } @Preview diff --git a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt index e114987c..686cef05 100644 --- a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt +++ b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt @@ -38,7 +38,8 @@ fun App(deepLinkUri: String? = null) { ) } - DeepLinkDestination.None -> { /* ignore unrecognized deep links */ + DeepLinkDestination.None -> { + /* ignore unrecognized deep links */ } } } diff --git a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt index 0a10a064..7096f29f 100644 --- a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt +++ b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt @@ -174,4 +174,9 @@ object DeepLinkParser { } return null } + + fun extractSupportedUrl(text: String): String? { + val regex = """https?://(?:www\.)?(?:github\.com|github-store\.org)[^\s<>"']+""".toRegex(RegexOption.IGNORE_CASE) + return regex.find(text)?.value + } } \ No newline at end of file From 22e97722d098ba9444484ff755e99ea47ecc633a Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 23 Feb 2026 16:30:18 +0500 Subject: [PATCH 3/7] refactor(details): Improve download and downgrade UX This commit enhances the user experience on the details screen by improving the download and version management logic. Downloads are now cached within a screen session. If a user dismisses an install prompt and retries the installation, the app will reuse the already-downloaded file instead of re-downloading it. The download progress indicator now displays the downloaded size (e.g., "14.2 MB / 25.0 MB") for better feedback. Temporary files from canceled or completed downloads are now reliably cleaned up when the user navigates away from the screen. The downgrade detection logic has also been made more robust. It now uses the release list order as the primary method to determine if a selected version is older, falling back to semantic version comparison only when necessary. This provides more accurate downgrade warnings. Finally, ProGuard/R8 is now enabled for release builds to optimize and shrink the application size. - **feat(download)**: Reuse an already-downloaded file if the user cancels the install prompt and then re-initiates it in the same session. - **feat(download)**: Display download progress with file sizes (e.g., "X MB / Y MB") instead of just a percentage. - **fix(download)**: Ensure partially downloaded and cached files are properly cleaned up when the user leaves the details screen. --- .../baselineProfiles/0/composeApp-release.dm | Bin 18021 -> 13355 bytes .../baselineProfiles/1/composeApp-release.dm | Bin 17990 -> 13284 bytes .../details/presentation/DetailsState.kt | 2 + .../details/presentation/DetailsViewModel.kt | 150 +++++++++++++----- .../components/SmartInstallButton.kt | 21 ++- 5 files changed, 135 insertions(+), 38 deletions(-) diff --git a/composeApp/release/baselineProfiles/0/composeApp-release.dm b/composeApp/release/baselineProfiles/0/composeApp-release.dm index 5a9331cc31a4bb2fe2af177ef49eca294e9c76be..fe88920b0b81d3b9b2505b373a172476c2d09d6a 100644 GIT binary patch literal 13355 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%0Dk8#z%efBDbtES*$AQ2XdnW#Es&2 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 JeajWZ0|4eHxWE7a diff --git a/composeApp/release/baselineProfiles/1/composeApp-release.dm b/composeApp/release/baselineProfiles/1/composeApp-release.dm index 988904944fac4e42b8a4dcb086eafb56f8e795fe..6fc1d2b746666c02c5a1544610b238544cf0fc76 100644 GIT binary patch literal 13284 zcmaib1yCGK*Dewu1WO=T@DL=yA-IK*K+r{k26uuxEQ`A??(PH&?(VL^WpP-7EW6mU zzGLwze~N z_TqGOcCbMI&QUSghZ_xpW*r?(ngb2Z6aCZ&FHP@jvfmXWU$)tZqJhY#5m)+8 zpP2fkXM!z|^BUzpli*BaOE;lLpP0Vks1*<==Y7bX77@U{sVhm z8uirfdPLJ!n|zh;(=WG^&CatTkIwrH!s73od9wQ_wM}q-wM)S|fL|R;W@=U-6zf_&_@0 z8`X^$TI{oR;RMA8T*12;!ePZF*8#uIY0Q?>1jok|UZcS3xS3cN(LLL+EC;#I_E0S9 zi+sf+S?ax{7~VVdT(^rIVS3NF6xSr8Rmz08Opqm#`y$_c>CFLXkKqOXJ?MDE9hS0Cr!tRUeCs@Gn2T#B@N?W8-?JL#4V=6H4J}Jtd0k zs;g@g*?S};8n>mgF#3yu1Bv0Uo#H+1rZl48KJ?lS%-u4;2T*M`w5{P8O1iF z=Y)o`XJ1)wvY3&$I(P#|BU~^TiJG-WSUkk9SWaB_ZU5Ydt2X9Slrr6U0W(Z?zG)nk z-i?5tpt26xs@D6nxY3c|5)SqnSd8@I=0A>O0F-c4#5;L5El1=o86gr>wZxM3uxKN> zyymIwa9yZDmEJ(2QSFh^D)lCRsr6CYSL#w7>yy45)wNS!zo&8T^W9gu!sn+dg5$Q9 z_7bx6_+H|Vwx+S(oJsL{EIDi!kKtkw<859BgnrMPNx*GOKUrwutXsU+qu^T$LNU;m zzkn3YG(lez(fn^^;S&75+rMZX0d%w;J^oZFSQK6=v6DewW_HGQ#{U}$0)En^apA=` zM*V+a!m;eO=YB7%L)CD?#Wm%Q>RaBv3;w0Bj?u8ZE^EZC>f!Z(tg=`Vj2bP1dr#47 z*jqq6K@phs6cjp5KZD(Q+wsf}Rh7o=2f4gM&-tOkdGsFhlb31b% zBWGmKlDU!NBcGw#D%eiz`9y5$f9zm%DiJEG`!PCIjBOZs?TJLo`4Q99Q40}X6-y4CR=53qJPo5TWFz6`GygspYd*FJ*pEjv0n+!Q4ce7!Zs7~G;e5eqh$M=o! zG#Q#Dbzl2!i$hNrl~35l%Vrg3!m&K_jc6N4hDXJqTtUp1c%C8@OXxNZ$0}Zh zh1&ex%x8z50BP}W(v)TJ=x0JL00x4+gjiuCD;$CyK4|KlTb6Vjt=%3T=<?A6AT7UUB7;Ei(lD#IO>e08rhb$m$F13Kb&d_07m`ETqOxNr zDn&%oEcIZ|u-VGO2_JI`iTEpB9y4C3NW6PpUB!d2Es1Zc7=F#ZsVb~9*;6;lLEE*8Rh7F~P@CGPR)^`h| zTScbnARQKQs4d?7yo4th%hR(4y{V*nVl)aASIVSH=6s25udTI=39<%soPX`84_V$b z9seJHzW)}u7_>?B@QrKw7&UZB`}0jOGBtki#%S=@^-2Dos4K43ZpH(Z!J zFSx)@_v|0-#k8Diw916xs(0&x*u{R=3Wpv%-Rsih+%yPIU2L%j!F~PyS-eXQe5t;4 zw4Qd;arL$`6d0Y%en}S_o5Fn2IQkQBh!Z)l4QXT0KE4u5_m=hJ@2dF6enpvWr;SQXgJ_IipKcW*Zt=HA#)8Jyc4! z`aLs&(RLT{)_^IcU9=Z-wE14lk&@mcb_{NX#*o93zaV0;O#=`+8dN)s;OMbpyolKO zDg;Z*>`)c3hS{sO(725qbXZc;XMH?y0N2Hwknh0-g%l~QCvVXx5WH?f+Ci3`t#auW zxjj+9dFDO3WXwg|z>eSSb86%ZC)@cn5BP8?8dqk!q{lsggeP5$1SW-ATJtE$sj2|K z9bj`I5y)Liy$7M$Om)mDh-oQNW)G4aeqj#%Bz!^DH-h6t3Lo8@6o3Y0!Gb{jpcz78 zVCn8%+pGK?dc2P21_ zxzNh~RFzOWV2Hot4DnQ!*f1mbatRivK*wwTwRhq=f_-ZjoG5I6L5?Kbp2$BDC3xdf z^^E5JGYFCWz=AJSI*#K!ljhhnmvCfRR!HNrX8_ue*=o8mnJL)STZt7f3MkUmB+Q z;B-rD<_^`nVoDnUVP-pNHcVp!Jlj2j$KjYQ5n2_tV|b~fr+`P&?F#{<^x&t71L!9UbJ?h8P4#jC`x2<;uuB-Jw*k%(edC%+@Q0P z5D710?*#`4PKnhzn4|iI(LDojF8qVsA^D2J(HrX?jDlXff71{YL^DznFq@e86+?&$ z^Vo8GB8x40&VX#JK#$_4h3IxkPEr81BMP6wfdZTN@rab&%p6Z9uq7L&{4xyuyO#+D#4R&`~j8$+YD zMl+?c3}=_-Vn!{ZJ}Gc-MVrUp))Y8dOsH(3R|RDisGn>y^5oYdLz*>{!?-;nXWCRB%|D_ScA-3V67pOGmi=sKL-%3WgLT%uGWYPIgRCnA5GxGV6;%#H ziC1UaB$`&QIQ`!JAH@CtJ^25|qLoAqP)yGzP{hlCGgmo3?wnJOc;1|wou`29X5w30 zik7^7xFMi`x1OPeoOO1g5>~iCPsb$-@my3R%97#xeR)IFvw+Dv!z{LTkTuz z`+uCqzanb4v8PcIyBZ;SkBzI2zr8(&oX7^VAqAl7Et#$`HRVjD#dExA(zPwFV|h6Wsw0K&K_SP=>g3Q_ z>eQ<~d{mz=_&ilr!d0q(FgWZg4;(;#@Zo^gI4_JY)S8=|vOgfmeF}g&7e;|a`{+}7 z(6|@M@vPBVBp*ZH-{li{TCvbvF-p!AObP7uls-a+DP%Sw3OUU; zn)iY$?0K?G4260M^(~&?6lI7{->@;+(8J<$D>lmoeq{l{A_f-fWBt#R^gx??FV>54 zSI5mA7uT1oZFEiO8`W?wBD^xJMum2#l&ycYMK8lvZ;ua^Fknhn3>pGD&Cc z$aK5qVm_ADXKO~!F>=Bs^5)3$#W6k8yl3WYY8wQ_&tG0BAbwMk0-P<-UNWj{6! zEAk`nmZIC{x)4B!ZpT!WV5f}Yn4i|>WgPrLQy8P$YmfuQl&9x3Hcs-p)9c@SIw`99 zb7rGrCn|5BWm65wQwZqb=Fo)@`MbFG3pGN2tF_P2o~dFg+#r+pfgEGC!Tm&u39Ebc z{ZZ(rU8J!uM_egSychJYK1dIT)G@~5;^*?{lmk*|m0s!5NDe748QBUM1h7Xdp#5PI zmv_4Iim+P+f27XskQl@VwmRR{|nBp7uL`b&L4+N9|!44X? z)E!Fqw5W+_;xrxLlnqfZz?eo>5A7YNOL#?Jh4}QsD^l?)gowCB0JRY{lU%=W!HCWx zNGDUVDf4ezw3{9t(yvi)s+6+AVn$%LxbSPU#UlohX@nQw0^@LggQJA=6hvh*ISwk& zG|(w*@SYByar!3--QHhX`#0e$=Y*q>t5lAWTDp0+FUiLk>6-Q|`ln)yw~Y4{f445Y zvQ@N*v~l7!e^>_?tIGeQz-9sk?3heu0}nO{?ZVOCggIsFF-t3-o}A24Yw{B%PO)p5 z#!~YxqGYS{M;RDIA&edEIo7=Whv6(;%BZ5t^GUUH!rl)&gjcJo&ZS110BpYS`k23JWF_lrAR zI7IV=|`IHPzkz`oy?rKX}tLLXpa^)}8eg@+wZ6R<0-tIz05G}6d^cx~I zOfbHD8>#m4B>Xk@OiLe4(w(66PyI{1Fa55Pp0PnB*+ztE-%T}gPOp^4gE_?*0>!RH z^z8LhDIY0cdqQuc6G38$v)2QoV!DWOAIIvgwj$|}0$#$HN-dT#N}$>qvnxAB%~(9Y zxbl5r%2amakj3{uF8*TLg`wLlfZ#QdD@PBH^#o}e@cX3d5=$FT>-Yjo9K}W+&26+? z$ulDeZpk%8Wh|>TE_&n8+y&aNyQ4&li(z)z4(WH?jLhQWNjBq&vlveRnYdj^$}1|4 z?4$l|P{Zx~F2A2VrGy7xPSCiCToo!kJ}-ll0bribqlHt|8OuE|RL@$;06cu=TPDRd zvjYa~%NZYtkj=gsX_R?Gdq%^01uTA_Cs!=cQ1iafw{@1{<4-!u8{|S$G8wn5aYQr_ zA%w}+lXaNfC>w}z5`V2csc}y+wp_ZifkiM}dQfn#h*`#=)PdFKoov*hw9%(3rGETC z1pDybsYdfItW0q5<^{z0VgA+g77@+aA0MCPLd=1Qu>n@S`hZM2fTgFW|BhMrG+b!` zL08mpNk)}J2z~5Lh0&rn^5s%jUV*aX)9Xy2Lh0y89m55E>mJ4ZyfzjoEB=@-A8KJ&D7LL`rAa^y`E2e0&32g6c{jN?+b?Efw!m(??CR zw2;*B{SUTBx)nQ}zwAP)wS0W!_|=hm8t7f z^=ateH0On-l%i@>3w7Ww)_&!?)~xFvb%2_#*MsY0F-zuj!dD#AZD%ZXF#gf%{grMZ z?+lSY-l=-!HNRSK=f36hWou^EjsHoNAZeE?3HA{792KoP8>0I2sNqaB(|m&r8Bcl* z9GLu^+R=Lo5q;}Sx{)+icA`KlqsZ})^O{#MN$(?3OF9PRUZ2SAQzQ>RBFT&jjZohw zANZ9&zxoxe?ki+R82vojU5_2$s^drw*H0+t1A0Tzp)AlE4QQQoP;nwiZzaS6*@gCV z4pSlICp+QNXLmL`zh?eKL5VgI&0*v|f->SeV~^OjD7G6T+mwv61}1W*MDnXgPlhgM z$Uw?3&qZ(j?zEG04NOrFJNF0UG|861P6@89xHpJUfJD;n^=r)7)x_m+cOUaVM&@Sl z?fnV*@*fl9g4onfJ;5Ko^(GTNB^Z!n{cI25{cjK@2n$S&Z$+7i1qv8#d2ySu6h}_*E3}$DJ%pBv_IIeGKbOhvr+s%M zhjOWfTaU`ZOJP(&bY9mO7Dke-aYkzv>cB&?K-{OLFGl!5cV>8Ul!1ovrah3eOe z2Y7aG?=PY=f;jkWdp6og70R01TzJa!51W+yx-?JMyT&Ic47-`p7q1^9ftnv{ff zk{xq4od$yHtJRvPT}_&Y$n>v5bygm=EsZra_0#_zJ$_rwsy8{)_Cr3_ORC*A2FKfq z`9uYp;w&u?*jaa9&$O->5jrUMFjM*+BOu!0=zqW0ahrb!j&!ali5(x{t(v4$p?O68 zpn(NU6?j%;k_&#Rm?oRA?I3Pui?$zKd*(s-{XFDqv29tRWxI$MBr`D4J!2{`8*-~%hEghD+hOQpIWb|bU}N*4wpixV2|g|DvM z@gv}v#GsIF{H{g*+@wrFl>O0+I#W88U>g8?&ilm=9?FbP+ z6c`5eXudx6gw0B&I|prS{G0_{l`q>SvrVW+IVh7lcs~Sf3B^6_s!w+~!Ni~1L^iLg zT-Fqp3=rMJWt)6{oy?CbtcS@YZOysIi=mxK9fLht~h?XCkWc_ORnM5*8f{63WtSC{K9>F<=tUtS;Idv zcxSp}%A=7Ka5^ggP4FgQ(ET=7$WZ51dR@4ubU1jEA99+8ii{Voj(R9Xk6?#Bo+&;5 zHSGN998*ByN?0(S^y($=m&Sys#(KWfS7r;Jz{7;}#R5r<5lK8Jrnm2(YrINV9LUn4 zv}o0CiW~j}Jl8+PJk9Csc+ir|ly_g7%W@DOMz+i0U>5tu{#UKLiziG)6_kfqW zqlRe!W8%A*?OeV)f7)>*Z#&u_!%Evd2>Jwc8m~6CoF&taGy!ENQu&%M@U`qWGQ12A zg|f-u%ak}+Gq0?^78nKGG+-};{0Pt33~g2CLBnMQA3&gGt;N@#$3*kx7;3^cru)}g z7CP*Qz@F;hv6a2LbyL`lJbByqUrHMZ*^%3d(~2S$XE9Y`ETR`VD+Sv$(0P{ihjU4w z2~gMPy~lJR-uKIEo6;P}b7_RzPL2DDk@sTXP?~PCQr`V(OhR+^m_hSH*mPE+IHOPb z7ox*foX7JF4>2)QJ1t^|FMXM!G*{PPmP9|sOq?7`8!{!IrsIv6iFY0Wmg&(W7cbfe zD_%Ggy#tu9N1GWPu5oRLM8E{iM)u#h{$A@9j~>A9Wou103F*qw!kn8@iF$#AS~SS1 zq*lytoL_BF{SJ=Kbosza9CFAzw)FzfFTgBoxd+ewfb->_R+Gz5`2jnr5_gFU{qq8L zS(gh#Q3p(QoAqPZ@2V#h#q`2k0=?lon%2tr-%78Fqy%L==C#*_kI-;o(kV^%; zxp^3v)qFmUvYtlfFnM`Q+j$?7*AcmXpY9BlEN(Yhb`hdtA}p^N1#yjt``GLHUBad^ zKQQ}P!9`!mOn6(;dinkGtf+kk#8EGEgsQ9WANI&+lG(7d>eL~`FIe?L0D5g21-Iw* z<;!<-OOLG~>H6vkKV`IbB2E1&P4vfF3pzGhhT01+51nU8p$U~4z>QS9@L?__qkfI5 zz2V@Dtb=;0i24}g@!IQd1|09P35BWfxcF0E=C9Wt`{tawF{&XcU+U=e9lXXKCg%9; zS@#T6zPHktZnToAZL4(f z%(U*)eDqhRoKM)}7 zJT3ZDkx$#_tES`=da=y_1Xq%rrW&6I{-(%AeD;rFszrALugM!)amaxsCl^Rr%VAYRlywvHmD@ErnTYHkY2AkQTy008kRfm2q-RPZZ1XXxPPdyt{J8By0KHRhju0*?g$w^8)W%5NqqYr>7aoh8Y zG$-}-?h{|qQx`SB-J58d`XZ0tv z>SX9iE>_(<)1}t5^q`it#8ax&dVf70AI4JcSlI3X&rwzlWo%(%^lr(Dxj%{qkYxm-uOKdKd3#ou#gfNwL?e7M{6BOsc<3U7YdNlCy zWetJItu(4X@=>9oJgDmg>k)r0{BMNl4Zpy#lFGJ6DfiQXw0fZg(q<2DU&nJqcbUe8 z**@kw0^T3gu9|$1_hKByd&f!sJZ`<+@*{M1urXq%Ialnr{ZaZu_lWPaFMxN87JT>K z@`megpWWE9R~e?Vx>k(u!AvW(8hTVi1jOZZ|8#yuMJf|i1Ik=6p2QT(KT5oGuZ!5J zhCj+}6?5r$e)$#my|eqIv+gLQs3pOJ`$aAw$qd7T`GtYd7}=*^dras$AIL`87d7rs z${)NYOI`MV=^Uw@j}}{g{^c^&PTkS}q1X&HUTTolHZXvfYzVTo5y?D*LdQ&aizHV~ z&cgy|C!YBMHp7Q6`baiYHDVF(#m1$v%PQYqHvqq$XpKwmi>c?zv^dK^Mm$M)Sd9Vk z7xuLwS7a;JLgGImt>o?&ecspF;&@#Ux;85CW%GK?C9oVO*U7{2h2sA z7vCIru+F#j-6EJ$`cL**7{5Bgx_)htJWNlY$60(ToKCHSPf5%m= zHQJ)~A#gZ}mUtf}?4~eN<+hm!a^m$D*e%4t>LZmc3rxCj}XI73pEjLh(tMCAL2nNPv=ooDL2FOTH*D_G0j+daX+@`?6hK&8e zFj%Q~m%R`(E|JA2bv351-yC@&v3bT}<|}pu%f8ttQwy^1FI`t=Ojf*0eoNR6Cl}px zmrWoTh`bZc$!U)KA|lfrrjacw$=()KGqpGUw9!RQ1=W&Ub>(RM>`Q;D zj8YG{??UnNH&8(Qfj(xO3%ojI=l=Y{kl)j9<2@yY0{i0 zbHr)Dmxcy$_o=t=aOLjJ&HD$wn{4=Bz!q$oR7y+)Zqy$NRhun~FPeTI*VQ`&QkR$4&61GJ(!QcDbGkD4rT(j=Dl_+_<}n8yV9{_KnDwM$HsB9kGM#E^V1R7;1x zf}>mA&(rqchos+_m~bv?zC^bB4#9jA$Z!)d?{O%}mMQFXgXnKQbCb*?4q>F}q)-al z*aJR+C0ddE268|@JAdIqS6q_tQjNW_{MCT2tW9ko0ZME<~a00Dpc0#Fp8YGzw}hejTqf;D1*qQ#MH9xTPI5~wA8UePZyHC zX(dov<@@D(uDF<;06phDyLmsd%vv4}@XPJVL2a!w6hL$ee?{yn`WYTC}c7hixB zdY8|BLC3s(Zm`+8b{FfLl>R1aVM?EZqa^xD^%IQ*h+5k_Z+3pAC81ODw7hC&yuXN4 zk{x(7>CdE_=rr9Q)*63jKP^*0*<%8j^5h%0iZl7W%n|RSt=yVCsRmaDcV>6b7G?J= ztu3`+Xr9gGs~uGuSP*#sUhZzLNz=ZUxM7pV$?0^up}pyG0laJT0C8%H-ylH=g`J0W zY~G2n@_yfpHa=8o4xFjn3qErK^pM61NeP@Hk}kG-_eIeznFL_@Hr3jfMPDH8hG{!) z72%G+MeCfCZ^s$wHAiO}t%YiM&d!C)S1KJ`zF@{1g;er0L(ea|1y`mt`=>IciUF6G zJj;v=(w@gEvY*~ek`O;?Q(%8zfDI-k3%XSt6TRgHraH_=9~lO#+~sJX8={B|%MGdG zzRK=Luco~wu%x_{*~~Q3A~3k#Iy^g~UT#%Y_PrUc?`u!gOOn=Y5I%i46vo*jXWMV_ zxSm@e%Bzi5zR7BoTz{$F=|j~exUcR2RleT5i}?c=5L)}Z$31PP=sAbqS;S({H8w+H zAGV9tP@C=JnfqGXf)JE4NzDs!X;~83-qnzyqsN1#@XqG8$B1kfrkhgwE5#Wyy=R#S z>!(8)iyVQEvk_}kFVP&sqo{?J{llzJ{zwIx?Lb~d>B!!Zn<$c8$AL*o_?@&RTF8G z^7Z9t)5&cJ>4ojrD&Jzr8K`wtldkk`k&SzA*CTnIDC&0rj6~=x;U_!LPiC3+m~`_1 ziRzP1t4gTfspQh^9m1PAOiS1qhgr1@o`h2AzKaX;2Vo|hP&JH~oCN)09lSP)kwUB9 zrBzp&dzoMp&V&6NE4VF(8bi3oYyQm6)kXF@7nj6bgik}(yys1l;MT92ZZECC0sDeiK-*2=Gl|7$VbXs3$ z#@3Wjv5Z7FFpR`|-1fzXouQ?d#EOG>sKdMK6`($U!tjhmYn4Fm1# z2Q)NStpA;qt*hWb{q^NpHf7E3GWM{tKgC=6;Fk==9K73=JOMLSUmJ7(3S`1=-&~&_5&_dmp<4sgbLjD4OGWJ~O4vgUT#^I|@D1ZgP?pN}Bs{5i_cTzJvm4x6006Pt&*iQCY4?*3h=QX z*xUX@<3c5~NTs6$1rJO`tRY?^IEyUfG=!=FiGRHj-?d+8oQ$o#FXFXj+^;0j+ z%aeafzIk-U6+yTeW*ruiAoB1L$;Dty-}l{>1U8?u^<7H0QL))P9s3u?5~-wZX`4~T z!>k5L&IaDuq+4G5(?e^G`fv*%+1t3=ZmMVZ^MZmt){HWx;%A9Qc$0ux&gI#j@yGBf zS(?I6wUG9AhnQ26EA{ehczWV^D3O=Vk?sf!7I1NY$EKFMz|tzYH}uvZ@|0Yo%b1Z0 z*Dy+`;Ge)D?2f~Zh#*q6QXe0ok?DLTb@k)edQrZeO8*d%hT3M>_|o zDiux^&z&pebQooI(QOM>s=31_$nsc~Xkq7yh>{knC?qUL&;b>NU?EEEJ!Qs8f8i2q zu-JH7r(PTs6Q)|N>HV+~4{ZFU@;s7^St+>j&!x757JK6rJYjYE;+3y=0s56shK-fh z6H<>$@ZB}X&kt+&LNQhBfWlK#PC|5t)nv6i@Qy)i3kIg8_gx+oG&-2Jr6hYTV>0dO z-K(B*o8{A$dLO((Ecp5_W%1A@duDFsuKT0%-edoAZ}w=$sl|J&1gEHAFK?R*G4Hyh zldxBodFH?yFC@coI^1!qV9y!CI291BcSC3ufkQz%^PC8zovwvuf{ujiP zP}9z`+KtTT=8;?KVQN#Q6Y7VG1BJSibN+DQ_j!&3(Lj`Um;2HeeUiP+~VY}`dcID4}zDU zZ#ahKWM56({)+kmGC6BN4R|CQCSmPF644-OvA@G{YsWkFi#*32g-KwD3W3SzkpyF^ zY%X0+z(c_(t5@qGXpt@$kn^=52du3FPZH)9(`Fur&mDDKLLo;s+^*iu`>^K51@UU4 zDw?GJ8@(*L{E!=RWd95B--vqVn=kh0YDp;!EbF^~M@}UFBNuXO(yaRlJu2yA&c9H6 zNDRF?>L2_K{imrYpkus7`;XF^e@FO#mDc=c`}abd|2p#DXZ;rg{D&p}!xsNO(oRJI T3;SQMG5&G4f37-w|GN8MQIyEc literal 17990 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 U+yHM@Hjp$E5S9Yz-L4=W04)rTKL7v# diff --git a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt index e5c7f9de..9837d49f 100644 --- a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt +++ b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsState.kt @@ -33,6 +33,8 @@ data class DetailsState( val isDownloading: Boolean = false, val downloadProgressPercent: Int? = null, + val downloadedBytes: Long = 0L, + val totalBytes: Long? = null, val isInstalling: Boolean = false, val downloadError: String? = null, val installError: String? = null, diff --git a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt index 00a269dd..189780fc 100644 --- a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt +++ b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt @@ -66,6 +66,9 @@ class DetailsViewModel( private var hasLoadedInitialData = false private var currentDownloadJob: Job? = null private var currentAssetName: String? = null + // Tracks the most recently downloaded file so it can be reused if the user + // dismisses the install dialog and re-clicks install on the same screen session. + private var cachedDownloadAssetName: String? = null private val _state = MutableStateFlow(DetailsState()) val state = _state @@ -314,23 +317,19 @@ class DetailsViewModel( val installedApp = _state.value.installedApp if (primary != null && release != null) { + // Downgrade detection: only warn when the user picks an OLDER version if (installedApp != null && !installedApp.isPendingInstall && - !installedApp.isUpdateAvailable && normalizeVersion(release.tagName) != normalizeVersion(installedApp.installedVersion) && platform == Platform.ANDROID ) { - val isConfirmedDowngrade = if ( - normalizeVersion(release.tagName) == normalizeVersion(installedApp.latestVersion) && - (installedApp.latestVersionCode ?: 0L) > 0 - ) { - installedApp.installedVersionCode > (installedApp.latestVersionCode - ?: 0L) - } else { - true - } + val isDowngrade = isDowngradeVersion( + candidate = release.tagName, + current = installedApp.installedVersion, + allReleases = _state.value.allReleases + ) - if (isConfirmedDowngrade) { + if (isDowngrade) { viewModelScope.launch { _events.send( DetailsEvent.ShowDowngradeWarning( @@ -369,21 +368,17 @@ class DetailsViewModel( val assetName = currentAssetName if (assetName != null) { - viewModelScope.launch { - try { - val deleted = downloader.cancelDownload(assetName) - logger.debug("Cancel download - file deleted: $deleted") - - appendLog( - assetName = assetName, - size = 0L, - tag = _state.value.selectedRelease?.tagName ?: "", - result = LogResult.Cancelled - ) - } catch (t: Throwable) { - logger.error("Failed to cancel download: ${t.message}") - } - } + // Keep the partially/fully downloaded file so the user can resume + // without re-downloading. It will be cleaned up in onCleared(). + cachedDownloadAssetName = assetName + val releaseTag = _state.value.selectedRelease?.tagName ?: "" + appendLog( + assetName = assetName, + size = _state.value.downloadedBytes, + tag = releaseTag, + result = LogResult.Cancelled + ) + logger.debug("Download cancelled – keeping file for potential reuse: $assetName") } currentAssetName = null @@ -723,16 +718,43 @@ class DetailsViewModel( extOrMime = assetName.substringAfterLast('.', "").lowercase() ) - _state.value = _state.value.copy(downloadStage = DownloadStage.DOWNLOADING) - downloader.download(downloadUrl, assetName).collect { p -> - _state.value = _state.value.copy(downloadProgressPercent = p.percent) - if (p.percent == 100) { - _state.value = _state.value.copy(downloadStage = DownloadStage.VERIFYING) + // Check if file was already downloaded (e.g. user dismissed install dialog) + val existingPath = downloader.getDownloadedFilePath(assetName) + val filePath: String + + if (existingPath != null && java.io.File(existingPath).exists()) { + logger.debug("Reusing already downloaded file: $assetName") + filePath = existingPath + _state.value = _state.value.copy( + downloadProgressPercent = 100, + downloadedBytes = sizeBytes, + totalBytes = sizeBytes, + downloadStage = DownloadStage.VERIFYING + ) + } else { + _state.value = _state.value.copy( + downloadStage = DownloadStage.DOWNLOADING, + downloadedBytes = 0L, + totalBytes = sizeBytes + ) + downloader.download(downloadUrl, assetName).collect { p -> + _state.value = _state.value.copy( + downloadProgressPercent = p.percent, + downloadedBytes = p.bytesDownloaded, + totalBytes = p.totalBytes ?: sizeBytes + ) + if (p.percent == 100) { + _state.value = + _state.value.copy(downloadStage = DownloadStage.VERIFYING) + } } - } - val filePath = downloader.getDownloadedFilePath(assetName) - ?: throw IllegalStateException("Downloaded file not found") + filePath = downloader.getDownloadedFilePath(assetName) + ?: throw IllegalStateException("Downloaded file not found") + + // Cache asset name so it persists for reuse until screen is left + cachedDownloadAssetName = assetName + } appendLog( assetName = assetName, @@ -983,9 +1005,19 @@ class DetailsViewModel( super.onCleared() currentDownloadJob?.cancel() - currentAssetName?.let { assetName -> + // When the screen is actually left (ViewModel destroyed), clean up any + // in-progress or cached download file so we don't accumulate stale files. + val assetsToClean = listOfNotNull(currentAssetName, cachedDownloadAssetName).distinct() + if (assetsToClean.isNotEmpty()) { viewModelScope.launch { - downloader.cancelDownload(assetName) + for (asset in assetsToClean) { + try { + downloader.cancelDownload(asset) + logger.debug("Cleaned up download on screen leave: $asset") + } catch (t: Throwable) { + logger.error("Failed to clean download on leave: ${t.message}") + } + } } } } @@ -994,6 +1026,52 @@ class DetailsViewModel( return version?.removePrefix("v")?.removePrefix("V")?.trim() ?: "" } + /** + * Returns true if [candidate] is strictly older than [current]. + * Uses list-index order as primary heuristic (releases are newest-first), + * and falls back to semantic version comparison when list lookup fails. + */ + private fun isDowngradeVersion( + candidate: String, + current: String, + allReleases: List + ): Boolean { + val normalizedCandidate = normalizeVersion(candidate) + val normalizedCurrent = normalizeVersion(current) + + if (normalizedCandidate == normalizedCurrent) return false + + val candidateIndex = allReleases.indexOfFirst { + normalizeVersion(it.tagName) == normalizedCandidate + } + val currentIndex = allReleases.indexOfFirst { + normalizeVersion(it.tagName) == normalizedCurrent + } + + // Both found in list → use list order (newer = lower index) + if (candidateIndex != -1 && currentIndex != -1) { + return candidateIndex > currentIndex + } + + // Fallback: semantic version comparison + return compareSemanticVersions(normalizedCandidate, normalizedCurrent) < 0 + } + + /** + * Compares two semantic version strings. Returns positive if a > b, negative if a < b, 0 if equal. + */ + private fun compareSemanticVersions(a: String, b: String): Int { + val aParts = a.split("[.\\-]".toRegex()) + val bParts = b.split("[.\\-]".toRegex()) + val maxLen = maxOf(aParts.size, bParts.size) + for (i in 0 until maxLen) { + val aPart = aParts.getOrNull(i)?.filter { it.isDigit() }?.toLongOrNull() ?: 0L + val bPart = bParts.getOrNull(i)?.filter { it.isDigit() }?.toLongOrNull() ?: 0L + if (aPart != bPart) return aPart.compareTo(bPart) + } + return 0 + } + private companion object { const val OBTAINIUM_REPO_ID: Long = 523534328 const val APP_MANAGER_REPO_ID: Long = 268006778 diff --git a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/components/SmartInstallButton.kt b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/components/SmartInstallButton.kt index b1fec6d4..d24603da 100644 --- a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/components/SmartInstallButton.kt +++ b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/components/SmartInstallButton.kt @@ -251,8 +251,13 @@ fun SmartInstallButton( fontWeight = FontWeight.Bold ) + val progressText = if (state.totalBytes != null && state.totalBytes > 0) { + "${formatFileSize(state.downloadedBytes)} / ${formatFileSize(state.totalBytes)}" + } else { + "${progress ?: 0}%" + } Text( - text = "${progress ?: 0}%", + text = progressText, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.8f) ) @@ -323,6 +328,9 @@ fun SmartInstallButton( if (primaryAsset != null) { val assetArch = extractArchitectureFromName(primaryAsset.name) val systemArch = state.systemArchitecture + val sizeText = formatFileSize(primaryAsset.size) + val archLabel = assetArch ?: systemArch.name.lowercase() + val subtitle = "$archLabel \u2022 $sizeText" Spacer(modifier = Modifier.height(2.dp)) @@ -331,7 +339,7 @@ fun SmartInstallButton( verticalAlignment = Alignment.CenterVertically ) { Text( - text = assetArch ?: systemArch.name.lowercase(), + text = subtitle, color = if (enabled) { when { isUpdateAvailable -> MaterialTheme.colorScheme.onTertiary.copy( @@ -449,6 +457,15 @@ private fun normalizeVersion(version: String): String { return version.removePrefix("v").removePrefix("V").trim() } +private fun formatFileSize(bytes: Long): String { + return when { + bytes >= 1_073_741_824 -> "%.1f GB".format(bytes / 1_073_741_824.0) + bytes >= 1_048_576 -> "%.1f MB".format(bytes / 1_048_576.0) + bytes >= 1_024 -> "%.1f KB".format(bytes / 1_024.0) + else -> "$bytes B" + } +} + @Preview @Composable fun SmartInstallButtonDownloadingPreview() { From 51ca90166d922c0b40d2901706873496214f671c Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 23 Feb 2026 16:30:32 +0500 Subject: [PATCH 4/7] - **refactor(details)**: Improved downgrade detection by primarily using the release list order, with semantic version comparison as a fallback. - **chore(build)**: Enabled ProGuard (`isMinifyEnabled`) and resource shrinking (`isShrinkResources`) for release builds. --- .../src/main/kotlin/AndroidApplicationConventionPlugin.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt index 530c214b..92ddd34f 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt @@ -30,7 +30,8 @@ class AndroidApplicationConventionPlugin : Plugin { } buildTypes { getByName("release") { - isMinifyEnabled = false + isMinifyEnabled = true + isShrinkResources = true } } From d5f79604bf347c0c9e148be1eb3571f88ee8aa89 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 23 Feb 2026 16:30:38 +0500 Subject: [PATCH 5/7] - **i18n**: Added and updated translations for various languages (bn, es, fr, hi, it, ja, kr, pl, ru, tr, zh-rCN) related to installation, versioning, and app status. --- .../composeResources/values-bn/strings-bn.xml | 24 +++++++++++ .../composeResources/values-es/strings-es.xml | 42 +++++++++++++++++++ .../composeResources/values-fr/strings-fr.xml | 42 +++++++++++++++++++ .../composeResources/values-hi/strings-hi.xml | 30 ++++++++++++- .../composeResources/values-it/strings-it.xml | 29 +++++++++++++ .../composeResources/values-ja/strings-ja.xml | 42 +++++++++++++++++++ .../composeResources/values-kr/strings-kr.xml | 24 +++++++++++ .../composeResources/values-pl/strings-pl.xml | 24 +++++++++++ .../composeResources/values-ru/strings-ru.xml | 24 +++++++++++ .../composeResources/values-tr/strings-tr.xml | 28 ++++++++++++- .../values-zh-rCN/strings-zh-rCN.xml | 42 +++++++++++++++++++ 11 files changed, 347 insertions(+), 4 deletions(-) diff --git a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml index 05965557..05cc0a5a 100644 --- a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml +++ b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml @@ -346,4 +346,28 @@ কোনো ভার্সন নির্বাচিত নয় ভার্সনসমূহ + + ইনস্টল মুলতুবি + + + আনইনস্টল + খুলুন + ডাউনগ্রেডের জন্য আনইনস্টল প্রয়োজন + সংস্করণ %1$s ইনস্টল করতে বর্তমান সংস্করণ (%2$s) প্রথমে আনইনস্টল করতে হবে। অ্যাপের ডেটা মুছে যাবে। + প্রথমে আনইনস্টল করুন + %1$s ইনস্টল করুন + %1$s খুলতে ব্যর্থ + %1$s আনইনস্টল করতে ব্যর্থ + + + সর্বশেষ + + + সর্বশেষ পরীক্ষা: %1$s + কখনো পরীক্ষা করা হয়নি + এইমাত্র + %1$d মিনিট আগে + %1$d ঘন্টা আগে + আপডেট পরীক্ষা করা হচ্ছে… + diff --git a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml index dec690f8..b8db96bf 100644 --- a/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml +++ b/core/presentation/src/commonMain/composeResources/values-es/strings-es.xml @@ -293,4 +293,46 @@ Ninguna versión seleccionada Versiones + + Abrir repositorio + Abrir en navegador + Cancelar descarga + Mostrar opciones de instalación + + + Sin descripción proporcionada. + Sin notas de versión. + + + No disponible + Actualizar app + Instalación pendiente + + + Abrir en Obtainium + Gestionar actualizaciones automáticamente + Inspeccionar con AppManager + Verificar permisos, rastreadores y seguridad + + + Desinstalar + Abrir + La degradación requiere desinstalar + Instalar la versión %1$s requiere desinstalar la versión actual (%2$s) primero. Los datos de la app se perderán. + Desinstalar primero + Instalar %1$s + Error al abrir %1$s + Error al desinstalar %1$s + + + Última + + + Última comprobación: %1$s + Nunca comprobado + justo ahora + hace %1$d min + hace %1$d h + Comprobando actualizaciones… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml index b36488e1..31df05ce 100644 --- a/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml +++ b/core/presentation/src/commonMain/composeResources/values-fr/strings-fr.xml @@ -293,4 +293,46 @@ Aucune version sélectionnée Versions + + Ouvrir le dépôt + Ouvrir dans le navigateur + Annuler le téléchargement + Afficher les options d\'installation + + + Aucune description fournie. + Aucune note de version. + + + Non disponible + Mettre à jour + Installation en attente + + + Ouvrir dans Obtainium + Gérer les mises à jour automatiquement + Inspecter avec AppManager + Vérifier les permissions, trackers et sécurité + + + Désinstaller + Ouvrir + La rétrogradation nécessite la désinstallation + L\'installation de la version %1$s nécessite la désinstallation de la version actuelle (%2$s). Les données de l\'application seront perdues. + Désinstaller d\'abord + Installer %1$s + Impossible d\'ouvrir %1$s + Impossible de désinstaller %1$s + + + Dernière + + + Dernière vérification : %1$s + Jamais vérifié + à l\'instant + il y a %1$d min + il y a %1$d h + Vérification des mises à jour… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml index f9eb660b..dfe2da02 100644 --- a/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml +++ b/core/presentation/src/commonMain/composeResources/values-hi/strings-hi.xml @@ -215,8 +215,6 @@ डाउनलोड की गई फ़ाइल नहीं मिली रुझान - नया - हाल ही में अपडेट किया गया रिपॉजिटरी ढूंढी जा रही हैं... और लोड हो रहा है... @@ -343,4 +341,32 @@ प्री-रिलीज़ कोई संस्करण चयनित नहीं संस्करण + + + हॉट रिलीज़ + सबसे लोकप्रिय + + + इंस्टॉल लंबित + + + अनइंस्टॉल + खोलें + डाउनग्रेड के लिए अनइंस्टॉल आवश्यक + संस्करण %1$s इंस्टॉल करने के लिए पहले वर्तमान संस्करण (%2$s) को अनइंस्टॉल करना होगा। ऐप डेटा खो जाएगा। + पहले अनइंस्टॉल करें + %1$s इंस्टॉल करें + %1$s खोलने में विफल + %1$s अनइंस्टॉल करने में विफल + + + नवीनतम + + + अंतिम जाँच: %1$s + कभी जाँच नहीं की + अभी + %1$d मिनट पहले + %1$d घंटे पहले + अपडेट की जाँच हो रही है… diff --git a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml index 61ecc718..b9aee12f 100644 --- a/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml +++ b/core/presentation/src/commonMain/composeResources/values-it/strings-it.xml @@ -342,4 +342,33 @@ Nessuna versione selezionata Versioni + + Installazione in sospeso + + + Disinstalla + Apri + Il downgrade richiede la disinstallazione + L\'installazione della versione %1$s richiede la disinstallazione della versione corrente (%2$s). I dati dell\'app verranno persi. + Disinstalla prima + Installa %1$s + Impossibile aprire %1$s + Impossibile disinstallare %1$s + + + Ultima + + + Chiaro + Scuro + Sistema + + + Ultimo controllo: %1$s + Mai controllato + proprio ora + %1$d min fa + %1$d h fa + Controllo aggiornamenti… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml index 1735bded..79d01447 100644 --- a/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml +++ b/core/presentation/src/commonMain/composeResources/values-ja/strings-ja.xml @@ -293,4 +293,46 @@ バージョン未選択 バージョン + + リポジトリを開く + ブラウザで開く + ダウンロードをキャンセル + インストールオプションを表示 + + + 説明はありません。 + リリースノートはありません。 + + + 利用不可 + アプリを更新 + インストール待ち + + + Obtainiumで開く + 自動的にアップデートを管理 + AppManagerで検査 + 権限、トラッカー、セキュリティを確認 + + + アンインストール + 開く + ダウングレードにはアンインストールが必要 + バージョン%1$sのインストールには、現在のバージョン(%2$s)のアンインストールが必要です。アプリデータは失われます。 + 先にアンインストール + %1$sをインストール + %1$sを開けませんでした + %1$sのアンインストールに失敗しました + + + 最新 + + + 最終確認: %1$s + 未確認 + たった今 + %1$d分前 + %1$d時間前 + アップデートを確認中… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml b/core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml index 8c724d84..27195656 100644 --- a/core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml +++ b/core/presentation/src/commonMain/composeResources/values-kr/strings-kr.xml @@ -344,4 +344,28 @@ 선택된 버전 없음 버전 + + 설치 대기 중 + + + 제거 + 열기 + 다운그레이드를 위해 제거가 필요합니다 + 버전 %1$s을(를) 설치하려면 현재 버전(%2$s)을 먼저 제거해야 합니다. 앱 데이터가 삭제됩니다. + 먼저 제거 + %1$s 설치 + %1$s 열기 실패 + %1$s 제거 실패 + + + 최신 + + + 마지막 확인: %1$s + 확인한 적 없음 + 방금 + %1$d분 전 + %1$d시간 전 + 업데이트 확인 중… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml index 292020c7..d9e9edab 100644 --- a/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml +++ b/core/presentation/src/commonMain/composeResources/values-pl/strings-pl.xml @@ -309,4 +309,28 @@ Nie wybrano wersji Wersje + + Oczekuje na instalację + + + Odinstaluj + Otwórz + Obniżenie wersji wymaga odinstalowania + Instalacja wersji %1$s wymaga odinstalowania bieżącej wersji (%2$s). Dane aplikacji zostaną utracone. + Najpierw odinstaluj + Zainstaluj %1$s + Nie udało się otworzyć %1$s + Nie udało się odinstalować %1$s + + + Najnowsza + + + Ostatnio sprawdzono: %1$s + Nigdy nie sprawdzano + właśnie teraz + %1$d min temu + %1$d godz. temu + Sprawdzanie aktualizacji… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml index 2a8c1a81..30c3991f 100644 --- a/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml +++ b/core/presentation/src/commonMain/composeResources/values-ru/strings-ru.xml @@ -311,4 +311,28 @@ Версия не выбрана Версии + + Ожидает установки + + + Удалить + Открыть + Для понижения версии требуется удаление + Для установки версии %1$s необходимо сначала удалить текущую версию (%2$s). Данные приложения будут потеряны. + Сначала удалить + Установить %1$s + Не удалось открыть %1$s + Не удалось удалить %1$s + + + Последняя + + + Последняя проверка: %1$s + Не проверялось + только что + %1$d мин назад + %1$d ч назад + Проверка обновлений… + \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml index a5853ef1..0b43b913 100644 --- a/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml +++ b/core/presentation/src/commonMain/composeResources/values-tr/strings-tr.xml @@ -232,9 +232,9 @@ Hız Sınırı Aşıldı Tüm %1$d API isteklerini kullandınız. - Tüm %1$s ücretsiz API isteğinizi kullandınız. + Tüm %1$d ücretsiz API isteğinizi kullandınız. %1$d dakika içinde yenilenir - Saat başı 60 yerine 5,000 istek için giriş yapın! + 💡 Saat başı 60 yerine 5.000 istek için giriş yapın! Giriş Yap Tamam Kapat @@ -343,4 +343,28 @@ Sürüm seçilmedi Sürümler + + Kurulum bekleniyor + + + Kaldır + + Sürüm düşürme kaldırma gerektirir + %1$s sürümünü yüklemek için önce mevcut sürümü (%2$s) kaldırmanız gerekir. Uygulama verileri kaybolacaktır. + Önce kaldır + %1$s yükle + %1$s açılamadı + %1$s kaldırılamadı + + + En son + + + Son kontrol: %1$s + Hiç kontrol edilmedi + az önce + %1$d dk önce + %1$d sa önce + Güncellemeler kontrol ediliyor… + diff --git a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml index dc9cf014..4fe5e750 100644 --- a/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml +++ b/core/presentation/src/commonMain/composeResources/values-zh-rCN/strings-zh-rCN.xml @@ -294,4 +294,46 @@ 未选择版本 版本 + + 打开仓库 + 在浏览器中打开 + 取消下载 + 显示安装选项 + + + 暂无描述。 + 暂无发行说明。 + + + 不可用 + 更新应用 + 等待安装 + + + 在 Obtainium 中打开 + 自动管理更新 + 使用 AppManager 检查 + 检查权限、追踪器和安全性 + + + 卸载 + 打开 + 降级需要先卸载 + 安装版本 %1$s 需要先卸载当前版本(%2$s)。应用数据将丢失。 + 先卸载 + 安装 %1$s + 无法打开 %1$s + 无法卸载 %1$s + + + 最新 + + + 上次检查:%1$s + 从未检查 + 刚刚 + %1$d 分钟前 + %1$d 小时前 + 正在检查更新… + \ No newline at end of file From b9b533514a6ff1f0a60e9c465553634bf33002d7 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 23 Feb 2026 18:06:59 +0500 Subject: [PATCH 6/7] refactor(details): Improve download cache logic and cleanup ViewModel This commit refactors the `DetailsViewModel` to enhance the download caching mechanism and remove obsolete code. The asset download logic is now more robust. It verifies not only the existence of a cached file but also confirms that its size matches the expected size from the asset metadata, preventing the use of incomplete or stale downloads. The ViewModel's code has also been streamlined by removing redundant comments and unused logic, particularly around download caching and downgrade warnings, improving overall readability and maintenance. - **feat(details)**: Added a file size check to the download cache logic, ensuring that a cached asset is only reused if its size matches the expected size. - **refactor(details)**: Removed obsolete comments and simplified code within the `DetailsViewModel`, including cleanup of the `onCleared` method. - **fix(deeplink)**: Improved the regex in `DeepLinkParser` to more accurately extract GitHub URLs from surrounding text by better handling trailing characters. - **chore(build)**: Overhauled and organized the ProGuard rules for release builds, ensuring proper shrinking and optimization for libraries like Ktor, Koin, Room, and Compose. - **fix(i18n)**: Corrected a minor typo in the Bengali (`bn`) translation for "hours ago". --- .../AndroidApplicationConventionPlugin.kt | 5 + composeApp/proguard-rules.pro | 273 +++++++++++------- .../app/deeplink/DeepLinkParser.kt | 2 +- .../composeResources/values-bn/strings-bn.xml | 2 +- .../details/presentation/DetailsViewModel.kt | 15 +- 5 files changed, 185 insertions(+), 112 deletions(-) diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt index 92ddd34f..66331a35 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt @@ -32,6 +32,11 @@ class AndroidApplicationConventionPlugin : Plugin { getByName("release") { isMinifyEnabled = true isShrinkResources = true + + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } diff --git a/composeApp/proguard-rules.pro b/composeApp/proguard-rules.pro index c4d47438..ed9a0fad 100644 --- a/composeApp/proguard-rules.pro +++ b/composeApp/proguard-rules.pro @@ -1,124 +1,201 @@ -# === CRITICAL: Keep Everything for Networking === --keeppackagenames io.ktor.** --keeppackagenames okhttp3.** --keeppackagenames okio.** - -# Kotlin --keep class kotlin.** { *; } --keep class kotlinx.** { *; } --keepclassmembers class kotlin.** { *; } - -# Coroutines --keep class kotlinx.coroutines.** { *; } +# ============================================================================ +# ProGuard / R8 Rules for GitHub Store (KMP + Compose Multiplatform) +# ============================================================================ +# Used with: proguard-android-optimize.txt (enables optimization passes) +# ============================================================================ + +# ── General Attributes ────────────────────────────────────────────────────── +-keepattributes Signature +-keepattributes *Annotation* +-keepattributes InnerClasses,EnclosingMethod +-keepattributes SourceFile,LineNumberTable +-keepattributes Exceptions + +# ── Kotlin Core ───────────────────────────────────────────────────────────── +# Keep Kotlin metadata for reflection used by serialization & Koin +-keep class kotlin.Metadata { *; } +-keep class kotlin.reflect.jvm.internal.** { *; } +-dontwarn kotlin.** +-dontwarn kotlinx.** + +# ── Kotlin Coroutines ────────────────────────────────────────────────────── -keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {} -keepnames class kotlinx.coroutines.CoroutineExceptionHandler {} -keepclassmembernames class kotlinx.** { volatile ; } +-dontwarn kotlinx.coroutines.** -# === Ktor - Keep EVERYTHING === --keep class io.ktor.** { *; } --keep interface io.ktor.** { *; } --keepclassmembers class io.ktor.** { *; } +# ── Kotlinx Serialization ────────────────────────────────────────────────── +# Serialization engine internals +-keep class kotlinx.serialization.** { *; } +-keepclassmembers class kotlinx.serialization.json.** { *** Companion; } +-dontnote kotlinx.serialization.** + +# Generated serializers for ALL @Serializable classes +-keep class **$$serializer { *; } +-keepclassmembers @kotlinx.serialization.Serializable class ** { + *** Companion; + *** INSTANCE; + kotlinx.serialization.KSerializer serializer(...); +} + +# App @Serializable classes (DTOs, models, navigation routes) across all packages +-keep @kotlinx.serialization.Serializable class zed.rainxch.** { *; } +-keep,includedescriptorclasses class zed.rainxch.**$$serializer { *; } +-keepclassmembers @kotlinx.serialization.Serializable class zed.rainxch.** { + *** Companion; +} + +# ── Navigation Routes ────────────────────────────────────────────────────── +# Type-safe navigation requires these classes to survive R8 +-keep class zed.rainxch.githubstore.app.navigation.GithubStoreGraph { *; } +-keep class zed.rainxch.githubstore.app.navigation.GithubStoreGraph$* { *; } + +# ── Network DTOs – Core Module ───────────────────────────────────────────── +-keep class zed.rainxch.core.data.dto.** { *; } + +# ── Network DTOs – Feature Modules ───────────────────────────────────────── +-keep class zed.rainxch.search.data.dto.** { *; } +-keep class zed.rainxch.devprofile.data.dto.** { *; } +-keep class zed.rainxch.home.data.dto.** { *; } + +# ── Domain Models ────────────────────────────────────────────────────────── +-keep class zed.rainxch.core.domain.model.GithubRepoSummary { *; } +-keep class zed.rainxch.core.domain.model.GithubUser { *; } + +# Keep enums used by Room TypeConverters and serialization +-keep class zed.rainxch.core.domain.model.InstallSource { *; } +-keep class zed.rainxch.core.domain.model.AppTheme { *; } +-keep class zed.rainxch.core.domain.model.FontTheme { *; } +-keep class zed.rainxch.core.domain.model.Platform { *; } +-keep class zed.rainxch.core.domain.model.SystemArchitecture { *; } +-keep class zed.rainxch.core.domain.model.PackageChangeType { *; } + +# ── Room Database ────────────────────────────────────────────────────────── +# Database class and generated implementation +-keep class zed.rainxch.core.data.local.db.AppDatabase { *; } +-keep class zed.rainxch.core.data.local.db.AppDatabase_Impl { *; } + +# Entities +-keep class zed.rainxch.core.data.local.db.entities.** { *; } + +# DAOs +-keep interface zed.rainxch.core.data.local.db.dao.** { *; } +-keep class zed.rainxch.core.data.local.db.dao.** { *; } + +# Room runtime +-keep class androidx.room.** { *; } +-dontwarn androidx.room.** + +# ── Ktor ─────────────────────────────────────────────────────────────────── +# Engine discovery, plugin system, and content negotiation use reflection +-keep class io.ktor.client.engine.** { *; } +-keep class io.ktor.client.plugins.** { *; } +-keep class io.ktor.serialization.** { *; } +-keep class io.ktor.utils.io.** { *; } +-keep class io.ktor.http.** { *; } -keepnames class io.ktor.** { *; } -dontwarn io.ktor.** - -# Ktor Debug -dontwarn java.lang.management.** -# === OkHttp - Keep EVERYTHING === --keep class okhttp3.** { *; } --keep interface okhttp3.** { *; } --keepclassmembers class okhttp3.** { *; } --keepnames class okhttp3.** { *; } +# ── OkHttp (Ktor engine) ────────────────────────────────────────────────── +-keep class okhttp3.internal.platform.** { *; } +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase -dontwarn okhttp3.** +-dontwarn org.bouncycastle.** +-dontwarn org.openjsse.** -# === Okio - Keep EVERYTHING === --keep class okio.** { *; } --keepclassmembers class okio.** { *; } --keepnames class okio.** { *; } +# ── Okio ─────────────────────────────────────────────────────────────────── -dontwarn okio.** -# === Network Stack - Keep EVERYTHING === --keep class java.net.** { *; } --keep class javax.net.** { *; } --keep class sun.security.ssl.** { *; } --keepclassmembers class java.net.** { *; } --keepclassmembers class javax.net.** { *; } - -# DNS Resolution --keep class java.net.InetAddress { *; } --keep class java.net.Inet4Address { *; } --keep class java.net.Inet6Address { *; } --keep class java.net.InetSocketAddress { *; } - -# SSL/TLS --keep class javax.net.ssl.** { *; } +# ── SSL/TLS ──────────────────────────────────────────────────────────────── -keep class org.conscrypt.** { *; } -dontwarn org.conscrypt.** -# === Kotlinx Serialization === --keepattributes *Annotation*, InnerClasses --dontnote kotlinx.serialization.** --keep,includedescriptorclasses class zed.rainxch.githubstore.**$$serializer { *; } --keep @kotlinx.serialization.Serializable class zed.rainxch.githubstore.** { *; } --keepclassmembers @kotlinx.serialization.Serializable class zed.rainxch.githubstore.** { - *** Companion; -} - -# Keep your models --keep class zed.rainxch.githubstore.core.domain.model.** { *; } +# ── Koin DI ──────────────────────────────────────────────────────────────── +# Koin uses reflection for constructor injection +-keep class org.koin.** { *; } +-keep interface org.koin.** { *; } +-dontwarn org.koin.** + +# Keep ViewModels so Koin can instantiate them +-keep class zed.rainxch.**.presentation.**ViewModel { *; } +-keep class zed.rainxch.**.presentation.**ViewModel$* { *; } + +# ── Compose / AndroidX ──────────────────────────────────────────────────── +# Compose runtime and navigation (most rules come bundled with the library) +-keep class androidx.compose.** { *; } +-dontwarn androidx.compose.** +-keep class androidx.navigation.** { *; } +-keep class androidx.lifecycle.** { *; } +-dontwarn androidx.lifecycle.** + +# ── DataStore ────────────────────────────────────────────────────────────── +-keep class androidx.datastore.** { *; } +-keepclassmembers class androidx.datastore.preferences.** { *; } +-dontwarn androidx.datastore.** + +# ── Landscapist / Coil3 (Image Loading) ──────────────────────────────────── +-keep class com.skydoves.landscapist.** { *; } +-keep interface com.skydoves.landscapist.** { *; } +-keep class coil3.** { *; } +-dontwarn coil3.** +-dontwarn com.skydoves.landscapist.** + +# ── Multiplatform Markdown Renderer ──────────────────────────────────────── +-keep class com.mikepenz.markdown.** { *; } +-keep class org.intellij.markdown.** { *; } +-dontwarn com.mikepenz.markdown.** +-dontwarn org.intellij.markdown.** + +# ── Kermit Logging ───────────────────────────────────────────────────────── +-keep class co.touchlab.kermit.** { *; } +-dontwarn co.touchlab.kermit.** + +# ── MOKO Permissions ────────────────────────────────────────────────────── +-keep class dev.icerock.moko.permissions.** { *; } +-dontwarn dev.icerock.moko.** + +# ── BuildKonfig (Generated Build Constants) ──────────────────────────────── +-keep class zed.rainxch.githubstore.BuildConfig { *; } +-keep class zed.rainxch.**.BuildKonfig { *; } +-keep class **.BuildKonfig { *; } -# === AndroidX Security === +# ── AndroidX Security / Crypto ───────────────────────────────────────────── -keep class androidx.security.crypto.** { *; } -keep class com.google.crypto.tink.** { *; } -dontwarn com.google.crypto.tink.** -dontwarn com.google.errorprone.annotations.** -# BuildConfig --keep class zed.rainxch.githubstore.BuildConfig { *; } - -# General --keepattributes Signature --keepattributes Exceptions --keepattributes *Annotation* --keepattributes SourceFile,LineNumberTable - -# === START: Auth Fix === --dontoptimize --keepattributes *Annotation*,Signature,Exception,InnerClasses,EnclosingMethod +# ── Firebase (if integrated) ────────────────────────────────────────────── +-keep class com.google.firebase.** { *; } +-dontwarn com.google.firebase.** -# Keep serialization infrastructure --keep class kotlinx.serialization.** { *; } --keep class **$$serializer { *; } --keepclassmembers @kotlinx.serialization.Serializable class ** { - *** Companion; - *** INSTANCE; - kotlinx.serialization.KSerializer serializer(...); +# ── Enum safety ──────────────────────────────────────────────────────────── +# Keep all enum values and valueOf methods (used by serialization/Room) +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); } -# Keep Ktor plugins --keep class io.ktor.client.plugins.** { *; } --keep class io.ktor.serialization.** { *; } - -# Keep your entire core package (narrow this down later) --keep class zed.rainxch.githubstore.core.** { *; } --keepclassmembers class zed.rainxch.githubstore.core.** { *; } -# === END: Auth Fix === - --keep class zed.rainxch.githubstore.core.data.remote.dto.** { *; } --keep class zed.rainxch.githubstore.core.domain.model.auth.** { *; } - -# If your models are in different packages, list them: --keep class zed.rainxch.githubstore.**.*DeviceStart* { *; } --keep class zed.rainxch.githubstore.**.*DeviceToken* { *; } --keep class zed.rainxch.githubstore.**.*AuthConfig* { *; } - -# Keep the companion objects explicitly --keepclassmembers class zed.rainxch.githubstore.**.DeviceStart { - public static ** Companion; +# ── Parcelable ───────────────────────────────────────────────────────────── +-keepclassmembers class * implements android.os.Parcelable { + public static final ** CREATOR; } --keepclassmembers class zed.rainxch.githubstore.**.DeviceTokenSuccess { - public static ** Companion; + +# ── ServiceLoader (used by Ktor, Koin, etc.) ────────────────────────────── +-keepnames class * implements java.io.Serializable +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); } --keepclassmembers class zed.rainxch.githubstore.**.DeviceTokenError { - public static ** Companion; -} \ No newline at end of file + +# ── Suppress Warnings for Missing Classes ────────────────────────────────── +-dontwarn java.lang.invoke.StringConcatFactory +-dontwarn javax.annotation.** +-dontwarn org.slf4j.** +-dontwarn org.codehaus.mojo.animal_sniffer.** diff --git a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt index 7096f29f..54b83ea6 100644 --- a/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt +++ b/composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/deeplink/DeepLinkParser.kt @@ -176,7 +176,7 @@ object DeepLinkParser { } fun extractSupportedUrl(text: String): String? { - val regex = """https?://(?:www\.)?(?:github\.com|github-store\.org)[^\s<>"']+""".toRegex(RegexOption.IGNORE_CASE) + val regex = """https?://(?:www\.)?(?:github\.com|github-store\.org)(?=[/\s?#]|$)[^\s<>"')\],;.!]*""".toRegex(RegexOption.IGNORE_CASE) return regex.find(text)?.value } } \ No newline at end of file diff --git a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml index 05cc0a5a..ae77c890 100644 --- a/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml +++ b/core/presentation/src/commonMain/composeResources/values-bn/strings-bn.xml @@ -367,7 +367,7 @@ কখনো পরীক্ষা করা হয়নি এইমাত্র %1$d মিনিট আগে - %1$d ঘন্টা আগে + %1$d ঘণ্টা আগে আপডেট পরীক্ষা করা হচ্ছে… diff --git a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt index 189780fc..d0259911 100644 --- a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt +++ b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt @@ -66,8 +66,7 @@ class DetailsViewModel( private var hasLoadedInitialData = false private var currentDownloadJob: Job? = null private var currentAssetName: String? = null - // Tracks the most recently downloaded file so it can be reused if the user - // dismisses the install dialog and re-clicks install on the same screen session. + private var cachedDownloadAssetName: String? = null private val _state = MutableStateFlow(DetailsState()) @@ -317,7 +316,6 @@ class DetailsViewModel( val installedApp = _state.value.installedApp if (primary != null && release != null) { - // Downgrade detection: only warn when the user picks an OLDER version if (installedApp != null && !installedApp.isPendingInstall && normalizeVersion(release.tagName) != normalizeVersion(installedApp.installedVersion) && @@ -368,8 +366,6 @@ class DetailsViewModel( val assetName = currentAssetName if (assetName != null) { - // Keep the partially/fully downloaded file so the user can resume - // without re-downloading. It will be cleaned up in onCleared(). cachedDownloadAssetName = assetName val releaseTag = _state.value.selectedRelease?.tagName ?: "" appendLog( @@ -718,11 +714,11 @@ class DetailsViewModel( extOrMime = assetName.substringAfterLast('.', "").lowercase() ) - // Check if file was already downloaded (e.g. user dismissed install dialog) val existingPath = downloader.getDownloadedFilePath(assetName) val filePath: String - if (existingPath != null && java.io.File(existingPath).exists()) { + val existingFile = existingPath?.let { java.io.File(it) } + if (existingFile != null && existingFile.exists() && existingFile.length() == sizeBytes) { logger.debug("Reusing already downloaded file: $assetName") filePath = existingPath _state.value = _state.value.copy( @@ -752,7 +748,6 @@ class DetailsViewModel( filePath = downloader.getDownloadedFilePath(assetName) ?: throw IllegalStateException("Downloaded file not found") - // Cache asset name so it persists for reuse until screen is left cachedDownloadAssetName = assetName } @@ -1005,8 +1000,6 @@ class DetailsViewModel( super.onCleared() currentDownloadJob?.cancel() - // When the screen is actually left (ViewModel destroyed), clean up any - // in-progress or cached download file so we don't accumulate stale files. val assetsToClean = listOfNotNull(currentAssetName, cachedDownloadAssetName).distinct() if (assetsToClean.isNotEmpty()) { viewModelScope.launch { @@ -1048,12 +1041,10 @@ class DetailsViewModel( normalizeVersion(it.tagName) == normalizedCurrent } - // Both found in list → use list order (newer = lower index) if (candidateIndex != -1 && currentIndex != -1) { return candidateIndex > currentIndex } - // Fallback: semantic version comparison return compareSemanticVersions(normalizedCandidate, normalizedCurrent) < 0 } From fd02ce91ce5a59dd8f51cd433beae58c46077233 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 23 Feb 2026 18:14:45 +0500 Subject: [PATCH 7/7] refactor(details): Improve version comparison and download logging This commit introduces a more robust semantic version comparison algorithm and corrects the download size logging for cancelled downloads. The version comparison logic now properly handles pre-release identifiers (e.g., `-alpha`, `-beta`), ensuring that stable releases are correctly prioritized over pre-releases. Additionally, when a download is cancelled, the log now correctly records the total expected size of the asset rather than the partially downloaded bytes. - **refactor(versioning)**: Updated `compareSemanticVersions` to correctly handle pre-release suffixes. - **fix(logging)**: Corrected `appendLog` to use the asset's total size instead of downloaded bytes when a download is cancelled. - **chore(proguard)**: Removed redundant `-keep` rules for AndroidX Compose and Navigation, as these are now bundled with the respective libraries. --- composeApp/proguard-rules.pro | 5 +---- .../details/presentation/DetailsViewModel.kt | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/composeApp/proguard-rules.pro b/composeApp/proguard-rules.pro index ed9a0fad..d41796cf 100644 --- a/composeApp/proguard-rules.pro +++ b/composeApp/proguard-rules.pro @@ -123,10 +123,7 @@ # ── Compose / AndroidX ──────────────────────────────────────────────────── # Compose runtime and navigation (most rules come bundled with the library) --keep class androidx.compose.** { *; } -dontwarn androidx.compose.** --keep class androidx.navigation.** { *; } --keep class androidx.lifecycle.** { *; } -dontwarn androidx.lifecycle.** # ── DataStore ────────────────────────────────────────────────────────────── @@ -182,7 +179,7 @@ public static final ** CREATOR; } -# ── ServiceLoader (used by Ktor, Koin, etc.) ────────────────────────────── +# ── Java Serializable Compatibility ─────────────────────────────────────── -keepnames class * implements java.io.Serializable -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; diff --git a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt index d0259911..7028d87b 100644 --- a/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt +++ b/feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt @@ -368,10 +368,11 @@ class DetailsViewModel( if (assetName != null) { cachedDownloadAssetName = assetName val releaseTag = _state.value.selectedRelease?.tagName ?: "" + val totalSize = _state.value.totalBytes ?: _state.value.downloadedBytes appendLog( assetName = assetName, - size = _state.value.downloadedBytes, tag = releaseTag, + size = totalSize, result = LogResult.Cancelled ) logger.debug("Download cancelled – keeping file for potential reuse: $assetName") @@ -1052,14 +1053,22 @@ class DetailsViewModel( * Compares two semantic version strings. Returns positive if a > b, negative if a < b, 0 if equal. */ private fun compareSemanticVersions(a: String, b: String): Int { - val aParts = a.split("[.\\-]".toRegex()) - val bParts = b.split("[.\\-]".toRegex()) + val aCore = a.split("-", limit = 2) + val bCore = b.split("-", limit = 2) + val aParts = aCore[0].split(".") + val bParts = bCore[0].split(".") + val maxLen = maxOf(aParts.size, bParts.size) for (i in 0 until maxLen) { val aPart = aParts.getOrNull(i)?.filter { it.isDigit() }?.toLongOrNull() ?: 0L val bPart = bParts.getOrNull(i)?.filter { it.isDigit() }?.toLongOrNull() ?: 0L if (aPart != bPart) return aPart.compareTo(bPart) } + + val aHasPre = aCore.size > 1 + val bHasPre = bCore.size > 1 + if (aHasPre != bHasPre) return if (aHasPre) -1 else 1 + return 0 }