diff --git a/android/Omnivore/app/build.gradle.kts b/android/Omnivore/app/build.gradle.kts index 7a1e6ae76..f07338946 100644 --- a/android/Omnivore/app/build.gradle.kts +++ b/android/Omnivore/app/build.gradle.kts @@ -28,8 +28,8 @@ android { applicationId = "app.omnivore.omnivore" minSdk = 26 targetSdk = 34 - versionCode = 2200000 - versionName = "0.220.0" + versionCode = 2260000 + versionName = "0.226.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/android/Omnivore/app/src/main/AndroidManifest.xml b/android/Omnivore/app/src/main/AndroidManifest.xml index 9d0492483..c5bb107e6 100644 --- a/android/Omnivore/app/src/main/AndroidManifest.xml +++ b/android/Omnivore/app/src/main/AndroidManifest.xml @@ -6,7 +6,6 @@ - - diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibrarySyncWorker.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibrarySyncWorker.kt index 04fe65c34..ef0f9e822 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibrarySyncWorker.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/library/LibrarySyncWorker.kt @@ -4,6 +4,7 @@ import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context +import android.content.pm.ServiceInfo import android.os.Build import android.util.Log import androidx.compose.ui.text.intl.Locale @@ -31,7 +32,6 @@ import java.time.Instant import java.util.TimeZone import java.util.UUID import java.util.regex.Pattern - @HiltWorker class LibrarySyncWorker @AssistedInject constructor( @Assisted appContext: Context, @@ -39,76 +39,18 @@ class LibrarySyncWorker @AssistedInject constructor( private val libraryRepository: LibraryRepository, private val datastoreRepository: DatastoreRepository, ) : CoroutineWorker(appContext, workerParams) { - override suspend fun getForegroundInfo(): ForegroundInfo { - return ForegroundInfo( - NOTIFICATION_ID, - createNotification() - ) - } - - 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 doWork(): Result { - try { - setForeground(createForegroundInfo()) - } catch (e: Exception) { - e.printStackTrace() - return Result.failure() - } - - return withContext(Dispatchers.IO) { - try { + return try { + withContext(Dispatchers.IO) { performItemSync() loadUsingSearchAPI() + Log.d("LibrarySyncWorker", "Library sync completed successfully") Result.success() - } catch (e: Exception) { - e.printStackTrace() - Result.failure() } - } - } - - private fun createForegroundInfo(): ForegroundInfo { - val notification = createNotification() - return ForegroundInfo(NOTIFICATION_ID, notification) - } - - private fun createNotification(): Notification { - val channelId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - createNotificationChannel() - } else { - "" - } - - return NotificationCompat.Builder(applicationContext, channelId) - .setContentTitle("Syncing library items") - .setContentText("Your library is being synced") - .setSmallIcon(R.drawable.ic_notification) - .setPriority(NotificationCompat.PRIORITY_LOW) - .build() - } - - private fun createNotificationChannel(): String { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channelName = NOTIFICATION_CHANNEL_NAME - val channel = NotificationChannel( - NOTIFICATION_CHANNEL_ID, - channelName, - NotificationManager.IMPORTANCE_LOW - ).apply { - description = "Notification channel for library syncing" - } - - val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.createNotificationChannel(channel) - - return NOTIFICATION_CHANNEL_ID - } else { - return "" + } catch (e: Exception) { + Log.e("LibrarySyncWorker", "Unexpected error in LibrarySyncWorker", e) + Result.failure() } } @@ -130,7 +72,7 @@ class LibrarySyncWorker @AssistedInject constructor( if (result.hasError) { result.errorString?.let { errorString -> - println("SYNC ERROR: $errorString") + Log.e("LibrarySyncWorker", "SYNC ERROR: $errorString") } } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveSheetActivity.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveSheetActivity.kt index 3dcaa2c1b..ba480fb9f 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveSheetActivity.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveSheetActivity.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.unit.dp import androidx.work.Constraints import androidx.work.Data +import androidx.work.ExistingWorkPolicy import androidx.work.NetworkType import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequestBuilder @@ -36,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 @@ -133,28 +135,25 @@ 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() + .setInputData(saveData) + .setConstraints(Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build()) .build() - val syncWorkerRequest = OneTimeWorkRequest.Builder(LibrarySyncWorker::class.java) - .setConstraints(constraints) - .addTag(url) + val syncWork = OneTimeWorkRequestBuilder() + .setConstraints(Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build()) + .setInitialDelay(5, TimeUnit.SECONDS) .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) - .build() - - beginWith(saveURLWorkRequest) - .then(syncWorkerRequest) + WorkManager.getInstance(context) + .beginUniqueWork("saveAndSync", ExistingWorkPolicy.REPLACE, saveWork) + .then(syncWork) .enqueue() } diff --git a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveURLWorker.kt b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveURLWorker.kt index 192839b1a..027ffd5d8 100644 --- a/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveURLWorker.kt +++ b/android/Omnivore/app/src/main/java/app/omnivore/omnivore/feature/save/SaveURLWorker.kt @@ -4,6 +4,7 @@ import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context +import android.content.pm.ServiceInfo import android.os.Build import android.util.Log import androidx.compose.ui.text.intl.Locale @@ -34,30 +35,27 @@ class SaveURLWorker @AssistedInject constructor( @Assisted workerParams: WorkerParameters, private val datastoreRepository: DatastoreRepository, ) : CoroutineWorker(appContext, workerParams) { - override suspend fun getForegroundInfo(): ForegroundInfo { - return ForegroundInfo( - NOTIFICATION_ID, - createNotification() - ) - } - - 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 doWork(): Result { - try { - setForeground(createForegroundInfo()) - } catch (e: Exception) { - e.printStackTrace() - return Result.failure() - } - return withContext(Dispatchers.IO) { - val url = inputData.getString("url") ?: return@withContext Result.failure() - if (saveURL(url)) Result.success() else Result.failure() + try { + val url = inputData.getString("url") + if (url == null) { + Log.e("SaveURLWorker", "No URL provided") + return@withContext Result.failure() + } + + if (saveURL(url)) { + Log.d("SaveURLWorker", "URL saved successfully") + Result.success() + } else { + Log.e("SaveURLWorker", "Failed to save URL") + Result.failure() + } + } catch (e: Exception) { + Log.e("SaveURLWorker", "Unexpected error in SaveURLWorker", e) + Result.failure() + } } } @@ -71,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() @@ -86,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 } } @@ -98,49 +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 createForegroundInfo(): ForegroundInfo { - val notification = createNotification() - return ForegroundInfo(NOTIFICATION_ID, notification) - } - - 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_LOW) - .build() - } - - private fun createNotificationChannel(): String { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val channelName = NOTIFICATION_CHANNEL_NAME - val channel = NotificationChannel( - NOTIFICATION_CHANNEL_ID, - channelName, - NotificationManager.IMPORTANCE_LOW - ).apply { - description = "Notification channel for URL saving" - } - - val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - notificationManager.createNotificationChannel(channel) - - return NOTIFICATION_CHANNEL_ID - } else { - return "" + null } } }