mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-05-15 05:10:28 +02:00
fix: sync download progress notification states
This commit is contained in:
@@ -35,6 +35,7 @@ class DownloadService : Service() {
|
||||
const val EXTRA_PROGRESS = "progress"
|
||||
const val EXTRA_TOTAL = "total"
|
||||
const val EXTRA_QUEUE_COUNT = "queue_count"
|
||||
const val EXTRA_STATUS = "status"
|
||||
|
||||
private var isRunning = false
|
||||
|
||||
@@ -61,7 +62,7 @@ class DownloadService : Service() {
|
||||
context.startService(intent)
|
||||
}
|
||||
|
||||
fun updateProgress(context: Context, trackName: String, artistName: String, progress: Long, total: Long, queueCount: Int) {
|
||||
fun updateProgress(context: Context, trackName: String, artistName: String, progress: Long, total: Long, queueCount: Int, status: String = "downloading") {
|
||||
val intent = Intent(context, DownloadService::class.java).apply {
|
||||
action = ACTION_UPDATE_PROGRESS
|
||||
putExtra(EXTRA_TRACK_NAME, trackName)
|
||||
@@ -69,6 +70,7 @@ class DownloadService : Service() {
|
||||
putExtra(EXTRA_PROGRESS, progress)
|
||||
putExtra(EXTRA_TOTAL, total)
|
||||
putExtra(EXTRA_QUEUE_COUNT, queueCount)
|
||||
putExtra(EXTRA_STATUS, status)
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
@@ -77,6 +79,7 @@ class DownloadService : Service() {
|
||||
private var wakeLock: PowerManager.WakeLock? = null
|
||||
private var currentTrackName = ""
|
||||
private var currentArtistName = ""
|
||||
private var currentStatus = "preparing"
|
||||
private var queueCount = 0
|
||||
|
||||
override fun onCreate() {
|
||||
@@ -89,6 +92,7 @@ class DownloadService : Service() {
|
||||
ACTION_START -> {
|
||||
currentTrackName = intent.getStringExtra(EXTRA_TRACK_NAME) ?: ""
|
||||
currentArtistName = intent.getStringExtra(EXTRA_ARTIST_NAME) ?: ""
|
||||
currentStatus = "preparing"
|
||||
queueCount = intent.getIntExtra(EXTRA_QUEUE_COUNT, 0)
|
||||
startForegroundService()
|
||||
}
|
||||
@@ -100,6 +104,7 @@ class DownloadService : Service() {
|
||||
currentArtistName = intent.getStringExtra(EXTRA_ARTIST_NAME) ?: currentArtistName
|
||||
val progress = intent.getLongExtra(EXTRA_PROGRESS, 0)
|
||||
val total = intent.getLongExtra(EXTRA_TOTAL, 0)
|
||||
currentStatus = intent.getStringExtra(EXTRA_STATUS) ?: currentStatus
|
||||
queueCount = intent.getIntExtra(EXTRA_QUEUE_COUNT, queueCount)
|
||||
updateNotification(progress, total)
|
||||
}
|
||||
@@ -186,7 +191,11 @@ class DownloadService : Service() {
|
||||
"Downloading..."
|
||||
}
|
||||
|
||||
val text = if (currentArtistName.isNotEmpty() && queueCount <= 1) {
|
||||
val text = if (currentStatus == "finalizing") {
|
||||
if (currentArtistName.isNotEmpty()) currentArtistName else "Embedding metadata..."
|
||||
} else if (currentStatus == "preparing" && total <= 0) {
|
||||
"Preparing download..."
|
||||
} else if (currentArtistName.isNotEmpty() && queueCount <= 1) {
|
||||
currentArtistName
|
||||
} else if (total > 0) {
|
||||
val progressPercent = (progress * 100 / total).toInt()
|
||||
@@ -194,7 +203,7 @@ class DownloadService : Service() {
|
||||
val totalMB = total / (1024.0 * 1024.0)
|
||||
String.format("%.1f / %.1f MB (%d%%)", progressMB, totalMB, progressPercent)
|
||||
} else {
|
||||
"Preparing download..."
|
||||
"Downloading..."
|
||||
}
|
||||
|
||||
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
@@ -207,10 +216,12 @@ class DownloadService : Service() {
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setCategory(NotificationCompat.CATEGORY_PROGRESS)
|
||||
|
||||
if (total > 0) {
|
||||
if (currentStatus == "preparing" && total <= 0) {
|
||||
builder.setProgress(0, 0, true)
|
||||
} else if (total > 0) {
|
||||
builder.setProgress(100, (progress * 100 / total).toInt(), false)
|
||||
} else {
|
||||
builder.setProgress(0, 0, true)
|
||||
builder.setProgress(0, 0, false)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
|
||||
@@ -2876,10 +2876,11 @@ class MainActivity: FlutterFragmentActivity() {
|
||||
"updateDownloadServiceProgress" -> {
|
||||
val trackName = call.argument<String>("track_name") ?: ""
|
||||
val artistName = call.argument<String>("artist_name") ?: ""
|
||||
val progress = call.argument<Long>("progress") ?: 0L
|
||||
val total = call.argument<Long>("total") ?: 0L
|
||||
val queueCount = call.argument<Int>("queue_count") ?: 0
|
||||
DownloadService.updateProgress(this@MainActivity, trackName, artistName, progress, total, queueCount)
|
||||
val progress = (call.argument<Number>("progress") ?: 0).toLong()
|
||||
val total = (call.argument<Number>("total") ?: 0).toLong()
|
||||
val queueCount = (call.argument<Number>("queue_count") ?: 0).toInt()
|
||||
val status = call.argument<String>("status") ?: "downloading"
|
||||
DownloadService.updateProgress(this@MainActivity, trackName, artistName, progress, total, queueCount, status)
|
||||
result.success(null)
|
||||
}
|
||||
"isDownloadServiceRunning" -> {
|
||||
|
||||
@@ -273,6 +273,10 @@ func SetItemBytesReceived(itemID string, received int64) {
|
||||
if item.BytesTotal > 0 {
|
||||
item.Progress = float64(received) / float64(item.BytesTotal)
|
||||
}
|
||||
if received > 0 {
|
||||
item.IsDownloading = true
|
||||
item.Status = itemProgressStatusDownloading
|
||||
}
|
||||
markMultiProgressDirtyIfChangedLocked(item, before)
|
||||
}
|
||||
}
|
||||
@@ -288,6 +292,10 @@ func SetItemBytesReceivedWithSpeed(itemID string, received int64, speedMBps floa
|
||||
if item.BytesTotal > 0 {
|
||||
item.Progress = float64(received) / float64(item.BytesTotal)
|
||||
}
|
||||
if received > 0 {
|
||||
item.IsDownloading = true
|
||||
item.Status = itemProgressStatusDownloading
|
||||
}
|
||||
markMultiProgressDirtyIfChangedLocked(item, before)
|
||||
}
|
||||
}
|
||||
@@ -318,6 +326,10 @@ func SetItemProgress(itemID string, progress float64, bytesReceived, bytesTotal
|
||||
if bytesTotal > 0 {
|
||||
item.BytesTotal = bytesTotal
|
||||
}
|
||||
if progress > 0 || bytesReceived > 0 || bytesTotal > 0 {
|
||||
item.IsDownloading = true
|
||||
item.Status = itemProgressStatusDownloading
|
||||
}
|
||||
markMultiProgressDirtyIfChangedLocked(item, before)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ func TestItemProgressPreparingAndDownloadingStatuses(t *testing.T) {
|
||||
SetItemProgress(itemID, 0.37, 0, 0)
|
||||
if item := multiProgress.Items[itemID]; item == nil {
|
||||
t.Fatal("expected item progress entry to exist after update")
|
||||
} else if item.Status != itemProgressStatusPreparing {
|
||||
t.Fatalf("status after progress update = %q, want %q", item.Status, itemProgressStatusPreparing)
|
||||
} else if item.Status != itemProgressStatusDownloading {
|
||||
t.Fatalf("status after progress update = %q, want %q", item.Status, itemProgressStatusDownloading)
|
||||
}
|
||||
|
||||
SetItemDownloading(itemID)
|
||||
|
||||
@@ -5818,9 +5818,27 @@ abstract class AppLocalizations {
|
||||
/// Notification body for queue complete - how many tracks were downloaded
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count} tracks downloaded successfully'**
|
||||
/// **'{count, plural, =1{1 track downloaded successfully} other{{count} tracks downloaded successfully}}'**
|
||||
String notifTracksDownloadedSuccess(int count);
|
||||
|
||||
/// Notification body when queue finishes with failures
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{completed, plural, =1{1 track downloaded} other{{completed} tracks downloaded}}, {failed, plural, =1{1 failed} other{{failed} failed}}'**
|
||||
String notifDownloadsFinishedBody(int completed, int failed);
|
||||
|
||||
/// Notification title when downloads are canceled by the user
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Downloads canceled'**
|
||||
String get notifDownloadsCanceledTitle;
|
||||
|
||||
/// Notification body when downloads are canceled by the user
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{count, plural, =1{1 download canceled by user} other{{count} downloads canceled by user}}'**
|
||||
String notifDownloadsCanceledBody(int count);
|
||||
|
||||
/// Notification title while scanning local library
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -3448,6 +3448,37 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3410,7 +3410,44 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String notifTracksDownloadedSuccess(int count) {
|
||||
return '$count tracks downloaded successfully';
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count tracks downloaded successfully',
|
||||
one: '1 track downloaded successfully',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3413,6 +3413,37 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3417,6 +3417,37 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3414,6 +3414,37 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3412,15 +3412,28 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String notifDownloadsFinished(int completed, int failed) {
|
||||
return 'Downloads Finished ($completed done, $failed failed)';
|
||||
return 'Unduhan Selesai ($completed selesai, $failed gagal)';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifAllDownloadsComplete => 'All Downloads Complete';
|
||||
String get notifAllDownloadsComplete => 'Semua Unduhan Selesai';
|
||||
|
||||
@override
|
||||
String notifTracksDownloadedSuccess(int count) {
|
||||
return '$count tracks downloaded successfully';
|
||||
return '$count lagu berhasil diunduh';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
return '$completed lagu diunduh, $failed gagal';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Unduhan dibatalkan';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
return '$count unduhan dibatalkan oleh pengguna';
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3401,6 +3401,37 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3394,6 +3394,37 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3414,6 +3414,37 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3413,6 +3413,37 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3473,6 +3473,37 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3440,6 +3440,37 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
@@ -3473,6 +3473,37 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
return '$count треки успішно завантажено';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Сканування локальної бібліотеки';
|
||||
|
||||
|
||||
@@ -3413,6 +3413,37 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
return '$count tracks downloaded successfully';
|
||||
}
|
||||
|
||||
@override
|
||||
String notifDownloadsFinishedBody(int completed, int failed) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
completed,
|
||||
locale: localeName,
|
||||
other: '$completed tracks downloaded',
|
||||
one: '1 track downloaded',
|
||||
);
|
||||
String _temp1 = intl.Intl.pluralLogic(
|
||||
failed,
|
||||
locale: localeName,
|
||||
other: '$failed failed',
|
||||
one: '1 failed',
|
||||
);
|
||||
return '$_temp0, $_temp1';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifDownloadsCanceledTitle => 'Downloads canceled';
|
||||
|
||||
@override
|
||||
String notifDownloadsCanceledBody(int count) {
|
||||
String _temp0 = intl.Intl.pluralLogic(
|
||||
count,
|
||||
locale: localeName,
|
||||
other: '$count downloads canceled by user',
|
||||
one: '1 download canceled by user',
|
||||
);
|
||||
return '$_temp0';
|
||||
}
|
||||
|
||||
@override
|
||||
String get notifScanningLibrary => 'Scanning local library';
|
||||
|
||||
|
||||
+26
-1
@@ -4465,7 +4465,7 @@
|
||||
"@notifAllDownloadsComplete": {
|
||||
"description": "Notification title when all downloads finish successfully"
|
||||
},
|
||||
"notifTracksDownloadedSuccess": "{count} tracks downloaded successfully",
|
||||
"notifTracksDownloadedSuccess": "{count, plural, =1{1 track downloaded successfully} other{{count} tracks downloaded successfully}}",
|
||||
"@notifTracksDownloadedSuccess": {
|
||||
"description": "Notification body for queue complete - how many tracks were downloaded",
|
||||
"placeholders": {
|
||||
@@ -4474,6 +4474,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifDownloadsFinishedBody": "{completed, plural, =1{1 track downloaded} other{{completed} tracks downloaded}}, {failed, plural, =1{1 failed} other{{failed} failed}}",
|
||||
"@notifDownloadsFinishedBody": {
|
||||
"description": "Notification body when queue finishes with failures",
|
||||
"placeholders": {
|
||||
"completed": {
|
||||
"type": "int"
|
||||
},
|
||||
"failed": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifDownloadsCanceledTitle": "Downloads canceled",
|
||||
"@notifDownloadsCanceledTitle": {
|
||||
"description": "Notification title when downloads are canceled by the user"
|
||||
},
|
||||
"notifDownloadsCanceledBody": "{count, plural, =1{1 download canceled by user} other{{count} downloads canceled by user}}",
|
||||
"@notifDownloadsCanceledBody": {
|
||||
"description": "Notification body when downloads are canceled by the user",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifScanningLibrary": "Scanning local library",
|
||||
"@notifScanningLibrary": {
|
||||
"description": "Notification title while scanning local library"
|
||||
|
||||
+28
-3
@@ -4366,7 +4366,7 @@
|
||||
"@notifDownloadComplete": {
|
||||
"description": "Notification title when a single download is complete"
|
||||
},
|
||||
"notifDownloadsFinished": "Downloads Finished ({completed} done, {failed} failed)",
|
||||
"notifDownloadsFinished": "Unduhan Selesai ({completed} selesai, {failed} gagal)",
|
||||
"@notifDownloadsFinished": {
|
||||
"description": "Notification title when queue finishes with some failures",
|
||||
"placeholders": {
|
||||
@@ -4378,11 +4378,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifAllDownloadsComplete": "All Downloads Complete",
|
||||
"notifAllDownloadsComplete": "Semua Unduhan Selesai",
|
||||
"@notifAllDownloadsComplete": {
|
||||
"description": "Notification title when all downloads finish successfully"
|
||||
},
|
||||
"notifTracksDownloadedSuccess": "{count} tracks downloaded successfully",
|
||||
"notifTracksDownloadedSuccess": "{count} lagu berhasil diunduh",
|
||||
"@notifTracksDownloadedSuccess": {
|
||||
"description": "Notification body for queue complete - how many tracks were downloaded",
|
||||
"placeholders": {
|
||||
@@ -4391,6 +4391,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifDownloadsFinishedBody": "{completed} lagu diunduh, {failed} gagal",
|
||||
"@notifDownloadsFinishedBody": {
|
||||
"description": "Notification body when queue finishes with failures",
|
||||
"placeholders": {
|
||||
"completed": {
|
||||
"type": "int"
|
||||
},
|
||||
"failed": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifDownloadsCanceledTitle": "Unduhan dibatalkan",
|
||||
"@notifDownloadsCanceledTitle": {
|
||||
"description": "Notification title when downloads are canceled by the user"
|
||||
},
|
||||
"notifDownloadsCanceledBody": "{count} unduhan dibatalkan oleh pengguna",
|
||||
"@notifDownloadsCanceledBody": {
|
||||
"description": "Notification body when downloads are canceled by the user",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifScanningLibrary": "Scanning local library",
|
||||
"@notifScanningLibrary": {
|
||||
"description": "Notification title while scanning local library"
|
||||
|
||||
@@ -1354,6 +1354,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
bool _networkPausedByWifiOnly = false;
|
||||
String? _lastServiceTrackName;
|
||||
String? _lastServiceArtistName;
|
||||
String? _lastServiceStatus;
|
||||
int _lastServicePercent = -1;
|
||||
int _lastServiceQueueCount = -1;
|
||||
DateTime _lastServiceUpdateAt = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
@@ -1672,6 +1673,9 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
int queuedCount = 0;
|
||||
int downloadingCount = 0;
|
||||
DownloadItem? firstDownloading;
|
||||
bool hasFinalizingItem = false;
|
||||
String? finalizingTrackName;
|
||||
String? finalizingArtistName;
|
||||
for (int i = 0; i < currentItems.length; i++) {
|
||||
final item = currentItems[i];
|
||||
if (item.status == DownloadStatus.downloading) {
|
||||
@@ -1679,16 +1683,18 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
firstDownloading ??= item;
|
||||
}
|
||||
if (item.status == DownloadStatus.queued ||
|
||||
item.status == DownloadStatus.downloading) {
|
||||
item.status == DownloadStatus.downloading ||
|
||||
item.status == DownloadStatus.finalizing) {
|
||||
queuedCount++;
|
||||
}
|
||||
if (item.status == DownloadStatus.finalizing && !hasFinalizingItem) {
|
||||
hasFinalizingItem = true;
|
||||
finalizingTrackName = item.track.name;
|
||||
finalizingArtistName = item.track.artistName;
|
||||
}
|
||||
}
|
||||
final progressUpdates = <String, _ProgressUpdate>{};
|
||||
|
||||
bool hasFinalizingItem = false;
|
||||
String? finalizingTrackName;
|
||||
String? finalizingArtistName;
|
||||
|
||||
for (final entry in items.entries) {
|
||||
final itemId = entry.key;
|
||||
final localItem = lookup.byItemId[itemId];
|
||||
@@ -1707,6 +1713,13 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
localItem.status == DownloadStatus.failed) {
|
||||
continue;
|
||||
}
|
||||
if (localItem.status == DownloadStatus.finalizing) {
|
||||
PlatformBridge.clearItemProgress(itemId).catchError((_) {});
|
||||
hasFinalizingItem = true;
|
||||
finalizingTrackName = localItem.track.name;
|
||||
finalizingArtistName = localItem.track.artistName;
|
||||
continue;
|
||||
}
|
||||
final rawItemProgress = entry.value;
|
||||
if (rawItemProgress is! Map) {
|
||||
continue;
|
||||
@@ -1718,6 +1731,10 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
final speedMBps = (itemProgress['speed_mbps'] as num?)?.toDouble() ?? 0.0;
|
||||
final isDownloading = itemProgress['is_downloading'] as bool? ?? false;
|
||||
final status = itemProgress['status'] as String? ?? 'downloading';
|
||||
final progressFromBackend =
|
||||
(itemProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
final hasRealProgress =
|
||||
bytesReceived > 0 || bytesTotal > 0 || progressFromBackend > 0;
|
||||
|
||||
if (status == 'finalizing') {
|
||||
progressUpdates[itemId] = const _ProgressUpdate(
|
||||
@@ -1730,7 +1747,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (status == 'preparing') {
|
||||
if (status == 'preparing' && !hasRealProgress) {
|
||||
progressUpdates[itemId] = const _ProgressUpdate(
|
||||
status: DownloadStatus.downloading,
|
||||
progress: 0.0,
|
||||
@@ -1745,10 +1762,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
continue;
|
||||
}
|
||||
|
||||
final progressFromBackend =
|
||||
(itemProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
|
||||
if (isDownloading) {
|
||||
if (isDownloading || hasRealProgress) {
|
||||
double percentage = 0.0;
|
||||
if (bytesTotal > 0) {
|
||||
percentage = bytesReceived / bytesTotal;
|
||||
@@ -1798,6 +1812,10 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
continue;
|
||||
}
|
||||
final update = entry.value;
|
||||
if (current.status == DownloadStatus.finalizing &&
|
||||
update.status != DownloadStatus.finalizing) {
|
||||
continue;
|
||||
}
|
||||
final next = current.copyWith(
|
||||
status: update.status,
|
||||
progress: update.progress,
|
||||
@@ -1833,7 +1851,16 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
|
||||
if (hasFinalizingItem && finalizingTrackName != null) {
|
||||
final safeArtistName = finalizingArtistName ?? '';
|
||||
if (finalizingTrackName != _lastFinalizingTrackName ||
|
||||
if (Platform.isAndroid) {
|
||||
_maybeUpdateAndroidDownloadService(
|
||||
trackName: finalizingTrackName,
|
||||
artistName: _notificationService.embeddingMetadataLabel,
|
||||
progress: 100,
|
||||
total: 100,
|
||||
queueCount: queuedCount,
|
||||
status: 'finalizing',
|
||||
);
|
||||
} else if (finalizingTrackName != _lastFinalizingTrackName ||
|
||||
safeArtistName != _lastFinalizingArtistName) {
|
||||
_notificationService.showDownloadFinalizing(
|
||||
trackName: finalizingTrackName,
|
||||
@@ -1848,18 +1875,18 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
_lastFinalizingArtistName = null;
|
||||
|
||||
if (items.isNotEmpty) {
|
||||
final firstEntry = items.entries.first;
|
||||
final rawFirstProgress = firstEntry.value;
|
||||
if (rawFirstProgress is! Map) {
|
||||
return;
|
||||
}
|
||||
final firstProgress = Map<String, dynamic>.from(rawFirstProgress);
|
||||
final bytesReceived =
|
||||
(firstProgress['bytes_received'] as num?)?.toInt() ?? 0;
|
||||
final bytesTotal = (firstProgress['bytes_total'] as num?)?.toInt() ?? 0;
|
||||
final backendStatus = firstProgress['status'] as String? ?? 'downloading';
|
||||
|
||||
if (downloadingCount > 0 && firstDownloading != null) {
|
||||
final rawProgress = items[firstDownloading.id];
|
||||
if (rawProgress is! Map) {
|
||||
return;
|
||||
}
|
||||
final selectedProgress = Map<String, dynamic>.from(rawProgress);
|
||||
final bytesReceived =
|
||||
(selectedProgress['bytes_received'] as num?)?.toInt() ?? 0;
|
||||
final bytesTotal =
|
||||
(selectedProgress['bytes_total'] as num?)?.toInt() ?? 0;
|
||||
final backendStatus =
|
||||
selectedProgress['status'] as String? ?? 'downloading';
|
||||
final trackName = downloadingCount == 1
|
||||
? firstDownloading.track.name
|
||||
: '$downloadingCount downloads';
|
||||
@@ -1870,24 +1897,29 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
int notifProgress = bytesReceived;
|
||||
int notifTotal = bytesTotal;
|
||||
|
||||
if (backendStatus == 'preparing') {
|
||||
final progressPercent =
|
||||
(selectedProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
final hasRealProgress =
|
||||
bytesReceived > 0 || bytesTotal > 0 || progressPercent > 0;
|
||||
|
||||
if (backendStatus == 'preparing' && !hasRealProgress) {
|
||||
notifProgress = 0;
|
||||
notifTotal = 100;
|
||||
notifTotal = 0;
|
||||
} else if (bytesTotal <= 0) {
|
||||
final progressPercent =
|
||||
(firstProgress['progress'] as num?)?.toDouble() ?? 0.0;
|
||||
notifProgress = (progressPercent * 100).toInt();
|
||||
notifTotal = 100;
|
||||
}
|
||||
final serviceStatus = notifTotal <= 0 ? 'preparing' : 'downloading';
|
||||
|
||||
final safeNotifTotal = notifTotal > 0 ? notifTotal : 1;
|
||||
if (_shouldUpdateProgressNotification(
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
progress: notifProgress,
|
||||
total: safeNotifTotal,
|
||||
queueCount: queuedCount,
|
||||
)) {
|
||||
if (!Platform.isAndroid &&
|
||||
_shouldUpdateProgressNotification(
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
progress: notifProgress,
|
||||
total: notifTotal,
|
||||
queueCount: queuedCount,
|
||||
)) {
|
||||
final safeNotifTotal = notifTotal > 0 ? notifTotal : 1;
|
||||
_notificationService.showDownloadProgress(
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
@@ -1901,8 +1933,9 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
trackName: firstDownloading.track.name,
|
||||
artistName: firstDownloading.track.artistName,
|
||||
progress: notifProgress,
|
||||
total: safeNotifTotal,
|
||||
total: notifTotal,
|
||||
queueCount: queuedCount,
|
||||
status: serviceStatus,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1915,22 +1948,28 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
required int progress,
|
||||
required int total,
|
||||
required int queueCount,
|
||||
String status = 'downloading',
|
||||
}) {
|
||||
final now = DateTime.now();
|
||||
final safeTotal = total > 0 ? total : 1;
|
||||
final progressPercent = ((progress * 100) / safeTotal)
|
||||
.round()
|
||||
.clamp(0, 100)
|
||||
.toInt();
|
||||
final progressBucket = progressPercent == 100
|
||||
? 100
|
||||
: ((progressPercent ~/ _serviceProgressStepPercent) *
|
||||
_serviceProgressStepPercent)
|
||||
.clamp(0, 100);
|
||||
final progressBucket = total <= 0
|
||||
? -1
|
||||
: (() {
|
||||
final progressPercent = ((progress * 100) / total)
|
||||
.round()
|
||||
.clamp(0, 100)
|
||||
.toInt();
|
||||
return progressPercent == 100
|
||||
? 100
|
||||
: ((progressPercent ~/ _serviceProgressStepPercent) *
|
||||
_serviceProgressStepPercent)
|
||||
.clamp(0, 100)
|
||||
.toInt();
|
||||
})();
|
||||
|
||||
final didContentChange =
|
||||
trackName != _lastServiceTrackName ||
|
||||
artistName != _lastServiceArtistName ||
|
||||
status != _lastServiceStatus ||
|
||||
queueCount != _lastServiceQueueCount ||
|
||||
progressBucket != _lastServicePercent;
|
||||
final allowHeartbeat =
|
||||
@@ -1942,6 +1981,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
|
||||
_lastServiceTrackName = trackName;
|
||||
_lastServiceArtistName = artistName;
|
||||
_lastServiceStatus = status;
|
||||
_lastServicePercent = progressBucket;
|
||||
_lastServiceQueueCount = queueCount;
|
||||
_lastServiceUpdateAt = now;
|
||||
@@ -1950,8 +1990,9 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
progress: progress,
|
||||
total: safeTotal,
|
||||
total: total,
|
||||
queueCount: queueCount,
|
||||
status: status,
|
||||
).catchError((_) {});
|
||||
}
|
||||
|
||||
@@ -1969,6 +2010,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
_usingProgressStream = false;
|
||||
_lastServiceTrackName = null;
|
||||
_lastServiceArtistName = null;
|
||||
_lastServiceStatus = null;
|
||||
_lastServicePercent = -1;
|
||||
_lastServiceQueueCount = -1;
|
||||
_lastServiceUpdateAt = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
@@ -3015,6 +3057,26 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
updatedItems[index] = next;
|
||||
state = state.copyWith(items: updatedItems);
|
||||
|
||||
if (Platform.isAndroid && status == DownloadStatus.finalizing) {
|
||||
PlatformBridge.clearItemProgress(id).catchError((_) {});
|
||||
final queueCount = updatedItems
|
||||
.where(
|
||||
(entry) =>
|
||||
entry.status == DownloadStatus.queued ||
|
||||
entry.status == DownloadStatus.downloading ||
|
||||
entry.status == DownloadStatus.finalizing,
|
||||
)
|
||||
.length;
|
||||
_maybeUpdateAndroidDownloadService(
|
||||
trackName: next.track.name,
|
||||
artistName: _notificationService.embeddingMetadataLabel,
|
||||
progress: 100,
|
||||
total: 100,
|
||||
queueCount: queueCount,
|
||||
status: 'finalizing',
|
||||
);
|
||||
}
|
||||
|
||||
if (status == DownloadStatus.completed ||
|
||||
status == DownloadStatus.failed ||
|
||||
status == DownloadStatus.skipped) {
|
||||
@@ -4327,6 +4389,7 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
orElse: () => state.items.first,
|
||||
);
|
||||
try {
|
||||
await _notificationService.cancelDownloadNotification();
|
||||
await PlatformBridge.startDownloadService(
|
||||
trackName: firstItem.track.name,
|
||||
artistName: firstItem.track.artistName,
|
||||
@@ -4470,7 +4533,8 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
_log.i(
|
||||
'Queue stats - completed: $_completedInSession, failed: $_failedInSession, totalAtStart: $_totalQueuedAtStart',
|
||||
);
|
||||
if (!stoppedWhilePaused && _totalQueuedAtStart > 0) {
|
||||
final hasSessionResults = _completedInSession > 0 || _failedInSession > 0;
|
||||
if (!stoppedWhilePaused && _totalQueuedAtStart > 0 && hasSessionResults) {
|
||||
await _notificationService.showQueueComplete(
|
||||
completedCount: _completedInSession,
|
||||
failedCount: _failedInSession,
|
||||
@@ -4483,6 +4547,10 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
|
||||
_log.i('Auto-exported failed downloads to: $exportPath');
|
||||
}
|
||||
}
|
||||
} else if (!stoppedWhilePaused && _totalQueuedAtStart > 0) {
|
||||
await _notificationService.showQueueCanceled(
|
||||
canceledCount: _totalQueuedAtStart,
|
||||
);
|
||||
}
|
||||
|
||||
if (stoppedWhilePaused) {
|
||||
|
||||
@@ -23,6 +23,9 @@ class NotificationService {
|
||||
_l10n = l10n;
|
||||
}
|
||||
|
||||
String get embeddingMetadataLabel =>
|
||||
_l10n?.notifEmbeddingMetadata ?? 'Embedding metadata...';
|
||||
|
||||
static const int downloadProgressId = 1;
|
||||
static const int updateDownloadId = 2;
|
||||
static const int libraryScanId = 3;
|
||||
@@ -282,11 +285,17 @@ class NotificationService {
|
||||
required int failedCount,
|
||||
}) async {
|
||||
if (!_isInitialized) await initialize();
|
||||
if (completedCount <= 0 && failedCount <= 0) return;
|
||||
|
||||
final title = failedCount > 0
|
||||
? (_l10n?.notifDownloadsFinished(completedCount, failedCount) ??
|
||||
'Downloads Finished ($completedCount done, $failedCount failed)')
|
||||
: (_l10n?.notifAllDownloadsComplete ?? 'All Downloads Complete');
|
||||
final body = failedCount > 0
|
||||
? (_l10n?.notifDownloadsFinishedBody(completedCount, failedCount) ??
|
||||
'$completedCount downloaded, $failedCount failed')
|
||||
: (_l10n?.notifTracksDownloadedSuccess(completedCount) ??
|
||||
'$completedCount tracks downloaded successfully');
|
||||
|
||||
const androidDetails = AndroidNotificationDetails(
|
||||
channelId,
|
||||
@@ -313,9 +322,46 @@ class NotificationService {
|
||||
await _showSafely(
|
||||
id: downloadProgressId,
|
||||
title: title,
|
||||
body:
|
||||
_l10n?.notifTracksDownloadedSuccess(completedCount) ??
|
||||
'$completedCount tracks downloaded successfully',
|
||||
body: body,
|
||||
details: details,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> showQueueCanceled({required int canceledCount}) async {
|
||||
if (!_isInitialized) await initialize();
|
||||
if (canceledCount <= 0) return;
|
||||
|
||||
final title = _l10n?.notifDownloadsCanceledTitle ?? 'Downloads canceled';
|
||||
final body =
|
||||
_l10n?.notifDownloadsCanceledBody(canceledCount) ??
|
||||
'$canceledCount downloads canceled by user';
|
||||
|
||||
const androidDetails = AndroidNotificationDetails(
|
||||
channelId,
|
||||
channelName,
|
||||
channelDescription: channelDescription,
|
||||
importance: Importance.defaultImportance,
|
||||
priority: Priority.defaultPriority,
|
||||
autoCancel: true,
|
||||
playSound: false,
|
||||
icon: '@mipmap/ic_launcher',
|
||||
);
|
||||
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentSound: false,
|
||||
);
|
||||
|
||||
const details = NotificationDetails(
|
||||
android: androidDetails,
|
||||
iOS: iosDetails,
|
||||
);
|
||||
|
||||
await _showSafely(
|
||||
id: downloadProgressId,
|
||||
title: title,
|
||||
body: body,
|
||||
details: details,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -816,6 +816,7 @@ class PlatformBridge {
|
||||
required int progress,
|
||||
required int total,
|
||||
required int queueCount,
|
||||
String status = 'downloading',
|
||||
}) async {
|
||||
await _channel.invokeMethod('updateDownloadServiceProgress', {
|
||||
'track_name': trackName,
|
||||
@@ -823,6 +824,7 @@ class PlatformBridge {
|
||||
'progress': progress,
|
||||
'total': total,
|
||||
'queue_count': queueCount,
|
||||
'status': status,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user