pref: 优化一键签到

This commit is contained in:
HuanCheng65 2022-12-31 13:51:20 +08:00
parent 39a6470f4d
commit b2b85bfcda
No known key found for this signature in database
GPG Key ID: E9031EF91A805148
5 changed files with 307 additions and 48 deletions

View File

@ -27,6 +27,7 @@
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.miui.personalassistant.permission.FAVORITE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<supports-screens
android:anyDensity="true"
@ -57,6 +58,13 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute">
<service
android:name=".services.OKSignService"
android:exported="true"
android:enabled="true"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":oksign" />
<activity
android:name=".activities.AppFontSizeActivity"
android:configChanges="screenSize|screenLayout|orientation|smallestScreenSize|keyboardHidden"
@ -77,6 +85,7 @@
android:configChanges="screenSize|screenLayout|orientation|smallestScreenSize|keyboardHidden"
android:theme="@style/AppTheme.PhotoView"
android:windowSoftInputMode="adjustResize" />
<receiver
android:name=".receivers.BootCompleteSignReceiver"
android:enabled="true"
@ -150,11 +159,11 @@
</activity>
<activity-alias
android:name=".MainActivityIconOld"
android:name=".MainActivityIconInvert"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:icon="@mipmap/ic_launcher_new_invert"
android:roundIcon="@mipmap/ic_launcher_new_invert_round"
android:targetActivity=".MainActivityV2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -167,11 +176,11 @@
android:resource="@xml/shortcut" />
</activity-alias>
<activity-alias
android:name=".MainActivityIconInvert"
android:name=".MainActivityIconOld"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_new_invert"
android:roundIcon="@mipmap/ic_launcher_new_invert_round"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:targetActivity=".MainActivityV2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -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"
}
}

View File

@ -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(

View File

@ -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

View File

@ -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 {
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,9 +82,8 @@ 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(
// OKSignService.enqueueWork(
// context,
// Intent()
// .setClassName(
// context.packageName,
@ -91,25 +92,21 @@ object TiebaUtil {
// .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// .setAction(OKSignService.ACTION_START_SIGN)
// )
// } 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<OKSignWork>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork("OKSign", ExistingWorkPolicy.KEEP, okSignWork)
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<OKSignWork>()
// .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
// .build()
// WorkManager.getInstance(context)
// .enqueueUniqueWork("OKSign", ExistingWorkPolicy.KEEP, okSignWork)
}
@JvmStatic