Try to run sync in background

This commit is contained in:
Jackson Harper
2024-07-06 11:14:35 +08:00
parent 8466499593
commit 61d66f4b51
3 changed files with 28 additions and 152 deletions

View File

@ -40,81 +40,20 @@ class LibrarySyncWorker @AssistedInject constructor(
private val datastoreRepository: DatastoreRepository,
) : CoroutineWorker(appContext, workerParams) {
companion object {
const val NOTIFICATION_CHANNEL_ID = "LIBRARY_SYNC_WORKER_CHANNEL"
const val NOTIFICATION_CHANNEL_NAME = "Sync library"
const val NOTIFICATION_ID = 2
}
override suspend fun getForegroundInfo(): ForegroundInfo {
val notification = createNotification()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
ForegroundInfo(NOTIFICATION_ID, notification)
}
}
override suspend fun doWork(): Result {
return try {
// Start foreground service immediately
setForeground(getForegroundInfo())
withContext(Dispatchers.IO) {
performItemSync()
loadUsingSearchAPI()
Log.d("LibrarySyncWorker", "Library sync completed successfully")
Result.success()
}
} catch (e: IllegalStateException) {
Log.w("LibrarySyncWorker", "Couldn't start foreground service", e)
// Continue with the work without the foreground service
try {
performItemSync()
loadUsingSearchAPI()
Log.d("LibrarySyncWorker", "Library sync completed without foreground service")
Result.success()
} catch (e: Exception) {
Log.e("LibrarySyncWorker", "Failed to sync library without foreground service", e)
Result.failure()
}
} catch (e: Exception) {
Log.e("LibrarySyncWorker", "Unexpected error in LibrarySyncWorker", e)
Result.failure()
}
}
private fun createNotification(): Notification {
val channelId = createNotificationChannel()
return NotificationCompat.Builder(applicationContext, channelId)
.setContentTitle("Syncing library items")
.setContentText("Your library is being synced")
.setSmallIcon(R.drawable.ic_notification)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.build()
}
private fun createNotificationChannel(): String {
val channel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH
).apply {
description = "Notification channel for library syncing"
}
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
return NOTIFICATION_CHANNEL_ID
}
private suspend fun performItemSync(
cursor: String? = null,
since: String = getLastSyncTime()?.toString() ?: Instant.MIN.toString(),
@ -133,7 +72,7 @@ class LibrarySyncWorker @AssistedInject constructor(
if (result.hasError) {
result.errorString?.let { errorString ->
println("SYNC ERROR: $errorString")
Log.e("LibrarySyncWorker", "SYNC ERROR: $errorString")
}
}

View File

@ -37,6 +37,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import java.util.concurrent.TimeUnit
import kotlin.time.Duration.Companion.seconds
import kotlin.time.toJavaDuration
@ -134,23 +135,26 @@ class SaveSheetActivity : AppCompatActivity() {
}
private fun WorkManager.enqueueSaveWorker(context: Context, url: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
val saveData = workDataOf("url" to url)
val saveWork = OneTimeWorkRequestBuilder<SaveURLWorker>()
.setInputData(saveData)
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.build()
val inputData = Data.Builder()
.putString("url", url)
.build()
val saveURLWorkRequest = OneTimeWorkRequest.Builder(SaveURLWorker::class.java)
.setConstraints(constraints)
.setInputData(inputData)
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.addTag(url)
val syncWork = OneTimeWorkRequestBuilder<LibrarySyncWorker>()
.setConstraints(Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build())
.setInitialDelay(5, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork("saveUrl", ExistingWorkPolicy.REPLACE, saveURLWorkRequest)
.beginUniqueWork("saveAndSync", ExistingWorkPolicy.REPLACE, saveWork)
.then(syncWork)
.enqueue()
}
@Composable

View File

@ -36,31 +36,9 @@ class SaveURLWorker @AssistedInject constructor(
private val datastoreRepository: DatastoreRepository,
) : CoroutineWorker(appContext, workerParams) {
companion object {
const val NOTIFICATION_CHANNEL_ID = "SAVE_URL_WORKER_CHANNEL"
const val NOTIFICATION_CHANNEL_NAME = "URL Saver"
const val NOTIFICATION_ID = 1
}
override suspend fun getForegroundInfo(): ForegroundInfo {
val notification = createNotification()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
)
} else {
ForegroundInfo(NOTIFICATION_ID, notification)
}
}
override suspend fun doWork(): Result {
return try {
// Start foreground service immediately
setForeground(getForegroundInfo())
withContext(Dispatchers.IO) {
return withContext(Dispatchers.IO) {
try {
val url = inputData.getString("url")
if (url == null) {
Log.e("SaveURLWorker", "No URL provided")
@ -74,21 +52,10 @@ class SaveURLWorker @AssistedInject constructor(
Log.e("SaveURLWorker", "Failed to save URL")
Result.failure()
}
}
} catch (e: IllegalStateException) {
Log.w("SaveURLWorker", "Couldn't start foreground service", e)
// Continue with the work without the foreground service
val url = inputData.getString("url")
if (url != null && saveURL(url)) {
Log.d("SaveURLWorker", "URL saved successfully without foreground service")
Result.success()
} else {
Log.e("SaveURLWorker", "Failed to save URL without foreground service")
} catch (e: Exception) {
Log.e("SaveURLWorker", "Unexpected error in SaveURLWorker", e)
Result.failure()
}
} catch (e: Exception) {
Log.e("SaveURLWorker", "Unexpected error in SaveURLWorker", e)
Result.failure()
}
}
@ -102,7 +69,7 @@ class SaveURLWorker @AssistedInject constructor(
val cleanedUrl = cleanUrl(url) ?: url
try {
return try {
val timezone = TimeZone.getDefault().id
val locale = Locale.current.toLanguageTag()
@ -117,11 +84,10 @@ class SaveURLWorker @AssistedInject constructor(
)
)
).execute()
return (response.data?.saveUrl?.onSaveSuccess?.url != null)
(response.data?.saveUrl?.onSaveSuccess?.url != null)
} catch (e: Exception) {
Log.d("omnivore", "FAILED TO SAVE ITEM")
e.printStackTrace()
return false
Log.e("SaveURLWorker", "Failed to save item", e)
false
}
}
@ -129,43 +95,10 @@ class SaveURLWorker @AssistedInject constructor(
val pattern = Pattern.compile("\\b(?:https?|ftp)://\\S+")
val matcher = pattern.matcher(text)
if (matcher.find()) {
return matcher.group()
}
return null
}
private fun createNotification(): Notification {
val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
return if (matcher.find()) {
matcher.group()
} else {
""
}
return NotificationCompat.Builder(applicationContext, channelId)
.setContentTitle("Saving URL")
.setContentText("Your URL is being saved in the background.")
.setSmallIcon(R.drawable.ic_notification) // Ensure this icon is valid
.setPriority(NotificationCompat.PRIORITY_HIGH)
.build()
}
private fun createNotificationChannel(): String {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH // Changed from LOW to HIGH
).apply {
description = "Notification channel for URL saving"
}
val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
NOTIFICATION_CHANNEL_ID
} else {
""
null
}
}
}