feat: Various misc QoL enchancements#3398
Conversation
|
Maybe just say "Decoding resources (Xs)" instead of "Still". However this entire PR has a contract issue. The patcher is what emits the arbitrary log strings. There is no contracted guarantee those strings will change. You cant "assume" a specific string Similarly replaceLineAtIndex isnt guaranteed, since the patcher might emit more or less strings shifting the index. |
Replacing the last line (heartbeat-tick case) avoids splitting the whole message into a list and rejoining it
|
What's left here? it's best to make sure this doesn't remain in this PR for too long otherwise it's going to stale out like its siblings |
Only thing that was left was any future ideas of what to add next, but I 100% agree. Readyyyyy |
PalmDevs
left a comment
There was a problem hiding this comment.
Needs some small changes.
Will string changes be reflected to Crowdin? @validcube
| <string name="patches_force_download">Force download all patches</string> | ||
| <string name="patches_reset">Reset patches</string> | ||
| <string name="downloaders_reset">Reset downloaders</string> | ||
| <string name="downloaded_apps_clear">Clear downloaded APK cache</string> |
There was a problem hiding this comment.
Not sure if this is necessarily always an APK. In the future, I think we may support other formats, so it's best to do
Clear download cache or Clear downloaded apps cache.
Thoughts @oSumAtrIX?
There was a problem hiding this comment.
Well, regardless, if thats the case for the future, maybe Clear downloaded assets cache
| } No newline at end of file | ||
| } | ||
|
|
||
| private val boldRegex = Regex("</?b>") |
There was a problem hiding this comment.
Is this how other apps do it? Is there a dependency that does this for us?
There was a problem hiding this comment.
I'm not really sure how other apps do it I'll be honest
I personally like the regex method because its the cleanest, instead of a bunch of text splits and find index etc..
For changes applied to default language strings (english), yes. For changes applied to other languages they will be reverted to original state. |
|
I have asked this before but still have not understood how you are certain about where to inject "[INFO] Decoded resources in 31s" in the logs. What if the patcher adds or removes certain logs? How do you know when decoding starts and ends? This part of the process is not in the hands of manager, and probably even a concern of patcher if at all.
Patches should never raise an exception back to caller. Can you provide a stack trace or location where an exception is unhandled?
The formatting is not user friendly. Instead it should say: Info: or co. Perhaps the raw log string can also be styled, but a "lazy" string works too for the while. |
We never read the patcher's logs to time this. The timer is just a coroutine ticking every second, totally separate from whatever the patcher prints: val heartbeat = Heartbeat(this) { elapsed ->
emitLog("Decoding resources", "${elapsed}s")
}The patcher could even not print anything and it would still keep ticking
The start time will be the moment patcher { (patch, exception) ->
heartbeat.complete { elapsed ->
val message = "Decoded resources in ${elapsed}s"
logger.info(message)
emitLog(message)
}
// ...And we cant call if (!finished.compareAndSet(false, true)) returnSo later patches dont run this again
Yes and that stays true since we arent changing any behaviour of the patcher, just using its steps to get a rough estimate of the ETA
And it doesnt, the exception gets passed as a regular string variable on the result callback, nothing is unhandled patcher { (patch, exception) ->
local val patch: Patch
local val exception: PatchException?The only place an exception actually flies is at the very end of that callback, where we re-throw it on purpose to abort the run if (exception != null) {
// ...
phaseLogger.error("${patch.name} failed:")
phaseLogger.error(exception.stackTraceToString())
throw exception
} // ...The soft-skip is only preventing the re-throw when the exception looks like a missing fingerprint, and we add a Ideally, re-throwing would never happen and for each failed patch its treated as a soft-skip / skippable task |
What was added
Live updates for patcher screen
Implemented live updates for: Decoding resources
Decoding resources [space] Xs)every second, replacing in placeDecoded resources in Xsreplaces the live tick[INFO] Applying patches[INFO] Decoded resources in 31s[INFO] Writing patched files...Implemented live updates for: Downloading APK file
Download APK file [spacer] [size] - Xs)every second, replacing in placeDownloaded APK file in Xs [spacer] [size]replaces the live tick[INFO] Applying patches[INFO] Decoded resources in 31s[INFO] Writing patched files...CI: Skip automatic builds for drafts
As the title implies, it just prevents GitHub Actions to build on PR drafts, everything else it unchanged (i.e. keeps building on commits)
Clear downloaded APK cache
Just a button under
Settings=>Developer optionsto clear the cache of downloaded APKsImage preview
Fix network memory leak
The flow for donwloads is:
Every read operation allocates a small byte container, everything writes correctly, but the containers are never freed from memory after use, causing them to persist and accumulate
To fix this, we wrap each chunk inside a
.use { }blocks for automatic resource management:Instead of wrapping the main logic in an
if (success)check, it now throws early if it failsIt keeps the exact same behavior but saves us a level of indentation and its better practice
Fixes #3392
Dedicated dialogs for patcher kills and native crashes
ProcessRuntimethrows a genericExceptionfor any non-zero exit code from the patcher subprocess, leaving users with the generic "Process exited with nonzero exit code X"A good example is on #3060 which on low-RAM devices is almost always Android's LowMemoryKiller, not a real bug
Added signal exit codes to two typed exceptions routed to dedicated
InstallerStatusDialogkinds:PatcherKilledExceptionfor when the system terminates the processPatcherCrashedExceptionfor when the process crashed nativelyAnd
InstallerModelnow has aretry()so the dialog button can a clean install attempt can be tried from the installer screenSoft-skip failed patches - WIP!
When a patch fails, the entire process dies, this addition makes it so keeps patching, skipping the failed patch
Image preview
Fix step icons not aligned
Image preview
Removed useless prefix
The prefix
[INFO]is useless and shouldn't be there, removed only for the INFO levelStyling and refactor
`strings.xml` has style tags like `` but it doesn't work, now it does!
Now these components animate: