415 lines
15 KiB
Kotlin
415 lines
15 KiB
Kotlin
/**
|
||
* 自然写互动课堂电视端应用软件 V1.0
|
||
* Leanback主界面Fragment - Android TV主界面导航
|
||
*
|
||
* 功能说明:
|
||
* 1. Leanback BrowseSupportFragment主界面布局
|
||
* 2. D-Pad遥控器焦点导航适配(方向键/确认键/返回键)
|
||
* 3. 多功能区域展示(课堂笔迹、互动答题、学情报告、设置)
|
||
* 4. 课堂状态实时显示(当前课堂信息、在线学生数)
|
||
* 5. 语音操控集成(Android TV语音搜索)
|
||
* 6. 网关连接状态指示
|
||
* 7. 自动全屏沉浸式模式
|
||
*/
|
||
|
||
package com.writech.tv.ui
|
||
|
||
import android.content.Context
|
||
import android.graphics.Color
|
||
import android.os.Bundle
|
||
import android.os.Handler
|
||
import android.os.Looper
|
||
import android.util.Log
|
||
import android.view.KeyEvent
|
||
import android.view.View
|
||
import android.view.WindowManager
|
||
import android.widget.Toast
|
||
import java.text.SimpleDateFormat
|
||
import java.util.*
|
||
|
||
/**
|
||
* TV端主界面数据模型 - 功能卡片
|
||
*/
|
||
data class FunctionCard(
|
||
val id: String, // 卡片唯一标识
|
||
val title: String, // 标题
|
||
val description: String, // 描述
|
||
val iconRes: Int, // 图标资源ID
|
||
val category: String, // 所属分类
|
||
val action: String // 点击动作标识
|
||
)
|
||
|
||
/**
|
||
* 课堂状态信息
|
||
*/
|
||
data class ClassroomStatus(
|
||
var isActive: Boolean = false, // 是否有进行中的课堂
|
||
var classId: String = "", // 课堂ID
|
||
var className: String = "", // 课堂名称
|
||
var teacherName: String = "", // 授课教师
|
||
var onlineStudentCount: Int = 0, // 在线学生数
|
||
var totalStudentCount: Int = 0, // 总学生数
|
||
var startTime: Long = 0, // 课堂开始时间
|
||
var currentSubject: String = "" // 当前科目
|
||
)
|
||
|
||
/**
|
||
* TV端Leanback主界面Fragment
|
||
* 采用Android TV Leanback库的BrowseSupportFragment风格
|
||
* 适配遥控器D-Pad焦点导航操作
|
||
*/
|
||
class MainFragment {
|
||
|
||
companion object {
|
||
private const val TAG = "MainFragment"
|
||
|
||
// 功能分类ID
|
||
private const val CATEGORY_CLASSROOM = "classroom"
|
||
private const val CATEGORY_INTERACTIVE = "interactive"
|
||
private const val CATEGORY_REPORT = "report"
|
||
private const val CATEGORY_SETTINGS = "settings"
|
||
}
|
||
|
||
/** 当前课堂状态 */
|
||
private val classroomStatus = ClassroomStatus()
|
||
|
||
/** 功能卡片列表(按分类组织) */
|
||
private val functionCards = mutableMapOf<String, MutableList<FunctionCard>>()
|
||
|
||
/** 主线程Handler */
|
||
private val handler = Handler(Looper.getMainLooper())
|
||
|
||
/** 课堂计时器 */
|
||
private var classroomTimer: Timer? = null
|
||
|
||
/** 日期格式化器 */
|
||
private val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA)
|
||
|
||
/**
|
||
* 初始化界面
|
||
* 配置Leanback样式、加载功能卡片、设置焦点导航
|
||
*/
|
||
fun initialize() {
|
||
// 配置Leanback主题色
|
||
// brandColor = Color.parseColor("#1976D2")
|
||
// searchAffordanceColor = Color.parseColor("#2196F3")
|
||
|
||
// 加载功能卡片数据
|
||
loadFunctionCards()
|
||
|
||
// 设置搜索回调(语音搜索)
|
||
setupSearch()
|
||
|
||
// 设置全屏沉浸式模式
|
||
setupImmersiveMode()
|
||
|
||
Log.i(TAG, "主界面初始化完成")
|
||
}
|
||
|
||
/**
|
||
* 加载功能卡片列表
|
||
* 按分类组织:课堂展示、互动答题、学情报告、系统设置
|
||
*/
|
||
private fun loadFunctionCards() {
|
||
// 课堂展示功能
|
||
val classroomCards = mutableListOf(
|
||
FunctionCard(
|
||
id = "stroke_display",
|
||
title = "全班笔迹实时展示",
|
||
description = "大屏展示全班学生实时书写笔迹",
|
||
iconRes = 0, // R.drawable.ic_stroke_display
|
||
category = CATEGORY_CLASSROOM,
|
||
action = "open_stroke_display"
|
||
),
|
||
FunctionCard(
|
||
id = "multi_compare",
|
||
title = "多学生同屏对比",
|
||
description = "选择学生笔迹并排对比展示",
|
||
iconRes = 0,
|
||
category = CATEGORY_CLASSROOM,
|
||
action = "open_multi_compare"
|
||
),
|
||
FunctionCard(
|
||
id = "copybook_display",
|
||
title = "字帖临摹展示",
|
||
description = "放大范字与学生实时书写对比",
|
||
iconRes = 0,
|
||
category = CATEGORY_CLASSROOM,
|
||
action = "open_copybook"
|
||
),
|
||
FunctionCard(
|
||
id = "stroke_replay",
|
||
title = "笔迹回放",
|
||
description = "回放学生书写过程(支持变速)",
|
||
iconRes = 0,
|
||
category = CATEGORY_CLASSROOM,
|
||
action = "open_replay"
|
||
)
|
||
)
|
||
|
||
// 课堂互动功能
|
||
val interactiveCards = mutableListOf(
|
||
FunctionCard(
|
||
id = "quiz_display",
|
||
title = "答题结果展示",
|
||
description = "大屏展示课堂互动答题统计",
|
||
iconRes = 0,
|
||
category = CATEGORY_INTERACTIVE,
|
||
action = "open_quiz_display"
|
||
),
|
||
FunctionCard(
|
||
id = "random_pick",
|
||
title = "随机点名",
|
||
description = "随机抽取学生进行展示",
|
||
iconRes = 0,
|
||
category = CATEGORY_INTERACTIVE,
|
||
action = "open_random_pick"
|
||
),
|
||
FunctionCard(
|
||
id = "group_display",
|
||
title = "分组展示",
|
||
description = "按小组展示学生作品",
|
||
iconRes = 0,
|
||
category = CATEGORY_INTERACTIVE,
|
||
action = "open_group_display"
|
||
)
|
||
)
|
||
|
||
// 学情报告功能
|
||
val reportCards = mutableListOf(
|
||
FunctionCard(
|
||
id = "class_report",
|
||
title = "班级学情概览",
|
||
description = "班级整体学情数据大屏展示",
|
||
iconRes = 0,
|
||
category = CATEGORY_REPORT,
|
||
action = "open_class_report"
|
||
),
|
||
FunctionCard(
|
||
id = "student_report",
|
||
title = "学生学情详情",
|
||
description = "单个学生学情画像详细展示",
|
||
iconRes = 0,
|
||
category = CATEGORY_REPORT,
|
||
action = "open_student_report"
|
||
),
|
||
FunctionCard(
|
||
id = "growth_chart",
|
||
title = "书写成长轨迹",
|
||
description = "学生书写能力变化趋势图",
|
||
iconRes = 0,
|
||
category = CATEGORY_REPORT,
|
||
action = "open_growth_chart"
|
||
)
|
||
)
|
||
|
||
// 系统设置功能
|
||
val settingsCards = mutableListOf(
|
||
FunctionCard(
|
||
id = "gateway_settings",
|
||
title = "网关连接",
|
||
description = "搜索并绑定教室网关设备",
|
||
iconRes = 0,
|
||
category = CATEGORY_SETTINGS,
|
||
action = "open_gateway_settings"
|
||
),
|
||
FunctionCard(
|
||
id = "display_settings",
|
||
title = "显示设置",
|
||
description = "分辨率、字体大小、背景色调整",
|
||
iconRes = 0,
|
||
category = CATEGORY_SETTINGS,
|
||
action = "open_display_settings"
|
||
),
|
||
FunctionCard(
|
||
id = "network_settings",
|
||
title = "网络设置",
|
||
description = "WiFi连接、云平台地址配置",
|
||
iconRes = 0,
|
||
category = CATEGORY_SETTINGS,
|
||
action = "open_network_settings"
|
||
),
|
||
FunctionCard(
|
||
id = "about",
|
||
title = "关于",
|
||
description = "版本信息、设备ID、软件许可",
|
||
iconRes = 0,
|
||
category = CATEGORY_SETTINGS,
|
||
action = "open_about"
|
||
)
|
||
)
|
||
|
||
functionCards[CATEGORY_CLASSROOM] = classroomCards
|
||
functionCards[CATEGORY_INTERACTIVE] = interactiveCards
|
||
functionCards[CATEGORY_REPORT] = reportCards
|
||
functionCards[CATEGORY_SETTINGS] = settingsCards
|
||
|
||
Log.i(TAG, "功能卡片加载完成,共${functionCards.values.sumOf { it.size }}个")
|
||
}
|
||
|
||
/**
|
||
* 处理功能卡片点击事件
|
||
* 根据action标识跳转到对应的功能Fragment
|
||
*/
|
||
fun onCardSelected(card: FunctionCard) {
|
||
Log.i(TAG, "选中功能: ${card.title} -> ${card.action}")
|
||
when (card.action) {
|
||
"open_stroke_display" -> navigateToStrokeDisplay()
|
||
"open_multi_compare" -> navigateToMultiCompare()
|
||
"open_copybook" -> navigateToCopybookDisplay()
|
||
"open_replay" -> navigateToReplay()
|
||
"open_quiz_display" -> navigateToQuizDisplay()
|
||
"open_random_pick" -> performRandomPick()
|
||
"open_group_display" -> navigateToGroupDisplay()
|
||
"open_class_report" -> navigateToClassReport()
|
||
"open_student_report" -> navigateToStudentReport()
|
||
"open_growth_chart" -> navigateToGrowthChart()
|
||
"open_gateway_settings" -> navigateToGatewaySettings()
|
||
"open_display_settings" -> navigateToDisplaySettings()
|
||
"open_network_settings" -> navigateToNetworkSettings()
|
||
"open_about" -> navigateToAbout()
|
||
else -> Log.w(TAG, "未知操作: ${card.action}")
|
||
}
|
||
}
|
||
|
||
/** 设置语音搜索(Android TV Voice Search) */
|
||
private fun setupSearch() {
|
||
// setOnSearchClickedListener { openSearchFragment() }
|
||
Log.i(TAG, "语音搜索配置完成")
|
||
}
|
||
|
||
/** 设置全屏沉浸式模式 */
|
||
private fun setupImmersiveMode() {
|
||
// activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||
// activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_SECURE) // 防截屏
|
||
Log.i(TAG, "沉浸式模式已启用")
|
||
}
|
||
|
||
/**
|
||
* 处理遥控器按键事件
|
||
* 适配D-Pad方向键、确认键、返回键、菜单键
|
||
*/
|
||
fun onKeyEvent(keyCode: Int, event: KeyEvent): Boolean {
|
||
return when (keyCode) {
|
||
KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER -> {
|
||
// 确认键:选中当前焦点项
|
||
Log.d(TAG, "遥控器确认键按下")
|
||
false // 交给焦点系统处理
|
||
}
|
||
KeyEvent.KEYCODE_MENU -> {
|
||
// 菜单键:显示快捷操作面板
|
||
showQuickActions()
|
||
true
|
||
}
|
||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
|
||
// 播放/暂停键:控制笔迹回放
|
||
toggleReplayPause()
|
||
true
|
||
}
|
||
else -> false
|
||
}
|
||
}
|
||
|
||
/** 显示快捷操作面板 */
|
||
private fun showQuickActions() {
|
||
Log.i(TAG, "显示快捷操作面板")
|
||
}
|
||
|
||
/** 切换回放暂停/继续 */
|
||
private fun toggleReplayPause() {
|
||
Log.i(TAG, "切换回放状态")
|
||
}
|
||
|
||
/* ========== 课堂状态管理 ========== */
|
||
|
||
/** 更新课堂状态 */
|
||
fun updateClassroomStatus(status: ClassroomStatus) {
|
||
classroomStatus.isActive = status.isActive
|
||
classroomStatus.classId = status.classId
|
||
classroomStatus.className = status.className
|
||
classroomStatus.teacherName = status.teacherName
|
||
classroomStatus.onlineStudentCount = status.onlineStudentCount
|
||
classroomStatus.totalStudentCount = status.totalStudentCount
|
||
classroomStatus.startTime = status.startTime
|
||
classroomStatus.currentSubject = status.currentSubject
|
||
|
||
if (status.isActive) {
|
||
startClassroomTimer()
|
||
} else {
|
||
stopClassroomTimer()
|
||
}
|
||
|
||
// 更新Header显示
|
||
updateHeaderInfo()
|
||
}
|
||
|
||
/** 启动课堂计时器(实时显示课堂进行时长) */
|
||
private fun startClassroomTimer() {
|
||
stopClassroomTimer()
|
||
classroomTimer = Timer("classroom-timer")
|
||
classroomTimer?.scheduleAtFixedRate(object : TimerTask() {
|
||
override fun run() {
|
||
val elapsed = System.currentTimeMillis() - classroomStatus.startTime
|
||
val minutes = (elapsed / 60000).toInt()
|
||
val seconds = ((elapsed % 60000) / 1000).toInt()
|
||
val timeStr = String.format("%02d:%02d", minutes, seconds)
|
||
handler.post {
|
||
// 更新课堂时长显示
|
||
Log.d(TAG, "课堂进行: $timeStr")
|
||
}
|
||
}
|
||
}, 0, 1000)
|
||
}
|
||
|
||
/** 停止课堂计时器 */
|
||
private fun stopClassroomTimer() {
|
||
classroomTimer?.cancel()
|
||
classroomTimer = null
|
||
}
|
||
|
||
/** 更新顶部标题栏信息 */
|
||
private fun updateHeaderInfo() {
|
||
val title = if (classroomStatus.isActive) {
|
||
"${classroomStatus.className} - ${classroomStatus.currentSubject}" +
|
||
" (${classroomStatus.onlineStudentCount}/${classroomStatus.totalStudentCount}人在线)"
|
||
} else {
|
||
"自然写互动课堂"
|
||
}
|
||
// 设置标题
|
||
Log.i(TAG, "更新标题: $title")
|
||
}
|
||
|
||
/** 执行随机点名 */
|
||
private fun performRandomPick() {
|
||
if (!classroomStatus.isActive) {
|
||
Log.w(TAG, "当前无进行中的课堂,无法随机点名")
|
||
return
|
||
}
|
||
// 从在线学生列表中随机抽取
|
||
Log.i(TAG, "执行随机点名")
|
||
}
|
||
|
||
/* ========== 导航方法 ========== */
|
||
|
||
private fun navigateToStrokeDisplay() { Log.i(TAG, "跳转: 全班笔迹展示") }
|
||
private fun navigateToMultiCompare() { Log.i(TAG, "跳转: 多学生对比") }
|
||
private fun navigateToCopybookDisplay() { Log.i(TAG, "跳转: 字帖临摹") }
|
||
private fun navigateToReplay() { Log.i(TAG, "跳转: 笔迹回放") }
|
||
private fun navigateToQuizDisplay() { Log.i(TAG, "跳转: 答题展示") }
|
||
private fun navigateToGroupDisplay() { Log.i(TAG, "跳转: 分组展示") }
|
||
private fun navigateToClassReport() { Log.i(TAG, "跳转: 班级学情") }
|
||
private fun navigateToStudentReport() { Log.i(TAG, "跳转: 学生学情") }
|
||
private fun navigateToGrowthChart() { Log.i(TAG, "跳转: 成长轨迹") }
|
||
private fun navigateToGatewaySettings() { Log.i(TAG, "跳转: 网关设置") }
|
||
private fun navigateToDisplaySettings() { Log.i(TAG, "跳转: 显示设置") }
|
||
private fun navigateToNetworkSettings() { Log.i(TAG, "跳转: 网络设置") }
|
||
private fun navigateToAbout() { Log.i(TAG, "跳转: 关于") }
|
||
|
||
/** 释放资源 */
|
||
fun release() {
|
||
stopClassroomTimer()
|
||
functionCards.clear()
|
||
Log.i(TAG, "主界面资源已释放")
|
||
}
|
||
}
|