/** * 自然写互动课堂电视端应用软件 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>() /** 主线程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, "主界面资源已释放") } }