feat: 小趣手表APP Android原生重构 - 基础框架搭建
已完成的模块: 1. 项目脚手架 - Gradle配置、28个包目录、核心基类 2. 权限管理 - 确认定制ROM已预授权所有权限 3. 工具类 - DateUtil/DeviceUtil/NetworkUtil/Md5Util 4. 设备信息 - DevicePrefs/UserPrefs (SharedPreferences) 5. 网络层 - OkHttp+Retrofit+MD5签名拦截器+解绑拦截器 6. 基础UI组件 - NavBarView/QuTipDialog/QuConfirmDialog/ActionButton/iconfont Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
78
app/src/main/java/com/xiaoqu/watch/util/DateUtil.kt
Normal file
78
app/src/main/java/com/xiaoqu/watch/util/DateUtil.kt
Normal file
@@ -0,0 +1,78 @@
|
||||
package com.xiaoqu.watch.util
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* 日期格式化工具
|
||||
* 对应旧版 commonUtil.js 的 getDateTime()
|
||||
*/
|
||||
object DateUtil {
|
||||
|
||||
private val weekNames = arrayOf("周日", "周一", "周二", "周三", "周四", "周五", "周六")
|
||||
|
||||
private val formatDateTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
|
||||
private val formatDate = SimpleDateFormat("MM月dd日", Locale.CHINA)
|
||||
private val formatTime = SimpleDateFormat("HH:mm:ss", Locale.CHINA)
|
||||
private val formatTimeShort = SimpleDateFormat("HH:mm", Locale.CHINA)
|
||||
|
||||
/** 完整日期时间:2026-04-24 20:15:30 */
|
||||
fun formatDateTime(timestamp: Long = System.currentTimeMillis()): String {
|
||||
return formatDateTime.format(Date(timestamp))
|
||||
}
|
||||
|
||||
/** 月日:04月24日 */
|
||||
fun formatDate(timestamp: Long = System.currentTimeMillis()): String {
|
||||
return formatDate.format(Date(timestamp))
|
||||
}
|
||||
|
||||
/** 时分秒:20:15:30 */
|
||||
fun formatTime(timestamp: Long = System.currentTimeMillis()): String {
|
||||
return formatTime.format(Date(timestamp))
|
||||
}
|
||||
|
||||
/** 时分:20:15 */
|
||||
fun formatTimeShort(timestamp: Long = System.currentTimeMillis()): String {
|
||||
return formatTimeShort.format(Date(timestamp))
|
||||
}
|
||||
|
||||
/** 星期:周四 */
|
||||
fun getWeekDay(timestamp: Long = System.currentTimeMillis()): String {
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = timestamp
|
||||
return weekNames[calendar.get(Calendar.DAY_OF_WEEK) - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整日期信息(对应旧版 getDateTime() 返回对象)
|
||||
*/
|
||||
fun getDateInfo(timestamp: Long = System.currentTimeMillis()): DateInfo {
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = timestamp
|
||||
return DateInfo(
|
||||
date = formatDate(timestamp),
|
||||
time = formatTime(timestamp),
|
||||
week = weekNames[calendar.get(Calendar.DAY_OF_WEEK) - 1],
|
||||
year = calendar.get(Calendar.YEAR),
|
||||
month = calendar.get(Calendar.MONTH) + 1,
|
||||
day = calendar.get(Calendar.DAY_OF_MONTH),
|
||||
hour = calendar.get(Calendar.HOUR_OF_DAY),
|
||||
minute = calendar.get(Calendar.MINUTE),
|
||||
second = calendar.get(Calendar.SECOND)
|
||||
)
|
||||
}
|
||||
|
||||
data class DateInfo(
|
||||
val date: String,
|
||||
val time: String,
|
||||
val week: String,
|
||||
val year: Int,
|
||||
val month: Int,
|
||||
val day: Int,
|
||||
val hour: Int,
|
||||
val minute: Int,
|
||||
val second: Int
|
||||
)
|
||||
}
|
||||
116
app/src/main/java/com/xiaoqu/watch/util/DeviceUtil.kt
Normal file
116
app/src/main/java/com/xiaoqu/watch/util/DeviceUtil.kt
Normal file
@@ -0,0 +1,116 @@
|
||||
package com.xiaoqu.watch.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ActivityManager
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.telephony.TelephonyManager
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* 设备信息工具
|
||||
* 对应旧版 deviceInfoUtil.js 的 getDevice()
|
||||
*/
|
||||
object DeviceUtil {
|
||||
|
||||
/** 设备品牌 */
|
||||
fun getBrand(): String = Build.BRAND
|
||||
|
||||
/** 设备型号 */
|
||||
fun getModel(): String = Build.MODEL
|
||||
|
||||
/** 系统版本 */
|
||||
fun getOsVersion(): String = Build.VERSION.RELEASE
|
||||
|
||||
/** 设备序列号 */
|
||||
@SuppressLint("HardwareIds")
|
||||
fun getSerial(): String {
|
||||
return try {
|
||||
Build.SERIAL ?: ""
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "获取序列号失败")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
/** 设备 IMEI(需要 READ_PHONE_STATE 权限) */
|
||||
@SuppressLint("HardwareIds", "MissingPermission")
|
||||
fun getImei(context: Context): String {
|
||||
return try {
|
||||
val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
||||
@Suppress("DEPRECATION")
|
||||
tm.deviceId ?: ""
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "获取IMEI失败")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
/** 蓝牙适配器名称 */
|
||||
@SuppressLint("HardwareIds")
|
||||
fun getBluetoothName(): String {
|
||||
return try {
|
||||
BluetoothAdapter.getDefaultAdapter()?.name ?: ""
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "获取蓝牙名称失败")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
/** 蓝牙 MAC 地址 */
|
||||
@SuppressLint("HardwareIds")
|
||||
fun getBluetoothMac(): String {
|
||||
return try {
|
||||
BluetoothAdapter.getDefaultAdapter()?.address ?: ""
|
||||
} catch (e: Exception) {
|
||||
Timber.w(e, "获取蓝牙MAC失败")
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
/** 总内存(MB) */
|
||||
fun getTotalMemory(context: Context): Long {
|
||||
val memInfo = ActivityManager.MemoryInfo()
|
||||
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
am.getMemoryInfo(memInfo)
|
||||
return memInfo.totalMem / (1024 * 1024)
|
||||
}
|
||||
|
||||
/** 可用内存(MB) */
|
||||
fun getAvailableMemory(context: Context): Long {
|
||||
val memInfo = ActivityManager.MemoryInfo()
|
||||
val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
am.getMemoryInfo(memInfo)
|
||||
return memInfo.availMem / (1024 * 1024)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整设备信息(对应旧版 watchInfo 对象)
|
||||
*/
|
||||
fun getDeviceInfo(context: Context): DeviceInfo {
|
||||
return DeviceInfo(
|
||||
brand = getBrand(),
|
||||
model = getModel(),
|
||||
osVersion = getOsVersion(),
|
||||
serial = getSerial(),
|
||||
imei = getImei(context),
|
||||
bluetoothName = getBluetoothName(),
|
||||
bluetoothMac = getBluetoothMac(),
|
||||
totalMemory = getTotalMemory(context),
|
||||
availableMemory = getAvailableMemory(context)
|
||||
)
|
||||
}
|
||||
|
||||
data class DeviceInfo(
|
||||
val brand: String,
|
||||
val model: String,
|
||||
val osVersion: String,
|
||||
val serial: String,
|
||||
val imei: String,
|
||||
val bluetoothName: String,
|
||||
val bluetoothMac: String,
|
||||
val totalMemory: Long,
|
||||
val availableMemory: Long
|
||||
)
|
||||
}
|
||||
22
app/src/main/java/com/xiaoqu/watch/util/Md5Util.kt
Normal file
22
app/src/main/java/com/xiaoqu/watch/util/Md5Util.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.xiaoqu.watch.util
|
||||
|
||||
import java.security.MessageDigest
|
||||
|
||||
/**
|
||||
* MD5 哈希工具
|
||||
* 对应旧版 md5.js 的 hex_md5(),用于 API 请求签名
|
||||
*/
|
||||
object Md5Util {
|
||||
|
||||
/** 计算字符串的 MD5 哈希值(小写 hex) */
|
||||
fun md5(input: String): String {
|
||||
val digest = MessageDigest.getInstance("MD5")
|
||||
val bytes = digest.digest(input.toByteArray())
|
||||
return bytes.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
/** 计算字符串的 MD5 哈希值(大写 hex) */
|
||||
fun md5Upper(input: String): String {
|
||||
return md5(input).uppercase()
|
||||
}
|
||||
}
|
||||
49
app/src/main/java/com/xiaoqu/watch/util/NetworkUtil.kt
Normal file
49
app/src/main/java/com/xiaoqu/watch/util/NetworkUtil.kt
Normal file
@@ -0,0 +1,49 @@
|
||||
package com.xiaoqu.watch.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkInfo
|
||||
|
||||
/**
|
||||
* 网络状态检测工具
|
||||
* 对应旧版 systemUtil.js 的 getNetWorkAvailable()
|
||||
*/
|
||||
object NetworkUtil {
|
||||
|
||||
/** 网络是否可用 */
|
||||
@Suppress("DEPRECATION")
|
||||
fun isNetworkAvailable(context: Context): Boolean {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
|
||||
return activeNetwork?.isConnected == true
|
||||
}
|
||||
|
||||
/** 是否连接 WiFi */
|
||||
@Suppress("DEPRECATION")
|
||||
fun isWifiConnected(context: Context): Boolean {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
|
||||
return wifiInfo?.isConnected == true
|
||||
}
|
||||
|
||||
/** 是否连接移动数据(4G) */
|
||||
@Suppress("DEPRECATION")
|
||||
fun isMobileConnected(context: Context): Boolean {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val mobileInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
|
||||
return mobileInfo?.isConnected == true
|
||||
}
|
||||
|
||||
/** 获取当前网络类型描述 */
|
||||
@Suppress("DEPRECATION")
|
||||
fun getNetworkTypeName(context: Context): String {
|
||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
|
||||
return when {
|
||||
activeNetwork == null || !activeNetwork.isConnected -> "无网络"
|
||||
activeNetwork.type == ConnectivityManager.TYPE_WIFI -> "WiFi"
|
||||
activeNetwork.type == ConnectivityManager.TYPE_MOBILE -> "移动数据"
|
||||
else -> "其他"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user