Skip to content

Conversation

@thomasttvo
Copy link
Collaborator

@thomasttvo thomasttvo commented Oct 16, 2025

  • Removed persistence logic from UploadProgress. Workers live and die with the application instance so we don't need persistence
  • Added logic to close the okhttp response asap before passing the content of the response along
  • Notifications now get updated using notificationManager.notify instead of setForeground
  • UploadProgress.clearIfNeeded no longer fetches worker statuses

Note

Switch to in-memory progress with updated notification handling, return UploadResponse from uploads, refactor EventReporter, and bump example minSdk to 29.

  • Android uploader:
    • Progress tracking:
      • Replace SharedPreferences-based persistence with in-memory UploadProgress (add/set/complete/remove/total) and auto-clear when all complete.
    • Networking:
      • okhttpUpload now returns UploadResponse (code/body/headers) and closes the Response early; maps headers via toMultimap.
      • EventReporter.success updated to consume UploadResponse; EventReporter refactored to an object.
    • Notifications:
      • Update notification via NotificationManager.notify and new buildNotification(); getForegroundInfo() builds from it.
    • Model changes:
      • Upload.notificationId is now Int (hash of provided string).
    • Cleanup:
      • Remove progress persistence/WorkManager status checks; drop init clearing in UploaderModule.
  • Example app:
    • Raise minSdkVersion to 29.

Written by Cursor Bugbot for commit e3c135c. Configure here.

@thomasttvo thomasttvo marked this pull request as ready for review October 16, 2025 23:16
val result = response.use { // close the response asap
UploadResponse(
response.code,
response.body?.string().takeIf { !it.isNullOrBlank() } ?: response.message,

Choose a reason for hiding this comment

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

looks like you're shadowing it here. you should either name the response you have opened via use, or name this string you are conditionally taking:

Suggested change
response.body?.string().takeIf { !it.isNullOrBlank() } ?: response.message,
response.body?.string()?.takeIf { str -> str.isNotEmpty() } ?: response.message,

override fun onResponse(call: Call, response: Response) =
continuation.resumeWith(Result.success(response))
override fun onResponse(call: Call, response: Response) {
val result = response.use { // close the response asap

Choose a reason for hiding this comment

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

This will technically work, but best practices would recommend naming the response you have opened:

val result = response.use { res ->
          UploadResponse(
            res.code,
           ...

.sumOf { storage.getLong(it, 0L) }
@Synchronized
fun set(uploadId: String, bytesUploaded: Long) {
map[uploadId]?.bytesUploaded = bytesUploaded

Choose a reason for hiding this comment

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

This only sets if map[uploadId] exists, which is not conventional in a set function. I would rename this to something like setIfNotNull

return (totalBytesUploaded.toDouble() * 100 / totalFileSize)
@Synchronized
fun complete(uploadId: String) {
map[uploadId]?.let {

Choose a reason for hiding this comment

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

nit you could add this as a complete() function in Progress and get some encapsulation:

Suggested change
map[uploadId]?.let {
map[uploadId]?.complete()

storage.edit().clear().apply()
}
@Synchronized
private fun clearIfNeeded() {

Choose a reason for hiding this comment

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

nit i would call this clearIfCompleted()

Comment on lines -26 to -28
// workers may be killed abruptly for whatever reasons,
// so they might not have had a chance to clear the progress data.
UploadProgress.clearIfNeeded(context)

Choose a reason for hiding this comment

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

Has no effect because the progress lives and dies with the application

private fun handleProgress(bytesSentTotal: Long, fileSize: Long) {
UploadProgress.set(upload.id, bytesSentTotal)
EventReporter.progress(upload.id, bytesSentTotal, fileSize)
setForeground(getForegroundInfo())

Choose a reason for hiding this comment

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

Pairing note: We only need to call setForeground once, no need to call it all the time like this

Copy link

@elliottkember elliottkember left a comment

Choose a reason for hiding this comment

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

LGTM

@elliottkember
Copy link

bugbot run

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no bugs!


Comment @cursor review or bugbot run to trigger another review on this PR

Copy link

@dhruv-dangi-openspace dhruv-dangi-openspace left a comment

Choose a reason for hiding this comment

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

LGTM

thomasvo and others added 3 commits December 11, 2025 16:42
- Name response variable in use block (UploadUtils.kt)
- Fix shadowed it in takeIf lambda (UploadUtils.kt)
- Rename set() to setIfNotNull() (UploadProgress.kt)
- Add complete() method to Progress class (UploadProgress.kt)
- Rename clearIfNeeded() to clearIfCompleted() (UploadProgress.kt)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@thomasttvo thomasttvo merged commit c97c345 into master Dec 12, 2025
2 checks passed
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.

5 participants