first commit
This commit is contained in:
65
app/src/main/java/com/juhabi/birds/util/LubanCompressUtil.kt
Normal file
65
app/src/main/java/com/juhabi/birds/util/LubanCompressUtil.kt
Normal file
@@ -0,0 +1,65 @@
|
||||
package com.juhabi.birds.util
|
||||
|
||||
import android.content.Context
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import top.zibin.luban.Luban
|
||||
import top.zibin.luban.OnCompressListener
|
||||
|
||||
/** 使用 Luban 对图片文件进行异步压缩。 */
|
||||
object LubanCompressUtil {
|
||||
|
||||
private const val DEFAULT_IGNORE_SIZE_KB = 100
|
||||
|
||||
interface CompressCallback {
|
||||
/** 图片压缩成功。 */
|
||||
fun success(file: File)
|
||||
|
||||
/** 图片压缩失败。 */
|
||||
fun fail(failMsg: String)
|
||||
}
|
||||
|
||||
/** 兼容 WaterProject 中的单例调用方式。 */
|
||||
fun getInstance(): LubanCompressUtil {
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩指定图片。
|
||||
*
|
||||
* 小于 100KB 的图片保持原样,GIF 图片不参与压缩。
|
||||
*/
|
||||
fun getCompressFile(
|
||||
context: Context,
|
||||
oldFile: File,
|
||||
callback: CompressCallback?
|
||||
) {
|
||||
if (!oldFile.exists() || !oldFile.isFile) {
|
||||
callback?.fail("图片文件不存在")
|
||||
return
|
||||
}
|
||||
|
||||
Luban.with(context.applicationContext)
|
||||
.load(oldFile)
|
||||
.ignoreBy(DEFAULT_IGNORE_SIZE_KB)
|
||||
.filter { path ->
|
||||
path.isNotBlank() && !path.lowercase(Locale.ROOT).endsWith(".gif")
|
||||
}
|
||||
.setCompressListener(object : OnCompressListener {
|
||||
/** 压缩开始。 */
|
||||
override fun onStart() {
|
||||
}
|
||||
|
||||
/** 返回压缩后的图片文件。 */
|
||||
override fun onSuccess(file: File) {
|
||||
callback?.success(file)
|
||||
}
|
||||
|
||||
/** 将压缩异常转换为业务错误消息。 */
|
||||
override fun onError(error: Throwable) {
|
||||
callback?.fail(error.message ?: "图片压缩失败")
|
||||
}
|
||||
})
|
||||
.launch()
|
||||
}
|
||||
}
|
||||
112
app/src/main/java/com/juhabi/birds/util/SharedPreferencesUtil.kt
Normal file
112
app/src/main/java/com/juhabi/birds/util/SharedPreferencesUtil.kt
Normal file
@@ -0,0 +1,112 @@
|
||||
package com.juhabi.birds.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonSyntaxException
|
||||
|
||||
/**
|
||||
* 使用 SharedPreferences 存储轻量级本地数据。
|
||||
*
|
||||
* 复杂对象会序列化为 JSON,仅适合存储用户信息等体积较小的数据。
|
||||
*/
|
||||
object SharedPreferencesUtil {
|
||||
const val DEFAULT_PREFERENCES_NAME = "kot_mvp_user"
|
||||
|
||||
private val gson = Gson()
|
||||
|
||||
private fun preferences(
|
||||
context: Context,
|
||||
preferencesName: String
|
||||
): SharedPreferences = context.applicationContext.getSharedPreferences(
|
||||
preferencesName,
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
|
||||
fun putString(
|
||||
context: Context,
|
||||
key: String,
|
||||
value: String,
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
) = preferences(context, preferencesName).edit().putString(key, value).apply()
|
||||
|
||||
fun getString(
|
||||
context: Context,
|
||||
key: String,
|
||||
defaultValue: String = "",
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
): String = preferences(context, preferencesName).getString(key, defaultValue) ?: defaultValue
|
||||
|
||||
fun putInt(context: Context, key: String, value: Int, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().putInt(key, value).apply()
|
||||
|
||||
fun getInt(context: Context, key: String, defaultValue: Int = 0, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).getInt(key, defaultValue)
|
||||
|
||||
fun putLong(context: Context, key: String, value: Long, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().putLong(key, value).apply()
|
||||
|
||||
fun getLong(context: Context, key: String, defaultValue: Long = 0L, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).getLong(key, defaultValue)
|
||||
|
||||
fun putFloat(context: Context, key: String, value: Float, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().putFloat(key, value).apply()
|
||||
|
||||
fun getFloat(context: Context, key: String, defaultValue: Float = 0f, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).getFloat(key, defaultValue)
|
||||
|
||||
fun putBoolean(context: Context, key: String, value: Boolean, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().putBoolean(key, value).apply()
|
||||
|
||||
fun getBoolean(context: Context, key: String, defaultValue: Boolean = false, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).getBoolean(key, defaultValue)
|
||||
|
||||
fun putStringSet(
|
||||
context: Context,
|
||||
key: String,
|
||||
value: Set<String>,
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
) = preferences(context, preferencesName).edit().putStringSet(key, value).apply()
|
||||
|
||||
fun getStringSet(
|
||||
context: Context,
|
||||
key: String,
|
||||
defaultValue: Set<String> = emptySet(),
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
): Set<String> = preferences(context, preferencesName)
|
||||
.getStringSet(key, defaultValue)
|
||||
?.toSet()
|
||||
?: defaultValue
|
||||
|
||||
fun putObject(
|
||||
context: Context,
|
||||
key: String,
|
||||
value: Any,
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
) = putString(context, key, gson.toJson(value), preferencesName)
|
||||
|
||||
fun <T> getObject(
|
||||
context: Context,
|
||||
key: String,
|
||||
clazz: Class<T>,
|
||||
preferencesName: String = DEFAULT_PREFERENCES_NAME
|
||||
): T? {
|
||||
val json = getString(context, key, preferencesName = preferencesName)
|
||||
if (json.isBlank()) return null
|
||||
|
||||
return try {
|
||||
gson.fromJson(json, clazz)
|
||||
} catch (_: JsonSyntaxException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun contains(context: Context, key: String, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).contains(key)
|
||||
|
||||
fun remove(context: Context, key: String, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().remove(key).apply()
|
||||
|
||||
fun clear(context: Context, preferencesName: String = DEFAULT_PREFERENCES_NAME) =
|
||||
preferences(context, preferencesName).edit().clear().apply()
|
||||
}
|
||||
43
app/src/main/java/com/juhabi/birds/util/ToastUtil.kt
Normal file
43
app/src/main/java/com/juhabi/birds/util/ToastUtil.kt
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.juhabi.birds.util
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
|
||||
/** Toast 统一管理工具。 */
|
||||
object ToastUtil {
|
||||
|
||||
var isShow = true
|
||||
|
||||
private var toast: Toast? = null
|
||||
|
||||
fun showShort(context: Context, message: CharSequence) {
|
||||
show(context, message, Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
fun showShort(context: Context, message: Int) {
|
||||
show(context, message.toString(), Toast.LENGTH_SHORT)
|
||||
}
|
||||
|
||||
fun showLong(context: Context, message: CharSequence) {
|
||||
show(context, message, Toast.LENGTH_LONG)
|
||||
}
|
||||
|
||||
fun showLong(context: Context, message: Int) {
|
||||
show(context, message.toString(), Toast.LENGTH_LONG)
|
||||
}
|
||||
|
||||
fun show(context: Context, message: CharSequence, duration: Int) {
|
||||
val currentToast = toast
|
||||
if (currentToast == null) {
|
||||
toast = Toast.makeText(context, message, duration)
|
||||
} else {
|
||||
currentToast.setText(message)
|
||||
currentToast.duration = duration
|
||||
}
|
||||
toast?.show()
|
||||
}
|
||||
|
||||
fun show(context: Context, message: Int, duration: Int) {
|
||||
show(context, message.toString(), duration)
|
||||
}
|
||||
}
|
||||
20
app/src/main/java/com/juhabi/birds/util/click/ClickUtil.kt
Normal file
20
app/src/main/java/com/juhabi/birds/util/click/ClickUtil.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package com.juhabi.birds.util.click
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.view.TouchDelegate
|
||||
import android.view.View
|
||||
|
||||
object ClickUtil {
|
||||
/** 将 [view] 的触摸区域向四周分别扩大 [size] 像素。 */
|
||||
@JvmStatic
|
||||
fun addClickPart(view: View, size: Int) {
|
||||
val parent = view.parent as? View ?: return
|
||||
val expandSize = size.coerceAtLeast(0)
|
||||
parent.post {
|
||||
val delegateArea = Rect()
|
||||
view.getHitRect(delegateArea)
|
||||
delegateArea.inset(-expandSize, -expandSize)
|
||||
parent.touchDelegate = TouchDelegate(delegateArea, view)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.juhabi.birds.util.data
|
||||
|
||||
import java.time.DateTimeException
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.ResolverStyle
|
||||
|
||||
/** 校验中国大陆地区的 15 位和 18 位居民身份证号码。 */
|
||||
object IDCardValidate {
|
||||
private val weights = intArrayOf(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2)
|
||||
private val verifyCodes = charArrayOf('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2')
|
||||
private val areaCodes = setOf(
|
||||
"11", "12", "13", "14", "15",
|
||||
"21", "22", "23",
|
||||
"31", "32", "33", "34", "35", "36", "37",
|
||||
"41", "42", "43", "44", "45", "46",
|
||||
"50", "51", "52", "53", "54",
|
||||
"61", "62", "63", "64", "65",
|
||||
"71", "81", "82", "91"
|
||||
)
|
||||
private val birthDateFormatter = DateTimeFormatter
|
||||
.ofPattern("uuuuMMdd")
|
||||
.withResolverStyle(ResolverStyle.STRICT)
|
||||
private val earliestBirthDate = LocalDate.of(1900, 1, 1)
|
||||
|
||||
@JvmStatic
|
||||
fun validate_effective(idcardNumber: String?): Boolean = validateEffective(idcardNumber)
|
||||
|
||||
/**
|
||||
* 为兼容 Water 项目而保留,第二个参数不会影响校验结果。
|
||||
*/
|
||||
@JvmStatic
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun validate_effective(idcardNumber: String?, isreturn_AutoCard: Boolean): Boolean =
|
||||
validateEffective(idcardNumber)
|
||||
|
||||
@JvmStatic
|
||||
fun validateEffective(idCardNumber: String?): Boolean {
|
||||
val source = idCardNumber?.trim()?.uppercase() ?: return false
|
||||
val cardNumber = when (source.length) {
|
||||
OLD_CARD_NUMBER_LENGTH -> convertToNewCardNumber(source) ?: return false
|
||||
NEW_CARD_NUMBER_LENGTH -> source
|
||||
else -> return false
|
||||
}
|
||||
|
||||
if (!cardNumber.take(17).all(Char::isDigit)) return false
|
||||
if (cardNumber.last() != 'X' && !cardNumber.last().isDigit()) return false
|
||||
if (cardNumber.substring(0, 2) !in areaCodes) return false
|
||||
if (!hasValidBirthDate(cardNumber.substring(6, 14))) return false
|
||||
return cardNumber.last() == calculateVerifyCode(cardNumber)
|
||||
}
|
||||
|
||||
private fun convertToNewCardNumber(oldCardNumber: String): String? {
|
||||
if (!oldCardNumber.all(Char::isDigit)) return null
|
||||
val firstSeventeen = buildString(17) {
|
||||
append(oldCardNumber, 0, 6)
|
||||
append("19")
|
||||
append(oldCardNumber, 6, oldCardNumber.length)
|
||||
}
|
||||
return firstSeventeen + calculateVerifyCode(firstSeventeen)
|
||||
}
|
||||
|
||||
private fun hasValidBirthDate(value: String): Boolean {
|
||||
val birthDate = try {
|
||||
LocalDate.parse(value, birthDateFormatter)
|
||||
} catch (_: DateTimeException) {
|
||||
return false
|
||||
}
|
||||
return birthDate.isAfter(earliestBirthDate) && birthDate.isBefore(LocalDate.now())
|
||||
}
|
||||
|
||||
private fun calculateVerifyCode(cardNumber: CharSequence): Char {
|
||||
val sum = weights.indices.sumOf { index ->
|
||||
(cardNumber[index] - '0') * weights[index]
|
||||
}
|
||||
return verifyCodes[sum % 11]
|
||||
}
|
||||
|
||||
private const val NEW_CARD_NUMBER_LENGTH = 18
|
||||
private const val OLD_CARD_NUMBER_LENGTH = 15
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.juhabi.birds.util.data
|
||||
|
||||
object PhonePatternUtil {
|
||||
private val phonePattern = Regex("^1[3-9]\\d{9}$")
|
||||
|
||||
@JvmStatic
|
||||
fun phoneReg(phoneNumber: String?): Boolean = isValidPhoneNumber(phoneNumber)
|
||||
|
||||
/** 校验中国大陆地区的 11 位手机号码。 */
|
||||
@JvmStatic
|
||||
fun isValidPhoneNumber(phoneNumber: String?): Boolean =
|
||||
phoneNumber != null && phonePattern.matches(phoneNumber)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.juhabi.birds.util.file
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.core.content.FileProvider
|
||||
import java.io.File
|
||||
|
||||
object PreviewFileUtil {
|
||||
@JvmStatic
|
||||
fun previewFiles(context: Context, suffix: String?, fileUrl: String?): Boolean {
|
||||
if (fileUrl.isNullOrBlank()) return false
|
||||
val uri = when {
|
||||
fileUrl.startsWith("content://", ignoreCase = true) -> Uri.parse(fileUrl)
|
||||
fileUrl.startsWith("http://", ignoreCase = true) ||
|
||||
fileUrl.startsWith("https://", ignoreCase = true) -> Uri.parse(fileUrl)
|
||||
else -> fileToContentUri(context, File(fileUrl)) ?: return false
|
||||
}
|
||||
return preview(context, uri, resolveMimeType(suffix, uri))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun preview(context: Context, uri: Uri, mimeType: String? = null): Boolean {
|
||||
val resolvedMimeType = mimeType
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: context.contentResolver.getType(uri)
|
||||
?: resolveMimeType(null, uri)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
.setDataAndType(uri, resolvedMimeType)
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
if (context !is Activity) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
return try {
|
||||
context.startActivity(Intent.createChooser(intent, null).apply {
|
||||
if (context !is Activity) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
})
|
||||
true
|
||||
} catch (_: ActivityNotFoundException) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun fileToContentUri(context: Context, file: File): Uri? {
|
||||
if (!file.exists() || !file.isFile) return null
|
||||
return try {
|
||||
FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveMimeType(suffix: String?, uri: Uri): String {
|
||||
val extension = suffix
|
||||
?.substringAfterLast('.')
|
||||
?.trim()
|
||||
?.lowercase()
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?: MimeTypeMap.getFileExtensionFromUrl(uri.toString()).lowercase()
|
||||
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
|
||||
?: DEFAULT_MIME_TYPE
|
||||
}
|
||||
|
||||
private const val DEFAULT_MIME_TYPE = "*/*"
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.juhabi.birds.util.manager
|
||||
|
||||
import android.app.Activity
|
||||
import java.util.Collections
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
object ActivityManager {
|
||||
private val activities = Collections.synchronizedMap(LinkedHashMap<String, Activity>())
|
||||
|
||||
/** 返回 Activity 集合的快照,防止调用方直接修改内部集合。 */
|
||||
@JvmStatic
|
||||
fun getActivitys(): Map<String, Activity> = synchronized(activities) {
|
||||
LinkedHashMap(activities)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getActivity(key: String): Activity? = activities[key]
|
||||
|
||||
@JvmStatic
|
||||
fun addActivity(value: Activity, key: String) {
|
||||
activities[key] = value
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeActivity(key: String) {
|
||||
activities.remove(key)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeAllActivity() {
|
||||
finishAndRemove { _, _ -> true }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeAllActivityExceptMain() {
|
||||
finishAndRemove { key, activity ->
|
||||
!key.contains(MAIN_ACTIVITY_NAME) && activity.javaClass.simpleName != MAIN_ACTIVITY_NAME
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun removeActivityByTag(tag: String) {
|
||||
if (tag.isBlank()) return
|
||||
finishAndRemove { key, _ -> key.contains(tag) }
|
||||
}
|
||||
|
||||
private fun finishAndRemove(predicate: (String, Activity) -> Boolean) {
|
||||
val targets = synchronized(activities) {
|
||||
activities.filter { (key, activity) -> predicate(key, activity) }
|
||||
}
|
||||
targets.forEach { (key, activity) ->
|
||||
if (!activity.isFinishing && !activity.isDestroyed) {
|
||||
activity.runOnUiThread { activity.finish() }
|
||||
}
|
||||
activities.remove(key, activity)
|
||||
}
|
||||
}
|
||||
|
||||
private const val MAIN_ACTIVITY_NAME = "MainActivity"
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.juhabi.birds.util.manager
|
||||
|
||||
import android.content.Context
|
||||
import com.juhabi.birds.MyApplication
|
||||
import com.juhabi.birds.network.TokenManager
|
||||
import com.juhabi.birds.user.model.UserEntity
|
||||
import com.juhabi.birds.util.SharedPreferencesUtil
|
||||
|
||||
/** 管理当前用户的内存缓存和轻量级本地持久化数据。 */
|
||||
object UserInfoManager {
|
||||
@Volatile
|
||||
private var cachedUser: UserEntity? = null
|
||||
|
||||
@JvmStatic
|
||||
fun getInstance(): UserInfoManager = this
|
||||
|
||||
/** 应用启动时恢复本地保存的 token 和用户信息。 */
|
||||
@JvmStatic
|
||||
fun initialize(context: Context) {
|
||||
TokenManager.get(context)
|
||||
cachedUser = SharedPreferencesUtil.getObject(
|
||||
context,
|
||||
KEY_USER_INFO,
|
||||
UserEntity::class.java
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getUserInfo(): UserEntity? = getUserInfo(MyApplication.appContext)
|
||||
|
||||
@JvmStatic
|
||||
fun getUserInfo(context: Context): UserEntity? {
|
||||
cachedUser?.let { return it }
|
||||
return SharedPreferencesUtil.getObject(
|
||||
context,
|
||||
KEY_USER_INFO,
|
||||
UserEntity::class.java
|
||||
)?.also { cachedUser = it }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setUserInfo(userInfo: UserEntity) {
|
||||
setUserInfo(MyApplication.appContext, userInfo)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setUserInfo(context: Context, userInfo: UserEntity) {
|
||||
cachedUser = userInfo
|
||||
SharedPreferencesUtil.putObject(context, KEY_USER_INFO, userInfo)
|
||||
}
|
||||
|
||||
/** 登录成功后统一保存用户信息和 token。 */
|
||||
@JvmStatic
|
||||
fun saveLogin(userInfo: UserEntity, token: String) {
|
||||
saveLogin(MyApplication.appContext, userInfo, token)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun saveLogin(context: Context, userInfo: UserEntity, token: String) {
|
||||
setUserInfo(context, userInfo)
|
||||
TokenManager.save(context, token)
|
||||
SharedPreferencesUtil.putBoolean(context, KEY_USER_LOGIN, token.isNotBlank())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun isLoggedIn(): Boolean = isLoggedIn(MyApplication.appContext)
|
||||
|
||||
@JvmStatic
|
||||
fun isLoggedIn(context: Context): Boolean {
|
||||
val hasToken = TokenManager.get(context).isNotBlank()
|
||||
return hasToken && SharedPreferencesUtil.getBoolean(context, KEY_USER_LOGIN, hasToken)
|
||||
}
|
||||
|
||||
/** 仅清除账号相关数据,不影响应用中的其他本地配置。 */
|
||||
@JvmStatic
|
||||
fun clearUser(context: Context) {
|
||||
cachedUser = null
|
||||
TokenManager.clear(context)
|
||||
SharedPreferencesUtil.remove(context, KEY_USER_INFO)
|
||||
SharedPreferencesUtil.remove(context, KEY_USER_LOGIN)
|
||||
}
|
||||
|
||||
private const val KEY_USER_INFO = "user_info"
|
||||
private const val KEY_USER_LOGIN = "user_login"
|
||||
}
|
||||
Reference in New Issue
Block a user