diff --git a/android/Omnivore/.gitignore b/android/Omnivore/.gitignore
index aa724b770..04f46af22 100644
--- a/android/Omnivore/.gitignore
+++ b/android/Omnivore/.gitignore
@@ -1,5 +1,6 @@
*.iml
.gradle
+.kotlin
/local.properties
/.idea/caches
/.idea/libraries
diff --git a/android/Omnivore/app/src/main/AndroidManifest.xml b/android/Omnivore/app/src/main/AndroidManifest.xml
index 5d3936eb1..00ef228cf 100644
--- a/android/Omnivore/app/src/main/AndroidManifest.xml
+++ b/android/Omnivore/app/src/main/AndroidManifest.xml
@@ -6,6 +6,8 @@
+
+
= 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 ""
+ }
+ }
+
private suspend fun performItemSync(
cursor: String? = null,
since: String = getLastSyncTime()?.toString() ?: Instant.MIN.toString(),
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 9a2c99ae1..3dcaa2c1b 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
@@ -1,9 +1,11 @@
package app.omnivore.omnivore.feature.save
import android.content.ContentValues
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
+import android.view.WindowManager
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
@@ -16,9 +18,12 @@ import androidx.compose.ui.Alignment.Companion.TopCenter
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import androidx.work.Constraints
+import androidx.work.Data
import androidx.work.NetworkType
+import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkInfo
@@ -49,7 +54,7 @@ class SaveSheetActivity : AppCompatActivity() {
if (intent.type?.startsWith("text/plain") == true) {
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
extractedText = it
- workManager.enqueueSaveWorker(it)
+ workManager.enqueueSaveWorker(this, it)
Log.d(ContentValues.TAG, "Extracted text: $extractedText")
}
}
@@ -80,8 +85,6 @@ class SaveSheetActivity : AppCompatActivity() {
}
val scaffoldState: ScaffoldState = rememberScaffoldState()
-
-
val message = when (saveState) {
SaveState.DEFAULT -> ""
SaveState.SAVING -> "Saved to Omnivore"
@@ -129,25 +132,28 @@ class SaveSheetActivity : AppCompatActivity() {
}
}
- private fun WorkManager.enqueueSaveWorker(url: String) {
+ private fun WorkManager.enqueueSaveWorker(context: Context, url: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
- val saveWorkerRequest = OneTimeWorkRequestBuilder()
- .setConstraints(constraints)
- .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
- .setInputData(workDataOf("url" to url))
- .addTag(url)
- // Can add other configs like setBackoffCriteria to retry sync if failed
- .build()
- val syncWorkerRequest = OneTimeWorkRequestBuilder()
+ val syncWorkerRequest = OneTimeWorkRequest.Builder(LibrarySyncWorker::class.java)
.setConstraints(constraints)
.addTag(url)
- .setInitialDelay(5.seconds.toJavaDuration())
.build()
- beginWith(saveWorkerRequest)
+ 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)
.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 b305dd8a9..192839b1a 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
@@ -1,10 +1,18 @@
package app.omnivore.omnivore.feature.save
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
import android.content.Context
+import android.os.Build
+import android.util.Log
import androidx.compose.ui.text.intl.Locale
+import androidx.core.app.NotificationCompat
import androidx.hilt.work.HiltWorker
import androidx.work.CoroutineWorker
+import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
+import app.omnivore.omnivore.R
import app.omnivore.omnivore.core.datastore.DatastoreRepository
import app.omnivore.omnivore.core.datastore.omnivoreAuthToken
import app.omnivore.omnivore.graphql.generated.SaveUrlMutation
@@ -26,16 +34,34 @@ 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 {
- return withContext(Dispatchers.IO){
+ 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()
}
}
private suspend fun saveURL(url: String): Boolean {
-
val authToken = datastoreRepository.getString(omnivoreAuthToken) ?: return false
val apolloClient = ApolloClient.Builder()
@@ -60,9 +86,10 @@ class SaveURLWorker @AssistedInject constructor(
)
)
).execute()
-
return (response.data?.saveUrl?.onSaveSuccess?.url != null)
} catch (e: Exception) {
+ Log.d("omnivore", "FAILED TO SAVE ITEM")
+ e.printStackTrace()
return false
}
}
@@ -77,5 +104,43 @@ class SaveURLWorker @AssistedInject constructor(
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()
+ } 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 ""
+ }
+ }
}
diff --git a/android/Omnivore/app/src/main/res/drawable/ic_notification.xml b/android/Omnivore/app/src/main/res/drawable/ic_notification.xml
new file mode 100644
index 000000000..1563b649d
--- /dev/null
+++ b/android/Omnivore/app/src/main/res/drawable/ic_notification.xml
@@ -0,0 +1,5 @@
+
+
+
+
+