Add pause, resume, and cancel controls for uploads
- Add pause/resume/cancel actions to notification bar - Add pause/resume/cancel buttons to in-app upload progress card - Track upload state (paused, uploading, cancelled) and upload type (chunked vs standard) - Chunked uploads support pause/resume, standard uploads only support cancel - Fix notification to persist cancelled state without flickering
This commit is contained in:
@@ -6,10 +6,18 @@ package com.mattintech.simplelogupload.constant;
|
||||
public class AppConstants {
|
||||
public static final String APP_TAG = "SLU::";
|
||||
|
||||
// Broadcast actions
|
||||
// Broadcast actions (service -> UI)
|
||||
public static final String ACTION_UPLOAD_COMPLETE = "com.mattintech.simplelogupload.UPLOAD_COMPLETE";
|
||||
public static final String ACTION_UPLOAD_ERROR = "com.mattintech.simplelogupload.UPLOAD_ERROR";
|
||||
public static final String ACTION_UPLOAD_PROGRESS = "com.mattintech.simplelogupload.UPLOAD_PROGRESS";
|
||||
public static final String ACTION_UPLOAD_PAUSED = "com.mattintech.simplelogupload.UPLOAD_PAUSED";
|
||||
public static final String ACTION_UPLOAD_RESUMED = "com.mattintech.simplelogupload.UPLOAD_RESUMED";
|
||||
public static final String ACTION_UPLOAD_CANCELLED = "com.mattintech.simplelogupload.UPLOAD_CANCELLED";
|
||||
|
||||
// Intent actions (UI/notification -> service)
|
||||
public static final String ACTION_PAUSE_UPLOAD = "com.mattintech.simplelogupload.PAUSE_UPLOAD";
|
||||
public static final String ACTION_RESUME_UPLOAD = "com.mattintech.simplelogupload.RESUME_UPLOAD";
|
||||
public static final String ACTION_CANCEL_UPLOAD = "com.mattintech.simplelogupload.CANCEL_UPLOAD";
|
||||
|
||||
// Intent extras
|
||||
public static final String EXTRA_UPLOAD_CODE = "upload_code";
|
||||
|
||||
@@ -66,6 +66,15 @@ class FileUploadForegroundService : Service() {
|
||||
private var notificationBuilder: NotificationCompat.Builder? = null
|
||||
private var lastProgressUpdate: Long = 0
|
||||
|
||||
// Upload state tracking
|
||||
private var currentUploadManager: ChunkedUploadManager? = null
|
||||
private var currentStandardUploadCall: Call? = null
|
||||
private var uploadState: UploadState = UploadState.IDLE
|
||||
|
||||
enum class UploadState {
|
||||
IDLE, UPLOADING, PAUSED, CANCELLED
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
uploadController = UploadController(this)
|
||||
@@ -83,6 +92,22 @@ class FileUploadForegroundService : Service() {
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
// Handle control actions
|
||||
when (intent.action) {
|
||||
AppConstants.ACTION_PAUSE_UPLOAD -> {
|
||||
handlePauseUpload()
|
||||
return START_STICKY
|
||||
}
|
||||
AppConstants.ACTION_RESUME_UPLOAD -> {
|
||||
handleResumeUpload()
|
||||
return START_STICKY
|
||||
}
|
||||
AppConstants.ACTION_CANCEL_UPLOAD -> {
|
||||
handleCancelUpload()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Intent received, extracting parameters...")
|
||||
|
||||
// Get file path from intent
|
||||
@@ -260,6 +285,10 @@ class FileUploadForegroundService : Service() {
|
||||
// Create chunked upload manager directly
|
||||
val uploadManager = ChunkedUploadManager(this, file, maxDownloads, expiryHours)
|
||||
|
||||
// Store reference for pause/resume/cancel control
|
||||
currentUploadManager = uploadManager
|
||||
uploadState = UploadState.UPLOADING
|
||||
|
||||
// Set progress listener with direct notification updates
|
||||
uploadManager.setProgressListener(object : ChunkedUploadManager.UploadProgressListener {
|
||||
override fun onProgress(bytesUploaded: Long, totalBytes: Long, percentComplete: Int) {
|
||||
@@ -288,6 +317,10 @@ class FileUploadForegroundService : Service() {
|
||||
override fun onUploadComplete(result: UploadResult) {
|
||||
Log.d(TAG, "Chunked upload complete: $result")
|
||||
|
||||
// Clear upload reference
|
||||
currentUploadManager = null
|
||||
uploadState = UploadState.IDLE
|
||||
|
||||
// Save to history directly if successful
|
||||
if (result.isSuccess) {
|
||||
saveToHistory(result)
|
||||
@@ -298,17 +331,22 @@ class FileUploadForegroundService : Service() {
|
||||
|
||||
override fun onError(error: String) {
|
||||
Log.e(TAG, "Chunked upload error: $error")
|
||||
|
||||
// Clear upload reference
|
||||
currentUploadManager = null
|
||||
uploadState = UploadState.IDLE
|
||||
|
||||
future.complete(UploadResult(error))
|
||||
}
|
||||
|
||||
override fun onPaused() {
|
||||
Log.d(TAG, "Chunked upload paused")
|
||||
updateNotification("Upload paused", -1, 100)
|
||||
// Note: updateNotification and sendPausedBroadcast are called in handlePauseUpload()
|
||||
}
|
||||
|
||||
override fun onResumed() {
|
||||
Log.d(TAG, "Chunked upload resumed")
|
||||
updateNotification("Resuming upload...", -1, 100)
|
||||
// Note: updateNotification and sendResumedBroadcast are called in handleResumeUpload()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -372,13 +410,27 @@ class FileUploadForegroundService : Service() {
|
||||
// Show initial progress
|
||||
updateNotification("Uploading ${file.name}...", 0, 100)
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
// Create call and store reference for cancellation
|
||||
val call = client.newCall(request)
|
||||
currentStandardUploadCall = call
|
||||
uploadState = UploadState.UPLOADING
|
||||
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
Log.e(TAG, "Upload failed", e)
|
||||
|
||||
// Clear upload reference
|
||||
currentStandardUploadCall = null
|
||||
uploadState = UploadState.IDLE
|
||||
|
||||
future.complete(UploadResult("Upload failed: ${e.message}"))
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
// Clear upload reference
|
||||
currentStandardUploadCall = null
|
||||
uploadState = UploadState.IDLE
|
||||
|
||||
response.use {
|
||||
if (response.isSuccessful) {
|
||||
try {
|
||||
@@ -482,6 +534,7 @@ class FileUploadForegroundService : Service() {
|
||||
.setOngoing(true)
|
||||
.setOnlyAlertOnce(true) // Don't alert on every progress update
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH) // High priority for better visibility
|
||||
.addAction(createCancelAction()) // Add cancel action from the start
|
||||
.apply {
|
||||
// Force immediate notification display on Android 14+ (prevents system delay)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
@@ -506,18 +559,49 @@ class FileUploadForegroundService : Service() {
|
||||
|
||||
Log.d(TAG, "Updating notification: $status (progress: $progress/$max)")
|
||||
|
||||
// Ignore updates if upload is cancelled (unless this IS the cancellation message)
|
||||
if (uploadState == UploadState.CANCELLED && !isComplete) {
|
||||
Log.d(TAG, "Ignoring notification update because upload is cancelled")
|
||||
return
|
||||
}
|
||||
|
||||
builder.setContentText(status)
|
||||
|
||||
if (progress >= 0) {
|
||||
if (progress >= 0 && !isComplete) {
|
||||
// Determinate progress
|
||||
builder.setProgress(max, progress, false)
|
||||
} else {
|
||||
} else if (!isComplete) {
|
||||
// Indeterminate progress
|
||||
builder.setProgress(max, 0, true)
|
||||
}
|
||||
|
||||
// When complete, make notification dismissible and remove progress bar
|
||||
if (isComplete) {
|
||||
// Add action buttons based on upload state
|
||||
if (!isComplete && uploadState != UploadState.CANCELLED) {
|
||||
builder.clearActions() // Remove old actions
|
||||
|
||||
when (uploadState) {
|
||||
UploadState.PAUSED -> {
|
||||
// Show Resume and Cancel buttons
|
||||
builder.addAction(createResumeAction())
|
||||
builder.addAction(createCancelAction())
|
||||
}
|
||||
UploadState.UPLOADING -> {
|
||||
// Show Pause (if chunked) and Cancel buttons
|
||||
if (currentUploadManager != null) {
|
||||
builder.addAction(createPauseAction())
|
||||
}
|
||||
builder.addAction(createCancelAction())
|
||||
}
|
||||
else -> {
|
||||
// For IDLE or other states, just show Cancel
|
||||
builder.addAction(createCancelAction())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When complete or cancelled, make notification dismissible and remove progress bar
|
||||
if (isComplete || uploadState == UploadState.CANCELLED) {
|
||||
builder.clearActions() // Remove all actions
|
||||
builder.setOngoing(false)
|
||||
.setProgress(0, 0, false) // Remove progress bar
|
||||
.setAutoCancel(true) // Allow swipe to dismiss
|
||||
@@ -611,4 +695,182 @@ class FileUploadForegroundService : Service() {
|
||||
// Send local broadcast to the ViewModel
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a broadcast when upload is paused
|
||||
*/
|
||||
private fun sendPausedBroadcast() {
|
||||
Log.d(TAG, "Sending paused broadcast")
|
||||
val intent = Intent(AppConstants.ACTION_UPLOAD_PAUSED)
|
||||
sendBroadcast(intent)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a broadcast when upload is resumed
|
||||
*/
|
||||
private fun sendResumedBroadcast() {
|
||||
Log.d(TAG, "Sending resumed broadcast")
|
||||
val intent = Intent(AppConstants.ACTION_UPLOAD_RESUMED)
|
||||
sendBroadcast(intent)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a broadcast when upload is cancelled
|
||||
*/
|
||||
private fun sendCancelledBroadcast() {
|
||||
Log.d(TAG, "Sending cancelled broadcast")
|
||||
val intent = Intent(AppConstants.ACTION_UPLOAD_CANCELLED)
|
||||
sendBroadcast(intent)
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pause action for the notification
|
||||
*/
|
||||
private fun createPauseAction(): NotificationCompat.Action {
|
||||
val pauseIntent = Intent(this, FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_PAUSE_UPLOAD
|
||||
}
|
||||
val pausePendingIntent = PendingIntent.getService(
|
||||
this,
|
||||
1,
|
||||
pauseIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
return NotificationCompat.Action.Builder(
|
||||
android.R.drawable.ic_media_pause,
|
||||
"Pause",
|
||||
pausePendingIntent
|
||||
).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a resume action for the notification
|
||||
*/
|
||||
private fun createResumeAction(): NotificationCompat.Action {
|
||||
val resumeIntent = Intent(this, FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_RESUME_UPLOAD
|
||||
}
|
||||
val resumePendingIntent = PendingIntent.getService(
|
||||
this,
|
||||
2,
|
||||
resumeIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
return NotificationCompat.Action.Builder(
|
||||
android.R.drawable.ic_media_play,
|
||||
"Resume",
|
||||
resumePendingIntent
|
||||
).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cancel action for the notification
|
||||
*/
|
||||
private fun createCancelAction(): NotificationCompat.Action {
|
||||
val cancelIntent = Intent(this, FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_CANCEL_UPLOAD
|
||||
}
|
||||
val cancelPendingIntent = PendingIntent.getService(
|
||||
this,
|
||||
3,
|
||||
cancelIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
return NotificationCompat.Action.Builder(
|
||||
android.R.drawable.ic_menu_close_clear_cancel,
|
||||
"Cancel",
|
||||
cancelPendingIntent
|
||||
).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle pause upload request
|
||||
*/
|
||||
private fun handlePauseUpload() {
|
||||
Log.d(TAG, "Handling pause upload request")
|
||||
|
||||
if (uploadState != UploadState.UPLOADING) {
|
||||
Log.w(TAG, "Cannot pause: upload not in progress (state: $uploadState)")
|
||||
return
|
||||
}
|
||||
|
||||
uploadState = UploadState.PAUSED
|
||||
|
||||
currentUploadManager?.let { manager ->
|
||||
manager.pauseUpload()
|
||||
updateNotification("Upload paused", -1, 100)
|
||||
sendPausedBroadcast()
|
||||
Log.d(TAG, "Chunked upload paused successfully")
|
||||
} ?: run {
|
||||
Log.w(TAG, "Cannot pause standard upload (not supported)")
|
||||
updateNotification("Cannot pause standard upload", -1, 100)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle resume upload request
|
||||
*/
|
||||
private fun handleResumeUpload() {
|
||||
Log.d(TAG, "Handling resume upload request")
|
||||
|
||||
if (uploadState != UploadState.PAUSED) {
|
||||
Log.w(TAG, "Cannot resume: upload not paused (state: $uploadState)")
|
||||
return
|
||||
}
|
||||
|
||||
uploadState = UploadState.UPLOADING
|
||||
|
||||
currentUploadManager?.let { manager ->
|
||||
manager.resumeUpload()
|
||||
updateNotification("Resuming upload...", -1, 100)
|
||||
sendResumedBroadcast()
|
||||
Log.d(TAG, "Chunked upload resumed successfully")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle cancel upload request
|
||||
*/
|
||||
private fun handleCancelUpload() {
|
||||
Log.d(TAG, "Handling cancel upload request")
|
||||
|
||||
uploadState = UploadState.CANCELLED
|
||||
|
||||
// Cancel chunked upload
|
||||
currentUploadManager?.let { manager ->
|
||||
manager.cancelUpload()
|
||||
currentUploadManager = null
|
||||
Log.d(TAG, "Cancelled chunked upload")
|
||||
}
|
||||
|
||||
// Cancel standard upload
|
||||
currentStandardUploadCall?.let { call ->
|
||||
call.cancel()
|
||||
currentStandardUploadCall = null
|
||||
Log.d(TAG, "Cancelled standard upload")
|
||||
}
|
||||
|
||||
// Clear upload in progress flag
|
||||
PreferencesUtil.setUploadInProgress(this, false, null)
|
||||
|
||||
// Send cancelled broadcast
|
||||
sendCancelledBroadcast()
|
||||
|
||||
// Update notification
|
||||
updateNotification("Upload cancelled", -1, 100, isComplete = true)
|
||||
|
||||
// Stop service after a short delay
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
stopForeground(STOP_FOREGROUND_DETACH)
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
stopForeground(false)
|
||||
}
|
||||
stopSelf()
|
||||
}, 500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,17 @@ package com.mattintech.simplelogupload.ui.screens
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BugReport
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.History
|
||||
import androidx.compose.material.icons.filled.Pause
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Upload
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
@@ -113,7 +117,7 @@ fun MainScreen(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Uploading",
|
||||
text = if (uiState.isPaused) "Upload Paused" else "Uploading",
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
@@ -149,6 +153,70 @@ fun MainScreen(
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||
)
|
||||
}
|
||||
|
||||
// Status message
|
||||
uiState.uploadStatusMessage?.let { message ->
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = message,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||
fontStyle = FontStyle.Italic
|
||||
)
|
||||
}
|
||||
|
||||
// Control buttons
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (uiState.isPaused) {
|
||||
// Show Resume button
|
||||
TextButton(
|
||||
onClick = { viewModel.resumeUpload() }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.PlayArrow,
|
||||
contentDescription = "Resume",
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text("Resume")
|
||||
}
|
||||
} else {
|
||||
// Show Pause button (only for chunked uploads)
|
||||
if (uiState.isChunkedUpload) {
|
||||
TextButton(
|
||||
onClick = { viewModel.pauseUpload() }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Pause,
|
||||
contentDescription = "Pause",
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text("Pause")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
|
||||
// Cancel button (always shown)
|
||||
TextButton(
|
||||
onClick = { viewModel.cancelUpload() }
|
||||
) {
|
||||
Icon(
|
||||
Icons.Default.Close,
|
||||
contentDescription = "Cancel",
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
Text("Cancel")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import com.mattintech.simplelogupload.constant.AppConstants
|
||||
import com.mattintech.simplelogupload.controller.FileController
|
||||
import com.mattintech.simplelogupload.controller.UploadController
|
||||
import com.mattintech.simplelogupload.model.UploadResult
|
||||
import com.mattintech.simplelogupload.service.FileUploadForegroundService
|
||||
import com.mattintech.simplelogupload.upload.UploadStrategySelector
|
||||
import com.mattintech.simplelogupload.util.PreferencesUtil
|
||||
import com.mattintech.simplelogupload.util.ZipUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -30,6 +32,9 @@ import java.util.*
|
||||
*/
|
||||
data class MainUiState(
|
||||
val isLoading: Boolean = false,
|
||||
val isPaused: Boolean = false,
|
||||
val isChunkedUpload: Boolean = false,
|
||||
val uploadStatusMessage: String? = null,
|
||||
val selectedFile: File? = null,
|
||||
val selectedFileName: String? = null,
|
||||
val dumpstateFiles: List<File> = emptyList(),
|
||||
@@ -150,6 +155,41 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
totalBytes = 0
|
||||
)
|
||||
}
|
||||
AppConstants.ACTION_UPLOAD_PAUSED -> {
|
||||
Log.d(TAG, "Upload paused")
|
||||
_uiState.value = _uiState.value.copy(
|
||||
isPaused = true,
|
||||
uploadStatusMessage = "Upload paused"
|
||||
)
|
||||
}
|
||||
AppConstants.ACTION_UPLOAD_RESUMED -> {
|
||||
Log.d(TAG, "Upload resumed")
|
||||
_uiState.value = _uiState.value.copy(
|
||||
isPaused = false,
|
||||
uploadStatusMessage = "Resuming upload..."
|
||||
)
|
||||
}
|
||||
AppConstants.ACTION_UPLOAD_CANCELLED -> {
|
||||
Log.d(TAG, "Upload cancelled")
|
||||
|
||||
// Clean up temporary zip file if it exists
|
||||
currentUploadTempZipFile?.let { tempFile ->
|
||||
if (tempFile.exists()) {
|
||||
val deleted = tempFile.delete()
|
||||
Log.d(TAG, "Cleaned up temp zip file after cancellation: ${tempFile.name}, deleted: $deleted")
|
||||
}
|
||||
currentUploadTempZipFile = null
|
||||
}
|
||||
|
||||
_uiState.value = _uiState.value.copy(
|
||||
isLoading = false,
|
||||
isPaused = false,
|
||||
uploadProgress = 0,
|
||||
bytesUploaded = 0,
|
||||
totalBytes = 0,
|
||||
uploadStatusMessage = "Upload cancelled"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,6 +198,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
addAction(AppConstants.ACTION_UPLOAD_PROGRESS)
|
||||
addAction(AppConstants.ACTION_UPLOAD_COMPLETE)
|
||||
addAction(AppConstants.ACTION_UPLOAD_ERROR)
|
||||
addAction(AppConstants.ACTION_UPLOAD_PAUSED)
|
||||
addAction(AppConstants.ACTION_UPLOAD_RESUMED)
|
||||
addAction(AppConstants.ACTION_UPLOAD_CANCELLED)
|
||||
}
|
||||
|
||||
LocalBroadcastManager.getInstance(getApplication())
|
||||
@@ -288,8 +331,15 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
currentUploadMaxDownloads = maxDownloads
|
||||
currentUploadExpiryHours = expiryHours
|
||||
|
||||
// Determine if this will be a chunked upload
|
||||
val isChunked = UploadStrategySelector.shouldUseChunkedUpload(getApplication(), file)
|
||||
Log.d(TAG, "Upload will use ${if (isChunked) "chunked" else "standard"} strategy")
|
||||
|
||||
_uiState.value = _uiState.value.copy(
|
||||
isLoading = true,
|
||||
isChunkedUpload = isChunked,
|
||||
isPaused = false,
|
||||
uploadStatusMessage = null,
|
||||
showUploadParamsDialog = false
|
||||
)
|
||||
|
||||
@@ -358,6 +408,17 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
currentUploadMaxDownloads = maxDownloads
|
||||
currentUploadExpiryHours = expiryHours
|
||||
|
||||
// Determine if this will be a chunked upload
|
||||
val isChunked = UploadStrategySelector.shouldUseChunkedUpload(getApplication(), fileToUpload)
|
||||
Log.d(TAG, "Upload will use ${if (isChunked) "chunked" else "standard"} strategy")
|
||||
|
||||
// Update state with upload type
|
||||
_uiState.value = _uiState.value.copy(
|
||||
isChunkedUpload = isChunked,
|
||||
isPaused = false,
|
||||
uploadStatusMessage = null
|
||||
)
|
||||
|
||||
uploadController.startUploadService(fileToUpload, maxDownloads, expiryHours)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error uploading dumpstate files", e)
|
||||
@@ -378,6 +439,39 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the current upload
|
||||
*/
|
||||
fun pauseUpload() {
|
||||
Log.d(TAG, "Pause upload requested")
|
||||
val intent = Intent(getApplication(), FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_PAUSE_UPLOAD
|
||||
}
|
||||
getApplication<Application>().startService(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume the paused upload
|
||||
*/
|
||||
fun resumeUpload() {
|
||||
Log.d(TAG, "Resume upload requested")
|
||||
val intent = Intent(getApplication(), FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_RESUME_UPLOAD
|
||||
}
|
||||
getApplication<Application>().startService(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the current upload
|
||||
*/
|
||||
fun cancelUpload() {
|
||||
Log.d(TAG, "Cancel upload requested")
|
||||
val intent = Intent(getApplication(), FileUploadForegroundService::class.java).apply {
|
||||
action = AppConstants.ACTION_CANCEL_UPLOAD
|
||||
}
|
||||
getApplication<Application>().startService(intent)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
// Unregister broadcast receiver
|
||||
|
||||
Reference in New Issue
Block a user