Try to run sync in background
This commit is contained in:
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
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
|
||||
|
||||
@ -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,23 +52,12 @@ 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")
|
||||
Result.failure()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("SaveURLWorker", "Unexpected error in SaveURLWorker", e)
|
||||
Result.failure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveURL(url: String): Boolean {
|
||||
val authToken = datastoreRepository.getString(omnivoreAuthToken) ?: return false
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user