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:
dongliang
2026-04-27 11:26:50 +09:30
commit a397985954
89 changed files with 3211 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- MainActivity 布局NavBar 已移入各 Fragment 自行管理
只保留 NavHostFragment主内容和 dialog_container全局弹窗层 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
tools:context=".app.MainActivity">
<!-- Layer 1: 主内容区NavHostFragment -->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_main" />
<!-- Layer 2: 全局弹窗层QuTipDialog / QuConfirmDialog 动态添加,默认隐藏) -->
<FrameLayout
android:id="@+id/dialog_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- QuConfirmDialog 布局:确认弹窗
结构:半透明遮罩 + 居中内容区 + 底部取消(×)/确认(✓)图标按钮 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/confirmOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/overlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/spacing_lg">
<!-- 内容区域(由调用方动态设置) -->
<FrameLayout
android:id="@+id/confirmContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_xl" />
<!-- 底部按钮组(取消 × / 确认 ✓) -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<!-- 取消按钮(×) -->
<TextView
android:id="@+id/btnCancel"
android:layout_width="60dp"
android:layout_height="60dp"
android:gravity="center"
android:text="\ue623"
android:textColor="@color/text_secondary"
android:textSize="36sp"
android:layout_marginEnd="@dimen/spacing_xl" />
<!-- 确认按钮(✓) -->
<TextView
android:id="@+id/btnConfirm"
android:layout_width="60dp"
android:layout_height="60dp"
android:gravity="center"
android:text="\ue600"
android:textColor="@color/success"
android:textSize="36sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- QuTipDialog 布局:提示弹窗(成功/警告/错误)
结构:全屏遮罩 + 居中内容(图标 + 标题 + 描述 + 倒计时返回按钮) -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/spacing_lg">
<!-- 状态图标(成功✓ / 警告! / 错误×) -->
<TextView
android:id="@+id/tipIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="48sp"
android:layout_marginBottom="@dimen/spacing_md" />
<!-- 标题文字 -->
<TextView
android:id="@+id/tipTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_primary"
android:textSize="@dimen/text_title"
android:textStyle="bold"
android:layout_marginBottom="@dimen/spacing_sm" />
<!-- 描述文字(可选) -->
<TextView
android:id="@+id/tipDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_secondary"
android:textSize="@dimen/text_caption"
android:gravity="center"
android:visibility="gone"
android:layout_marginBottom="@dimen/spacing_lg" />
<!-- 倒计时返回按钮(显示"返回 3s" -->
<TextView
android:id="@+id/tipBackBtn"
android:layout_width="@dimen/touch_min_size"
android:layout_height="@dimen/touch_min_size"
android:gravity="center"
android:textColor="@color/text_secondary"
android:textSize="@dimen/text_caption"
android:visibility="gone" />
</LinearLayout>
</FrameLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<!-- TODO: 二维码 + 设备信息 -->
</FrameLayout>

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 首页布局NavBar + 内容区 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:orientation="vertical">
<!-- 顶部导航栏(首页模式:状态图标 + 时间 + 电量) -->
<include layout="@layout/layout_nav_bar" />
<!-- 内容区域 -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/safe_area_left"
android:paddingEnd="@dimen/safe_area_right"
android:paddingBottom="@dimen/safe_area_bottom">
<!-- demo 信息展示 -->
<TextView
android:id="@+id/tvDemoInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_primary"
android:textSize="@dimen/text_small"
android:lineSpacingExtra="3dp"
android:layout_marginBottom="@dimen/spacing_md" />
<!-- 按钮 demo触发 QuTipDialog -->
<TextView
android:id="@+id/btnShowTip"
style="@style/ActionButton.Primary"
android:text="显示提示弹窗"
android:layout_marginBottom="@dimen/spacing_sm" />
<!-- 按钮 demo触发 QuConfirmDialog -->
<TextView
android:id="@+id/btnShowConfirm"
style="@style/ActionButton.Success"
android:text="显示确认弹窗"
android:layout_marginBottom="@dimen/spacing_sm" />
<!-- 按钮 demo其他样式展示 -->
<TextView
android:id="@+id/btnDanger"
style="@style/ActionButton.Danger"
android:text="危险按钮"
android:layout_marginBottom="@dimen/spacing_sm" />
<TextView
android:id="@+id/btnWarning"
style="@style/ActionButton.Warning"
android:text="警告按钮"
android:layout_marginBottom="@dimen/spacing_sm" />
<TextView
android:id="@+id/btnGrey"
style="@style/ActionButton.Grey"
android:text="灰色按钮"
android:layout_marginBottom="@dimen/spacing_sm" />
<!-- 半宽按钮并排 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
style="@style/ActionButton.Grey"
android:layout_width="0dp"
android:layout_weight="1"
android:text="取消"
android:layout_marginEnd="@dimen/spacing_sm" />
<TextView
style="@style/ActionButton.Primary"
android:layout_width="0dp"
android:layout_weight="1"
android:text="确定" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<!-- TODO: 设备信息展示 -->
</FrameLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<!-- TODO: 打卡操作界面 -->
</FrameLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<!-- TODO: 任务详情 + 操作按钮 -->
</FrameLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background">
<!-- TODO: RecyclerView 任务列表 -->
</FrameLayout>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- NavBarView顶部导航栏每个 Fragment 通过 <include> 引入
左/中/右三栏布局:
- 首页:左=状态图标(蓝牙/4G/NFC),中=时间,右=电量
- 子页面:左=返回按钮,中=标题,右=电量 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/navBar"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_bar_height"
android:background="@color/background"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="@dimen/safe_area_left"
android:paddingEnd="@dimen/safe_area_right">
<!-- 左侧区域(状态图标 或 返回按钮) -->
<FrameLayout
android:id="@+id/navLeft"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical">
<!-- 返回按钮(子页面用,默认隐藏) -->
<TextView
android:id="@+id/btnBack"
android:layout_width="@dimen/touch_min_size"
android:layout_height="@dimen/touch_min_size"
android:layout_gravity="center_vertical"
android:gravity="center"
android:text="\ue6bd"
android:textColor="@color/text_secondary"
android:textSize="18sp"
android:visibility="gone" />
<!-- 状态图标组(首页用,默认显示) -->
<LinearLayout
android:id="@+id/statusIcons"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<!-- 蓝牙状态 -->
<TextView
android:id="@+id/iconBluetooth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\ue6da"
android:textColor="@color/text_primary"
android:textSize="14sp"
android:paddingEnd="6dp" />
<!-- 4G 状态 -->
<TextView
android:id="@+id/icon4G"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\ue6dc"
android:textColor="@color/text_primary"
android:textSize="14sp"
android:paddingEnd="6dp" />
<!-- NFC 状态 -->
<TextView
android:id="@+id/iconNfc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\ue6d8"
android:textColor="@color/text_primary"
android:textSize="14sp" />
</LinearLayout>
</FrameLayout>
<!-- 中间区域(时间 或 标题) -->
<TextView
android:id="@+id/navTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:ellipsize="end"
android:gravity="center"
android:maxLines="1"
android:textColor="@color/text_primary"
android:textSize="@dimen/text_body" />
<!-- 右侧区域(电量图标) -->
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical|end"
android:orientation="horizontal">
<!-- 电量图标 -->
<TextView
android:id="@+id/iconBattery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\ue6ce"
android:textColor="@color/success"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>