also looking at this
fix(mobile): preserve native editing, navigation, and durable media requests
#369
36 files
+864
-185
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -1482,9 +1482,9 @@ describe('Craft Android builder', () => { | ||
| 1482 | 1482 | const shell = readFileSync(join(output, 'app/src/main/java/dev/craft/media/CraftNativeShell.kt'), 'utf8') |
| 1483 | 1483 | const gradle = readFileSync(join(output, 'app/build.gradle.kts'), 'utf8') |
| 1484 | 1484 | expect(gradle).toContain('androidx.work:work-runtime-ktx') |
| 1485 | // A job per address and connection rule, joined rather than started twice, run when its network is there. | |
| 1485 | // Serialize each address's requests under its connection rule; cached successors do not fetch again. | |
| 1486 | 1486 | expect(shell).toContain('internal class CraftNativeMediaWorker(') |
| 1487 | expect(shell).toContain('work.enqueueUniqueWork(workName(address, wifiOnly), androidx.work.ExistingWorkPolicy.KEEP, request)') | |
| 1487 | expect(shell).toContain('work.enqueueUniqueWork(workName(address, wifiOnly), androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE, request)') | |
| 1488 | 1488 | expect(shell).toContain('if (wifiOnly) androidx.work.NetworkType.UNMETERED else androidx.work.NetworkType.CONNECTED') |
| 1489 | 1489 | // Resumed from the part file an earlier attempt left. |
| 1490 | 1490 | expect(shell).toContain('connection.setRequestProperty("Range", "bytes=$have-")') |
| @@ -1272,8 +1272,10 @@ internal object CraftNativeMedia { | ||
| 1272 | 1272 | .addTag(TAG) |
| 1273 | 1273 | .addTag("$TAG:${digest(address)}") |
| 1274 | 1274 | .build() |
| 1275 | // KEEP: a transfer already queued or running for this address is joined, not started again. | |
| 1276 | work.enqueueUniqueWork(workName(address, wifiOnly), androidx.work.ExistingWorkPolicy.KEEP, request) | |
| 1275 | // Serialize requests, including one arriving after a terminal answer but | |
| 1276 | // before WorkManager marks that attempt complete. Each successor checks | |
| 1277 | // the cache before fetching, so concurrent callers still share one copy. | |
| 1278 | work.enqueueUniqueWork(workName(address, wifiOnly), androidx.work.ExistingWorkPolicy.APPEND_OR_REPLACE, request) | |
| 1277 | 1279 | val reason = when { |
| 1278 | 1280 | !online(app) -> "offline" |
| 1279 | 1281 | wifiOnly && metered(app) -> "cellular" |
| @@ -1370,7 +1372,7 @@ internal object CraftNativeMedia { | ||
| 1370 | 1372 | capabilities?.hasCapability(android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET) == true |
| 1371 | 1373 | }.getOrDefault(true) |
| 1372 | 1374 | |
| 1373 | /** Removes every copy whose address is not in `keep`, and stops their transfers; answers how many files went. */ | |
| 1375 | /** Removes idle copies outside `keep` and cancels their jobs; pending keeps retain ownership. */ | |
| 1374 | 1376 | fun prune(context: Context, keep: List<String>): Int { |
| 1375 | 1377 | val wanted = keep.map { digest(it) }.toSet() |
| 1376 | 1378 | var removed = 0 |
| @@ -1389,8 +1391,16 @@ internal object CraftNativeMedia { | ||
| 1389 | 1391 | runCatching { |
| 1390 | 1392 | androidx.work.WorkManager.getInstance(app).getWorkInfosByTag(TAG).get() |
| 1391 | 1393 | .filter { !it.state.isFinished } |
| 1392 | .filter { info -> info.tags.none { it.startsWith("$TAG:") && it.removePrefix("$TAG:") in wanted } } | |
| 1393 | .forEach { androidx.work.WorkManager.getInstance(app).cancelWorkById(it.id) } | |
| 1394 | .forEach { info -> | |
| 1395 | synchronized(lock) { | |
| 1396 | // The query runs asynchronously: a new keep may now | |
| 1397 | // own an address that was idle when prune was called. | |
| 1398 | val active = waiting.keys.map { digest(it) }.toSet() | |
| 1399 | if (info.tags.none { it.startsWith("$TAG:") && it.removePrefix("$TAG:") in wanted + active }) { | |
| 1400 | androidx.work.WorkManager.getInstance(app).cancelWorkById(info.id) | |
| 1401 | } | |
| 1402 | } | |
| 1403 | } | |
| 1394 | 1404 | } |
| 1395 | 1405 | } |
| 1396 | 1406 | return removed |