diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a58f2dd2..de0c2584 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -27,6 +27,7 @@
+
+
+
+
@@ -167,11 +176,11 @@
android:resource="@xml/shortcut" />
diff --git a/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt b/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt
new file mode 100644
index 00000000..4650f547
--- /dev/null
+++ b/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt
@@ -0,0 +1,235 @@
+package com.huanchengfly.tieba.post.services
+
+import android.Manifest
+import android.app.IntentService
+import android.app.PendingIntent
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.util.Log
+import android.widget.Toast
+import androidx.core.app.ActivityCompat
+import androidx.core.app.NotificationChannelCompat
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import androidx.core.app.ServiceCompat
+import com.huanchengfly.tieba.post.R
+import com.huanchengfly.tieba.post.activities.LoginActivity
+import com.huanchengfly.tieba.post.activities.MainActivity
+import com.huanchengfly.tieba.post.api.models.SignResultBean
+import com.huanchengfly.tieba.post.models.SignDataBean
+import com.huanchengfly.tieba.post.pendingIntentFlagImmutable
+import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils
+import com.huanchengfly.tieba.post.utils.AccountUtil
+import com.huanchengfly.tieba.post.utils.ProgressListener
+import com.huanchengfly.tieba.post.utils.SingleAccountSigner
+import com.huanchengfly.tieba.post.utils.addFlag
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.runBlocking
+import kotlin.coroutines.CoroutineContext
+
+class OKSignService : IntentService(TAG), CoroutineScope, ProgressListener {
+ private var job: Job = Job()
+ override val coroutineContext: CoroutineContext
+ get() = Dispatchers.Main + job
+
+ private val notificationManager: NotificationManagerCompat by lazy {
+ NotificationManagerCompat.from(this)
+ }
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ Log.i(TAG, "onStartCommand")
+ if (intent?.action == ACTION_START_SIGN) {
+ startForeground(
+ 1,
+ buildNotification(
+ getString(R.string.title_loading_data),
+ getString(R.string.text_please_wait)
+ ).build()
+ )
+ }
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ override fun onHandleIntent(intent: Intent?) {
+ Log.i(TAG, "onHandleWork")
+ if (intent?.action == ACTION_START_SIGN) {
+ val loginInfo = AccountUtil.getLoginInfo()
+ if (loginInfo != null) {
+ runBlocking {
+ SingleAccountSigner(
+ this@OKSignService,
+ AccountUtil.getLoginInfo()!!
+ )
+ .apply {
+ setProgressListener(this@OKSignService)
+ }
+ .start()
+ }
+ } else {
+ updateNotification(
+ getString(R.string.title_oksign_fail),
+ getString(R.string.text_login_first),
+ Intent(this, LoginActivity::class.java)
+ )
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
+ }
+ } else {
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
+ }
+ }
+
+ private fun createNotificationChannel() {
+ notificationManager.createNotificationChannel(
+ NotificationChannelCompat.Builder(
+ NOTIFICATION_CHANNEL_ID,
+ NotificationManagerCompat.IMPORTANCE_LOW
+ )
+ .setName(getString(R.string.title_oksign))
+ .setLightsEnabled(false)
+ .setShowBadge(false)
+ .build()
+ )
+ }
+
+ private fun buildNotification(title: String, text: String?): NotificationCompat.Builder {
+ createNotificationChannel()
+ return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setContentText(text)
+ .setContentTitle(title)
+ .setSubText(getString(R.string.title_oksign))
+ .setSmallIcon(R.drawable.ic_oksign)
+ .setAutoCancel(true)
+ .setStyle(NotificationCompat.BigTextStyle())
+ .setColor(ThemeUtils.getColorByAttr(this, R.attr.colorPrimary))
+ }
+
+ private fun updateNotification(title: String, text: String, intent: Intent) {
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return
+ }
+ notificationManager.notify(
+ 1,
+ buildNotification(title, text)
+ .setContentIntent(
+ PendingIntent.getActivity(
+ this,
+ 0,
+ intent,
+ pendingIntentFlagImmutable()
+ )
+ )
+ .build()
+ )
+ }
+
+ private fun updateNotification(title: String, text: String?) {
+ if (ActivityCompat.checkSelfPermission(
+ this,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return
+ }
+ val notification = buildNotification(title, text)
+ .build()
+ notification.flags = notification.flags.addFlag(NotificationCompat.FLAG_ONGOING_EVENT)
+ notificationManager.notify(1, notification)
+ }
+
+ private fun clearNotification() {
+ notificationManager.cancel(1)
+ }
+
+
+ override fun onStart(total: Int) {
+ updateNotification(getString(R.string.title_start_sign), null)
+ if (total > 0) Toast.makeText(
+ this,
+ R.string.toast_oksign_start,
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ coroutineContext.cancel()
+ }
+
+ override fun onProgressStart(signDataBean: SignDataBean, current: Int, total: Int) {
+ updateNotification(
+ getString(
+ R.string.title_signing_progress,
+ signDataBean.userName,
+ current,
+ total
+ ),
+ getString(
+ R.string.title_forum_name,
+ signDataBean.forumName
+ )
+ )
+ }
+
+ override fun onProgressFinish(
+ signDataBean: SignDataBean,
+ signResultBean: SignResultBean,
+ current: Int,
+ total: Int
+ ) {
+ updateNotification(
+ getString(
+ R.string.title_signing_progress,
+ signDataBean.userName,
+ current + 1,
+ total
+ ),
+ if (signResultBean.userInfo?.signBonusPoint != null)
+ getString(
+ R.string.text_singing_progress_exp,
+ signDataBean.forumName,
+ signResultBean.userInfo.signBonusPoint
+ )
+ else
+ getString(R.string.text_singing_progress, signDataBean.forumName)
+ )
+ }
+
+ override fun onFinish(success: Boolean, signedCount: Int, total: Int) {
+ updateNotification(
+ getString(R.string.title_oksign_finish),
+ if (total > 0) getString(
+ R.string.text_oksign_done,
+ signedCount
+ ) else getString(R.string.text_oksign_no_signable),
+ Intent(this, MainActivity::class.java)
+ )
+ sendBroadcast(Intent(ACTION_SIGN_SUCCESS_ALL))
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
+ }
+
+ override fun onFailure(current: Int, total: Int, errorCode: Int, errorMsg: String) {
+ ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
+ updateNotification(getString(R.string.title_oksign_fail), errorMsg)
+ }
+
+ companion object {
+// fun enqueueWork(context: Context, work: Intent) {
+// enqueueWork(context, OKSignService::class.java, JOB_ID, work)
+// }
+//
+// private const val JOB_ID = 233
+
+ const val TAG = "OKSignService"
+ const val NOTIFICATION_CHANNEL_ID = "1"
+ const val ACTION_SIGN_SUCCESS_ALL =
+ "com.huanchengfly.tieba.post.service.action.SIGN_SUCCESS_ALL"
+ const val ACTION_START_SIGN = "com.huanchengfly.tieba.post.service.action.ACTION_SIGN_START"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/AppPreferencesUtils.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/AppPreferencesUtils.kt
index 6df9a0c6..885b55c2 100644
--- a/app/src/main/java/com/huanchengfly/tieba/post/utils/AppPreferencesUtils.kt
+++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/AppPreferencesUtils.kt
@@ -2,8 +2,19 @@ package com.huanchengfly.tieba.post.utils
import android.content.Context
import androidx.datastore.core.DataStore
-import androidx.datastore.preferences.core.*
-import com.huanchengfly.tieba.post.*
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.floatPreferencesKey
+import androidx.datastore.preferences.core.intPreferencesKey
+import androidx.datastore.preferences.core.longPreferencesKey
+import androidx.datastore.preferences.core.stringPreferencesKey
+import com.huanchengfly.tieba.post.dataStore
+import com.huanchengfly.tieba.post.getBoolean
+import com.huanchengfly.tieba.post.getFloat
+import com.huanchengfly.tieba.post.getInt
+import com.huanchengfly.tieba.post.getLong
+import com.huanchengfly.tieba.post.getString
import com.huanchengfly.tieba.post.utils.ThemeUtil.TRANSLUCENT_THEME_LIGHT
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -21,6 +32,11 @@ open class AppPreferencesUtils(context: Context) {
var userLikeLastRequestUnix by DataStoreDelegates.long(defaultValue = 0L)
+ var appIcon by DataStoreDelegates.string(
+ defaultValue = Icons.DEFAULT_ICON,
+ key = AppIconUtil.PREF_KEY_APP_ICON
+ )
+
var autoSign by DataStoreDelegates.boolean(defaultValue = false, key = "auto_sign")
var autoSignTime by DataStoreDelegates.string(
diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/OKSigner.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/OKSigner.kt
index 87a816e9..2795be8c 100644
--- a/app/src/main/java/com/huanchengfly/tieba/post/utils/OKSigner.kt
+++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/OKSigner.kt
@@ -1,6 +1,7 @@
package com.huanchengfly.tieba.post.utils
import android.content.Context
+import android.util.Log
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.MSignBean
import com.huanchengfly.tieba.post.api.models.SignResultBean
@@ -118,6 +119,7 @@ class SingleAccountSigner(
signData.clear()
var userName: String by Delegates.notNull()
var tbs: String by Delegates.notNull()
+ Log.i(TAG, "start")
AccountUtil.fetchAccountFlow(account)
.flatMapConcat { account ->
userName = account.name
diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/TiebaUtil.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/TiebaUtil.kt
index c95c2fc7..8cb2434c 100644
--- a/app/src/main/java/com/huanchengfly/tieba/post/utils/TiebaUtil.kt
+++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/TiebaUtil.kt
@@ -2,33 +2,35 @@ package com.huanchengfly.tieba.post.utils
import android.app.AlarmManager
import android.app.PendingIntent
-import android.content.*
+import android.content.ClipData
+import android.content.ClipDescription
+import android.content.ClipboardManager
+import android.content.Context
+import android.content.Intent
import android.os.Build
import android.os.PersistableBundle
-import androidx.work.ExistingWorkPolicy
-import androidx.work.OneTimeWorkRequestBuilder
-import androidx.work.OutOfQuotaPolicy
-import androidx.work.WorkManager
+import androidx.core.content.ContextCompat
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.WebViewActivity
import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.CheckReportBean
import com.huanchengfly.tieba.post.components.dialogs.LoadingDialog
-import com.huanchengfly.tieba.post.components.workers.OKSignWork
import com.huanchengfly.tieba.post.pendingIntentFlagImmutable
import com.huanchengfly.tieba.post.receivers.AutoSignAlarm
+import com.huanchengfly.tieba.post.services.OKSignService
import com.huanchengfly.tieba.post.toastShort
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
-import java.util.*
+import java.util.Calendar
object TiebaUtil {
- private fun ClipData.setIsSensitive(isSensitive: Boolean): ClipData {
- description.extras = PersistableBundle().apply {
- putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, isSensitive)
+ private fun ClipData.setIsSensitive(isSensitive: Boolean): ClipData = apply {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ description.extras = PersistableBundle().apply {
+ putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, isSensitive)
+ }
}
- return this
}
@JvmStatic
@@ -80,36 +82,31 @@ object TiebaUtil {
@JvmStatic
fun startSign(context: Context) {
context.appPreferences.signDay = Calendar.getInstance()[Calendar.DAY_OF_MONTH]
-// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-// try {
-// context.startForegroundService(
-// Intent()
-// .setClassName(
-// context.packageName,
-// "${context.packageName}.services.OKSignService"
-// )
-// .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-// .setAction(OKSignService.ACTION_START_SIGN)
+// OKSignService.enqueueWork(
+// context,
+// Intent()
+// .setClassName(
+// context.packageName,
+// "${context.packageName}.services.OKSignService"
// )
-// } catch (e: IllegalStateException) {
-// e.printStackTrace()
-// }
-// } else {
-// context.startService(
-// Intent()
-// .setClassName(
-// context.packageName,
-// "${context.packageName}.services.OKSignService"
-// )
-// .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-// .setAction(OKSignService.ACTION_START_SIGN)
-// )
-// }
- val okSignWork = OneTimeWorkRequestBuilder()
- .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
- .build()
- WorkManager.getInstance(context)
- .enqueueUniqueWork("OKSign", ExistingWorkPolicy.KEEP, okSignWork)
+// .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+// .setAction(OKSignService.ACTION_START_SIGN)
+// )
+ ContextCompat.startForegroundService(
+ context,
+ Intent()
+ .setClassName(
+ context.packageName,
+ "${context.packageName}.services.OKSignService"
+ )
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ .setAction(OKSignService.ACTION_START_SIGN)
+ )
+// val okSignWork = OneTimeWorkRequestBuilder()
+// .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+// .build()
+// WorkManager.getInstance(context)
+// .enqueueUniqueWork("OKSign", ExistingWorkPolicy.KEEP, okSignWork)
}
@JvmStatic