From f67cf3b81a00f732ca743431258ae6b78f5f40ab Mon Sep 17 00:00:00 2001
From: tj <1378534974@qq.com>
Date: 星期四, 17 四月 2025 15:05:28 +0800
Subject: [PATCH] 11、我的 切换头像 点击切换头像没有显示允许存储权限的窗口,华为的手机目前有 49、首页 实时刷新 点击全部取件或其他分类后,回到上一层,内容没有刷新(5个分类) 52、数据统计 数据统计 1.周月年的柱状图统计逻辑需要修改为只统计快递类的数据 2.按年的图形统计,右下方加上图示说明 53、首页 首页登录 点击用户协议、隐私政策无反应
---
app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt | 10 +
app/src/main/java/com/example/firstapp/ui/profile/EditProfileActivity.kt | 73 ++++++++++--
app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt | 151 +++++++++++++++++++++++++
app/src/main/AndroidManifest.xml | 3
app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt | 14 +-
app/src/main/res/layout/layout_week_stats.xml | 26 ++--
app/src/main/java/com/example/firstapp/activity/LoginActivity.kt | 2
app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt | 34 ++++-
8 files changed, 273 insertions(+), 40 deletions(-)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 17c8460..4004bcd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -72,6 +72,9 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <!-- 允许语言识别。 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <!-- Android 13 及以上 -->
+ <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
+
<application
android:name=".App"
android:allowBackup="true"
diff --git a/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt b/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt
index 36ac653..fcb8a6b 100644
--- a/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt
+++ b/app/src/main/java/com/example/firstapp/activity/LoginActivity.kt
@@ -55,10 +55,12 @@
binding.tvUserAgreement.setOnClickListener {
// 打开用户协议
+ startContentActivity("用户协议", "服务使用协议")
}
binding.tvPrivacyPolicy.setOnClickListener {
// 打开隐私政策
+ startContentActivity("隐私协议", "隐私保护政策")
}
}
diff --git a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
index c3b0d52..e63ba6a 100644
--- a/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
+++ b/app/src/main/java/com/example/firstapp/database/dao/CodeDao.kt
@@ -202,7 +202,7 @@
CAST(strftime('%W', dates.date) AS INTEGER) as weekOfYear,
COUNT(code.id) as count
FROM dates
- LEFT JOIN code ON date(code.createTime) = dates.date
+ LEFT JOIN code ON date(code.createTime) = dates.date and code.category='快递'
GROUP BY dates.date
ORDER BY dates.date
""")
@@ -237,12 +237,12 @@
)
SELECT
strftime('%m', month_start) as date,
- COUNT(code.id) as count,
+ COUNT(c.id) as count,
strftime('%Y-%m-%d', month_start) as weekStart
- FROM months
- LEFT JOIN code ON strftime('%Y-%m', code.createTime) = strftime('%Y-%m', months.month_start)
- GROUP BY months.month_start
- ORDER BY months.month_start ASC
+ FROM months m
+ LEFT JOIN code c ON strftime('%Y-%m', c.createTime) = strftime('%Y-%m', m.month_start) and c.category='快递'
+ GROUP BY m.month_start
+ ORDER BY m.month_start ASC
""")
fun getYearMonthlyStats(date: Long): Flow<List<DailyStat>>
@@ -335,7 +335,7 @@
COUNT(c.id) AS count,
'' AS weekStart
FROM dates d
- LEFT JOIN code c ON date(c.createTime) = d.date_value
+ LEFT JOIN code c ON date(c.createTime) = d.date_value and c.category='快递'
GROUP BY d.date_value
ORDER BY d.date_value ASC
""")
diff --git a/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
index 0c5316d..b689d58 100644
--- a/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
@@ -21,7 +21,9 @@
import java.util.*
import java.text.SimpleDateFormat
import android.graphics.Color
+import android.view.Gravity
import android.widget.GridLayout
+import android.widget.LinearLayout
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.lifecycle.lifecycleScope
@@ -767,6 +769,153 @@
// 创建52周x7天的数据矩阵
val heatmapMatrix = Array(7) { IntArray(52) }
+
+ // 填充数据
+ stats.forEach { stat ->
+ val week = stat.weekOfYear - 1 // 0-51
+ val dayOfWeek = stat.dayOfWeek - 1 // 0-6
+ if (week in 0..51 && dayOfWeek in 0..6) {
+ heatmapMatrix[dayOfWeek][week] = stat.count
+ }
+ }
+
+ // 更新UI
+ binding.layoutWeekStats.heatmapYearly.apply {
+ removeAllViews()
+
+ val gridLayout = GridLayout(context).apply {
+ rowCount = 8 // 1行月份 + 7行星期
+ columnCount = 53 // 1列星期 + 52列周数
+ }
+
+ // 添加月份标签
+ val months = arrayOf("1月", "2月", "3月", "4月", "5月", "6月",
+ "7月", "8月", "9月", "10月", "11月", "12月")
+ months.forEachIndexed { index, month ->
+ val label = TextView(context).apply {
+ text = month
+ textSize = 10f
+ setPadding(0, 0, 8, 4)
+ val weekPosition = (index * 4.3).toInt() // 估算月份起始位置
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(weekPosition + 1)
+ rowSpec = GridLayout.spec(0)
+ }
+ }
+ gridLayout.addView(label)
+ }
+
+ // 添加星期标签
+ val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
+ dayLabels.forEachIndexed { index, label ->
+ val textView = TextView(context).apply {
+ text = label
+ textSize = 10f
+ setPadding(4, 0, 8, 0)
+ layoutParams = GridLayout.LayoutParams().apply {
+ columnSpec = GridLayout.spec(0)
+ rowSpec = GridLayout.spec(index + 1)
+ }
+ }
+ gridLayout.addView(textView)
+ }
+
+ // 添加热力图单元格
+ for (day in 0..6) {
+ for (week in 0..51) {
+ val count = heatmapMatrix[day][week]
+ val cell = View(context).apply {
+ layoutParams = GridLayout.LayoutParams().apply {
+ width = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ columnSpec = GridLayout.spec(week + 1)
+ rowSpec = GridLayout.spec(day + 1)
+ setMargins(1, 1, 1, 1)
+ }
+ setBackgroundColor(getHeatmapColor(count))
+ }
+ gridLayout.addView(cell)
+ }
+ }
+
+ // 创建图例(Legend)
+ val legendLayout = LinearLayout(context).apply {
+ orientation = LinearLayout.HORIZONTAL
+ gravity = Gravity.END or Gravity.CENTER_VERTICAL // 靠右对齐
+ setPadding(8, 16, 8, 0)
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
+ // 左侧“少”标签
+ val labelLow = TextView(context).apply {
+ text = "少"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+ legendLayout.addView(labelLow)
+
+ // 渐变色块 + 数值
+ val legendLevels = listOf(0, 5, 10, 15, 20)
+ legendLevels.forEach { level ->
+ val colorBox = View(context).apply {
+ setBackgroundColor(getHeatmapColor(level))
+ val size = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
+ layoutParams = LinearLayout.LayoutParams(size, size).apply {
+ marginEnd = 4
+ }
+ }
+
+ val label = TextView(context).apply {
+// text = "$level"
+ textSize = 10f
+ setPadding(0, 0, 8, 0)
+ }
+
+ legendLayout.addView(colorBox)
+ legendLayout.addView(label)
+ }
+
+ // 右侧“多”标签
+ val labelHigh = TextView(context).apply {
+ text = "多"
+ textSize = 10f
+ setPadding(8, 0, 0, 0)
+ }
+ legendLayout.addView(labelHigh)
+
+ // 垂直组合 gridLayout + legendLayout
+ val container = LinearLayout(context).apply {
+ orientation = LinearLayout.VERTICAL
+ addView(gridLayout)
+ addView(legendLayout)
+ }
+
+ addView(container)
+ }
+ }
+ }
+
+ private fun getHeatmapColor(count: Int): Int {
+ return when {
+ count == 0 -> Color.parseColor("#EBECF1") // 最淡
+ count < 5 -> Color.parseColor("#ACE7B1")
+ count < 10 -> Color.parseColor("#68C16F")
+ count < 15 -> Color.parseColor("#529F57")
+ else -> Color.parseColor("#356D40") // 最深
+ }
+ }
+
+
+
+ private fun updateHeatmapData_bak() {
+ viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
+ if (stats.isEmpty()) return@observe
+
+ // 创建52周x7天的数据矩阵
+ val heatmapMatrix = Array(7) { IntArray(52) }
// 填充数据
stats.forEach { stat ->
@@ -843,7 +992,7 @@
}
}
- private fun getHeatmapColor(count: Int): Int {
+ private fun getHeatmapColor_bak(count: Int): Int {
return when {
count == 0 -> Color.parseColor("#EBEDF0")
count == 1 -> Color.parseColor("#9BE9A8")
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
index 03440a8..d86a5c4 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeFragment.kt
@@ -124,6 +124,7 @@
}
}
+
private fun setupAdapters() {
binding.expressRecycler.apply {
layoutManager = LinearLayoutManager(context)
@@ -438,9 +439,16 @@
)
// 加载数据
- homeViewModel.loadExpressData()
+ homeViewModel.loadAllCategoryData()
+// homeViewModel.loadExpressData()
+// homeViewModel.loadFinanceData()
+// homeViewModel.loadIncomeData()
+// homeViewModel.loadFlightData()
+// homeViewModel.loadTrainData()
+
// 检查未读提醒数量
homeViewModel.checkUnreadReminders()
+
}
override fun onPause() {
diff --git a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
index b367f26..e1357b3 100644
--- a/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
+++ b/app/src/main/java/com/example/firstapp/ui/home/HomeViewModel.kt
@@ -192,17 +192,37 @@
loadDataByType("火车票")
}
+
+ fun loadAllCategoryData() {
+ getFullCategories().forEach { category ->
+ loadDataByType(category.name)
+ }
+ }
+
+
+ fun getFullCategories(): List<CategoryConfig> {
+ return listOf(
+ CategoryConfig(1, "快递", 0, true),
+ CategoryConfig(2, "还款", 1, true),
+ CategoryConfig(3, "收入", 2, true),
+ CategoryConfig(4, "航班", 3, true),
+ CategoryConfig(5, "火车票", 4, true)
+ )
+ }
+
private fun loadCategories() {
viewModelScope.launch {
try {
// 默认完整分类列表
- val fullCategories = listOf(
- CategoryConfig(1, "快递", 0, true),
- CategoryConfig(2, "还款", 1, true),
- CategoryConfig(3, "收入", 2, true),
- CategoryConfig(4, "航班", 3, true),
- CategoryConfig(5, "火车票", 4, true)
- )
+// val fullCategories = listOf(
+// CategoryConfig(1, "快递", 0, true),
+// CategoryConfig(2, "还款", 1, true),
+// CategoryConfig(3, "收入", 2, true),
+// CategoryConfig(4, "航班", 3, true),
+// CategoryConfig(5, "火车票", 4, true)
+// )
+
+ val fullCategories=getFullCategories()
// 基础分类(非会员可见)
val basicCategories = listOf(
diff --git a/app/src/main/java/com/example/firstapp/ui/profile/EditProfileActivity.kt b/app/src/main/java/com/example/firstapp/ui/profile/EditProfileActivity.kt
index a7f4af1..608eef6 100644
--- a/app/src/main/java/com/example/firstapp/ui/profile/EditProfileActivity.kt
+++ b/app/src/main/java/com/example/firstapp/ui/profile/EditProfileActivity.kt
@@ -36,15 +36,41 @@
private var selectedImageUri: Uri? = null
private var loadingDialog: AlertDialog? = null
- private val pickImage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
- if (result.resultCode == Activity.RESULT_OK) {
- result.data?.data?.let { uri ->
- selectedImageUri = uri
- Glide.with(this)
- .load(uri)
- .circleCrop()
- .into(binding.ivAvatar)
- }
+// private val pickImage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+// if (result.resultCode == Activity.RESULT_OK) {
+// result.data?.data?.let { uri ->
+// selectedImageUri = uri
+// Glide.with(this)
+// .load(uri)
+// .circleCrop()
+// .into(binding.ivAvatar)
+// }
+// }
+// }
+
+ private val pickImageLauncher = registerForActivityResult(
+ ActivityResultContracts.GetContent()
+ ) { uri: Uri? ->
+ uri?.let {
+ selectedImageUri = uri
+ // 这里直接处理选中的头像
+ Glide.with(this)
+ .load(it)
+ .into(binding.ivAvatar) // 替换成你的 ImageView id
+
+ // 如果需要上传可以用 contentResolver.openInputStream(uri)
+ }
+ }
+
+
+ // 👇 就放在这里
+ private val permissionLauncher = registerForActivityResult(
+ ActivityResultContracts.RequestPermission()
+ ) { isGranted: Boolean ->
+ if (isGranted) {
+ openGallery()
+ } else {
+ Toast.makeText(this, "需要权限才能选择头像", Toast.LENGTH_SHORT).show()
}
}
@@ -78,13 +104,29 @@
}
binding.ivAvatar.setOnClickListener {
- checkAndRequestPermission()
+// checkAndRequestPermission()
+ checkStoragePermission()
}
binding.btnSaveBottom.setOnClickListener {
saveAndFinish()
}
}
+
+ fun checkStoragePermission() {
+ val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ Manifest.permission.READ_MEDIA_IMAGES
+ } else {
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ }
+
+ if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
+ permissionLauncher.launch(permission)
+ } else {
+ openGallery()
+ }
+ }
+
private fun saveAndFinish() {
lifecycleScope.launch {
@@ -194,9 +236,16 @@
}
}
- private fun openGallery() {
+ private fun openGallery_bak() {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
- pickImage.launch(intent)
+// pickImage.launch(intent)
+ }
+
+ private fun openGallery() {
+ pickImageLauncher.launch("image/*")
+// val intent = Intent(Intent.ACTION_PICK)
+// intent.type = "image/*"
+// startActivityForResult(intent, 1001)
}
private fun showLoading() {
diff --git a/app/src/main/res/layout/layout_week_stats.xml b/app/src/main/res/layout/layout_week_stats.xml
index 2499968..a328499 100644
--- a/app/src/main/res/layout/layout_week_stats.xml
+++ b/app/src/main/res/layout/layout_week_stats.xml
@@ -43,20 +43,22 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
- android:layout_marginBottom="16dp">
+ android:layout_marginBottom="16dp"
+ android:padding="16dp"
+ >
- <HorizontalScrollView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="16dp">
+<!-- <HorizontalScrollView-->
+<!-- android:layout_width="match_parent"-->
+<!-- android:layout_height="wrap_content"-->
+<!-- android:padding="16dp">-->
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <!-- 热力图将在这里动态添加 -->
- </LinearLayout>
- </HorizontalScrollView>
+<!-- <LinearLayout-->
+<!-- android:layout_width="wrap_content"-->
+<!-- android:layout_height="wrap_content"-->
+<!-- android:orientation="horizontal">-->
+<!-- <!– 热力图将在这里动态添加 –>-->
+<!-- </LinearLayout>-->
+<!-- </HorizontalScrollView>-->
</androidx.cardview.widget.CardView>
--
Gitblit v1.9.3