zhujie
9 天以前 acb5be78c07b8499d0a38515b05a4982207c1c9a
app/src/main/java/com/example/firstapp/ui/dashboard/DashboardFragment.kt
@@ -1,37 +1,40 @@
package com.example.firstapp.ui.dashboard
import com.example.firstapp.R
import android.graphics.Color
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebView
import android.widget.GridLayout
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.cardview.widget.CardView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.example.firstapp.databinding.FragmentDashboardBinding
import com.google.android.material.tabs.TabLayout
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.firstapp.R
import com.example.firstapp.adapter.PackageAdapter
import com.example.firstapp.database.response.UserInfo
import com.example.firstapp.database.service.RetrofitClient
import com.example.firstapp.databinding.FragmentDashboardBinding
import com.example.firstapp.model.DailyStat
import com.example.firstapp.utils.PreferencesManager
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.formatter.ValueFormatter
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
import com.example.firstapp.database.response.UserInfo
import com.example.firstapp.database.service.RetrofitClient
import com.example.firstapp.model.DailyStat
import com.example.firstapp.utils.PreferencesManager
import com.google.android.material.tabs.TabLayout
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
class DashboardFragment : Fragment() {
@@ -57,6 +60,7 @@
    }
    private val viewModel: DashboardViewModel by viewModels()
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
@@ -74,6 +78,14 @@
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
//        val webView: WebView = binding.layoutWeekStats.webView
//        val webSettings = webView.settings
//        webSettings.javaScriptEnabled = true // 启用 JavaScript
//
//
//        // 加载本地的 HTML 文件
//        webView.loadUrl("file:///android_asset/calendar-heatmap.html")
        //渲染包裹列表
        setupRecyclerView()
@@ -763,7 +775,242 @@
        heatmapView.visibility = View.GONE
    }
    // 用于创建图例
    private fun createLegend(): LinearLayout {
        val legendLayout = LinearLayout(context).apply {
            orientation = LinearLayout.HORIZONTAL
            gravity = Gravity.END or Gravity.CENTER_VERTICAL
            setPadding(8, 16, 8, 0)
        }
        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 {
                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)
        return legendLayout
    }
    private fun updateHeatmapData() {
        viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
            if (stats.isEmpty()) return@observe
            val heatmapMatrix = Array(7) { IntArray(52) }
            stats.forEach { stat ->
                val week = stat.weekOfYear - 1
                val dayOfWeek = stat.dayOfWeek - 1
                if (week in 0..51 && dayOfWeek in 0..6) {
                    heatmapMatrix[dayOfWeek][week] = stat.count
                }
            }
            binding.layoutWeekStats.heatmapYearly.apply {
                removeAllViews()
                // 外层父布局:水平 LinearLayout,左固定周标签,右为横向滚动热力图
                val outerLayout = LinearLayout(context).apply {
                    orientation = LinearLayout.HORIZONTAL
                }
                // 左侧星期标签列
                val dayLabelLayout = LinearLayout(context).apply {
                    orientation = LinearLayout.VERTICAL
                    val dayLabels = arrayOf("周一", "周二", "周三", "周四", "周五", "周六", "周日")
                    // 顶部空白占位
                    addView(TextView(context).apply {
                        text = ""
                        textSize = 20f
                        height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
                    })
                    dayLabels.forEach { label ->
                        val textView = TextView(context).apply {
                            text = label
                            textSize = 10f
                            height = resources.getDimensionPixelSize(R.dimen.heatmap_cell_size)
                            setPadding(4, 0, 4, 0)
                        }
                        addView(textView)
                    }
                }
                // 右侧滚动部分
                val scrollView = HorizontalScrollView(context).apply {
                    isHorizontalScrollBarEnabled = false
                    layoutParams = LinearLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT
                    )
                }
                val scrollContentLayout = LinearLayout(context).apply {
                    orientation = LinearLayout.VERTICAL
                }
                val gridLayout = GridLayout(context).apply {
                    rowCount = 8
                    columnCount = 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(10, 0, 8, 4)
                        val weekPosition = (index * 4.3).toInt()
                        layoutParams = GridLayout.LayoutParams().apply {
                            columnSpec = GridLayout.spec(weekPosition)
                            rowSpec = GridLayout.spec(0)
                        }
                    }
                    gridLayout.addView(label)
                }*/
                months.forEachIndexed { index, month ->
                    val label = TextView(context).apply {
                        text = month
                        textSize = 10f
                        setPadding(10, 0, 8, 4)
                        val weekPosition = (index * 4.3).toInt()
                        val span = 4  // 控制跨列范围
                        layoutParams = GridLayout.LayoutParams().apply {
                            columnSpec = GridLayout.spec(weekPosition, span, GridLayout.CENTER)
                            rowSpec = GridLayout.spec(0)
                        }
                    }
                    gridLayout.addView(label)
                }
                // 添加热力格子
                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)
                                rowSpec = GridLayout.spec(day + 1)
                                setMargins(1, 1, 1, 1)
                            }
                            setBackgroundColor(getHeatmapColor(count))
                        }
                        gridLayout.addView(cell)
                    }
                }
                scrollContentLayout.addView(gridLayout)
                scrollView.addView(scrollContentLayout)
                // 添加两个主要部分到外层布局
                outerLayout.addView(dayLabelLayout)
                outerLayout.addView(scrollView)
                // 图例
                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 {
                        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)
                // 总容器垂直布局:热力图 + 图例
               val container = LinearLayout(context).apply {
                    orientation = LinearLayout.VERTICAL
                    addView(outerLayout)
                    addView(legendLayout)
                }
//                addView(container)
                // 设置外部 margin
                val params = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                ).apply {
                    setMargins(16, 16, 16, 16)  // 左、上、右、下的 margin,单位是像素
                }
                // 添加到父布局并应用 margin
                addView(container, params)
            }
        }
    }
    private fun updateHeatmapData_a() {
        viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
            if (stats.isEmpty()) return@observe
@@ -789,8 +1036,10 @@
                }
                // 添加月份标签
                val months = arrayOf("1月", "2月", "3月", "4月", "5月", "6月",
                    "7月", "8月", "9月", "10月", "11月", "12月")
                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
@@ -898,6 +1147,154 @@
        }
    }
    private fun updateHeatmapData_aaa() {
        viewModel.getYearlyHeatmap(currentDate.timeInMillis).observe(viewLifecycleOwner) { stats ->
            if (stats.isEmpty()) return@observe
            // 创建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)
                    }
                }
                // ✅ 把 gridLayout 包裹进 HorizontalScrollView
                val scrollView = HorizontalScrollView(context).apply {
                    layoutParams = LinearLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT
                    )
                    isHorizontalScrollBarEnabled = true
                }
                scrollView.addView(gridLayout)
                // 创建图例(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(scrollView)
                    addView(legendLayout)
                }
                addView(container)
            }
        }
    }
    private fun getHeatmapColor(count: Int): Int {
        return when {
            count == 0 -> Color.parseColor("#EBECF1") // 最淡