From b2b85bfcdacb52d22c2efb31764d05094aab716e Mon Sep 17 00:00:00 2001 From: HuanCheng65 <22636177+HuanCheng65@users.noreply.github.com> Date: Sat, 31 Dec 2022 13:51:20 +0800 Subject: [PATCH] =?UTF-8?q?pref:=20=E4=BC=98=E5=8C=96=E4=B8=80=E9=94=AE?= =?UTF-8?q?=E7=AD=BE=E5=88=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 21 +- .../tieba/post/services/OKSignService.kt | 235 ++++++++++++++++++ .../tieba/post/utils/AppPreferencesUtils.kt | 20 +- .../huanchengfly/tieba/post/utils/OKSigner.kt | 2 + .../tieba/post/utils/TiebaUtil.kt | 77 +++--- 5 files changed, 307 insertions(+), 48 deletions(-) create mode 100644 app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt 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