From 3466799c94227c5ebba9fb201621e745058867ee Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期二, 15 四月 2025 13:18:34 +0800 Subject: [PATCH] add: 消息提醒时间设定;会员到期时间调整; --- app/src/main/res/layout/activity_reminder_list.xml | 36 +++++- app/src/main/res/values-v23/themes.xml | 12 +- app/src/main/java/com/example/firstapp/ui/notifications/NotificationsFragment.kt | 2 app/src/main/java/com/example/firstapp/activity/ReminderListActivity.kt | 4 app/src/main/java/com/example/firstapp/MainActivity.kt | 24 ++++ app/src/main/java/com/example/firstapp/service/ReminderWorker.kt | 120 ++++++++++++++++++++++- app/src/main/java/com/example/firstapp/App.kt | 34 ------ app/src/main/res/layout/fragment_notifications.xml | 17 ++ 8 files changed, 189 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/com/example/firstapp/App.kt b/app/src/main/java/com/example/firstapp/App.kt index a3992f7..1a0b34c 100644 --- a/app/src/main/java/com/example/firstapp/App.kt +++ b/app/src/main/java/com/example/firstapp/App.kt @@ -453,41 +453,15 @@ * 设置定时提醒Worker * 配置为每天运行一次检查是否有新的提醒内容 */ - private fun setupReminderWorker() { + fun setupReminderWorker() { Log.d(TAG, "设置定时提醒Worker") - // 方式1:使用周期性执行 - val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() - - // 创建周期性工作请求 - val reminderWorkRequest = PeriodicWorkRequestBuilder<ReminderWorker>( - ReminderWorker.REPEAT_INTERVAL, - ReminderWorker.REPEAT_INTERVAL_TIME_UNIT - ) - .setConstraints(constraints) - .addTag("reminder_worker") - .build() - - // 使用 REPLACE 策略确保新配置生效 - WorkManager.getInstance(this).enqueueUniquePeriodicWork( - "reminder_work", - ExistingPeriodicWorkPolicy.REPLACE, - reminderWorkRequest - ) - - // 方式2:设置在特定时间执行(例如每天上午9点和下午18点) + // 仅在特定时间执行(每天指定时间) // 可根据需要设置多个不同时间点的提醒 ReminderWorker.setupScheduledWorker(this, 9, 0) // 上午9:00 - ReminderWorker.setupScheduledWorker(this, 13, 50) // 下午18:00 + ReminderWorker.setupScheduledWorker(this, 13, 50) // 下午13:50 - // 注意:不再立即执行一次提醒检查,避免重复提醒 - // 如果需要立即检查,可以设置一个延迟,例如5分钟后执行 - val delayedWorkRequest = OneTimeWorkRequestBuilder<ReminderWorker>() - .setInitialDelay(5, TimeUnit.MINUTES) // 延迟5分钟执行 - .build() - WorkManager.getInstance(this).enqueue(delayedWorkRequest) + // 不再使用周期性轮询和立即执行的方式 } } \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/MainActivity.kt b/app/src/main/java/com/example/firstapp/MainActivity.kt index 13ae51e..9c533a8 100644 --- a/app/src/main/java/com/example/firstapp/MainActivity.kt +++ b/app/src/main/java/com/example/firstapp/MainActivity.kt @@ -75,6 +75,9 @@ // 只保留底部导航的设置 navView.setupWithNavController(navController) + // 重置提醒计划并检查是否有错过的提醒 + resetReminders() + // 检查权限 if (ContextCompat.checkSelfPermission( this, Manifest.permission.RECEIVE_SMS @@ -323,4 +326,25 @@ Toast.makeText(this, "同步短信失败:${e.message}", Toast.LENGTH_SHORT).show() } } + + // 重置提醒计划 + private fun resetReminders() { + try { + // 取消所有现有的提醒任务 + androidx.work.WorkManager.getInstance(this).cancelAllWorkByTag("reminder_worker") + + // 清除旧的提醒偏好设置 + getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE).edit().clear().apply() + + // 重新设置提醒任务 + (application as App).setupReminderWorker() + + // 检查是否有错过的提醒 + com.example.firstapp.service.ReminderWorker.checkMissedReminders(this) + + android.util.Log.d("MainActivity", "已重置提醒计划") + } catch (e: Exception) { + android.util.Log.e("MainActivity", "重置提醒计划失败: ${e.message}") + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/activity/ReminderListActivity.kt b/app/src/main/java/com/example/firstapp/activity/ReminderListActivity.kt index 44a6c76..5d8c26f 100644 --- a/app/src/main/java/com/example/firstapp/activity/ReminderListActivity.kt +++ b/app/src/main/java/com/example/firstapp/activity/ReminderListActivity.kt @@ -90,7 +90,7 @@ } // 添加已读按钮点击事件 - binding.clearReadMessagesButton.setOnClickListener { + binding.clearReadContainer.setOnClickListener { lifecycleScope.launch { // 将所有未读消息标记为已读 adapter.currentList.forEach { record -> @@ -99,7 +99,7 @@ } } Toast.makeText( - this@ReminderListActivity, "所有消息已标记为已读", Toast.LENGTH_SHORT + this@ReminderListActivity, "所有消息已标记为删除", Toast.LENGTH_SHORT ).show() checkUnreadMessages() } diff --git a/app/src/main/java/com/example/firstapp/service/ReminderWorker.kt b/app/src/main/java/com/example/firstapp/service/ReminderWorker.kt index 5e9d3fd..ef0d07f 100644 --- a/app/src/main/java/com/example/firstapp/service/ReminderWorker.kt +++ b/app/src/main/java/com/example/firstapp/service/ReminderWorker.kt @@ -40,9 +40,15 @@ override suspend fun doWork(): Result = withContext(Dispatchers.IO) { android.util.Log.d("ReminderWorker", "doWork 开始执行") try { - // 强制发送一条测试通知(确认Worker是否执行) - // sendTestNotification() - android.util.Log.d("ReminderWorker", "发送测试通知确认Worker已执行") + // 获取当前时间 + val currentTime = System.currentTimeMillis() + val scheduledTime = inputData.getLong("scheduled_time", 0) + + // 如果有设定的预定时间且当前时间与预定时间相差超过30分钟,则跳过执行 + if (scheduledTime > 0 && Math.abs(currentTime - scheduledTime) > 30 * 60 * 1000) { + android.util.Log.d("ReminderWorker", "当前时间与预定时间相差过大,跳过执行") + return@withContext Result.success() + } // 获取所有提醒设置 val reminderList = reminderRepository.getAllReminders().first() @@ -158,8 +164,12 @@ val channel = NotificationChannel( CHANNEL_ID, "提醒通知", - NotificationManager.IMPORTANCE_DEFAULT - ) + NotificationManager.IMPORTANCE_HIGH // 提高重要性级别 + ).apply { + enableLights(true) // 开启指示灯 + enableVibration(true) // 开启震动 + description = "重要提醒通知" // 设置描述 + } notificationManager.createNotificationChannel(channel) } @@ -168,7 +178,9 @@ .setSmallIcon(R.drawable.ic_reminder) // 使用自定义图标 .setContentTitle(title) .setContentText(content) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) + .setPriority(NotificationCompat.PRIORITY_HIGH) // 提高通知优先级 + .setCategory(NotificationCompat.CATEGORY_REMINDER) // 设置为提醒类别 + .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // 在锁屏上显示完整通知 .setAutoCancel(true) .setContentIntent(pendingIntent) .build() @@ -233,10 +245,11 @@ companion object { private const val CHANNEL_ID = "reminder_channel" + private const val MISSED_PREF_KEY = "last_checked_reminder_time" - // 定时任务执行频率 - 可选不同配置 - val REPEAT_INTERVAL = 15L // 设置为每15分钟运行一次 - val REPEAT_INTERVAL_TIME_UNIT = TimeUnit.MINUTES + // 定时任务执行频率(不再使用) + val REPEAT_INTERVAL = 24L // 设置为每24小时运行一次 + val REPEAT_INTERVAL_TIME_UNIT = TimeUnit.HOURS // 创建在指定时间运行的定时任务 fun setupScheduledWorker(context: Context, hour: Int, minute: Int) { @@ -255,11 +268,22 @@ // 计算初始延迟 val initialDelay = calendar.timeInMillis - now.timeInMillis + // 先取消所有现有的提醒任务 + WorkManager.getInstance(context).cancelAllWorkByTag("reminder_worker") + // 创建周期性工作请求(每天同一时间) val dailyWorkRequest = PeriodicWorkRequestBuilder<ReminderWorker>( 24, TimeUnit.HOURS ) .setInitialDelay(initialDelay, TimeUnit.MILLISECONDS) + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + // 设置灵活时间窗口为0,确保尽量准时执行 + .setInputData(Data.Builder().putLong("scheduled_time", calendar.timeInMillis).build()) + .addTag("reminder_worker") .build() // 使用 REPLACE 策略确保新配置生效 @@ -268,6 +292,84 @@ ExistingPeriodicWorkPolicy.REPLACE, dailyWorkRequest ) + + android.util.Log.d("ReminderWorker", "设置定时提醒: ${hour}:${minute}, 初始延迟: ${initialDelay/1000/60}分钟") + + // 记录预定的下次执行时间 + val prefs = context.getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE) + prefs.edit().putLong("next_reminder_time_${hour}_${minute}", calendar.timeInMillis).apply() + } + + // 应用启动时检查是否有错过的提醒 + fun checkMissedReminders(context: Context) { + val prefs = context.getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE) + val lastCheckedTime = prefs.getLong(MISSED_PREF_KEY, 0) + val currentTime = System.currentTimeMillis() + + // 如果上次检查时间是0,说明是首次运行应用 + if (lastCheckedTime == 0L) { + prefs.edit().putLong(MISSED_PREF_KEY, currentTime).apply() + return + } + + // 检查是否错过了提醒时间点 + val lastCheckedCalendar = Calendar.getInstance().apply { timeInMillis = lastCheckedTime } + val currentCalendar = Calendar.getInstance().apply { timeInMillis = currentTime } + + // 如果不是同一天,或者超过了设定的提醒时间点 + val missedReminder = checkIfMissedReminderTime(lastCheckedCalendar, currentCalendar) + + if (missedReminder) { + android.util.Log.d("ReminderWorker", "检测到错过的提醒,立即执行一次") + // 立即安排一次性任务执行提醒检查 + val oneTimeRequest = OneTimeWorkRequestBuilder<ReminderWorker>() + .setConstraints( + Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() + ) + .build() + + WorkManager.getInstance(context).enqueue(oneTimeRequest) + } + + // 更新最后检查时间 + prefs.edit().putLong(MISSED_PREF_KEY, currentTime).apply() + } + + // 检查是否错过了提醒时间点 + private fun checkIfMissedReminderTime(lastChecked: Calendar, current: Calendar): Boolean { + // 如果日期不同,说明至少过了一天 + if (lastChecked.get(Calendar.DAY_OF_YEAR) != current.get(Calendar.DAY_OF_YEAR) || + lastChecked.get(Calendar.YEAR) != current.get(Calendar.YEAR)) { + + // 检查当前时间是否超过了9:00或13:50 + val currentHour = current.get(Calendar.HOUR_OF_DAY) + val currentMinute = current.get(Calendar.MINUTE) + + return (currentHour > 9 || (currentHour == 9 && currentMinute >= 0)) || + (currentHour > 13 || (currentHour == 13 && currentMinute >= 50)) + } + + // 如果同一天,检查是否在上次检查后经过了9:00或13:50时间点 + val lastHour = lastChecked.get(Calendar.HOUR_OF_DAY) + val lastMinute = lastChecked.get(Calendar.MINUTE) + val currentHour = current.get(Calendar.HOUR_OF_DAY) + val currentMinute = current.get(Calendar.MINUTE) + + // 检查是否错过了9:00 + if ((lastHour < 9 || (lastHour == 9 && lastMinute == 0)) && + (currentHour > 9 || (currentHour == 9 && currentMinute > 0))) { + return true + } + + // 检查是否错过了13:50 + if ((lastHour < 13 || (lastHour == 13 && lastMinute < 50)) && + (currentHour > 13 || (currentHour == 13 && currentMinute >= 50))) { + return true + } + + return false } } } \ No newline at end of file diff --git a/app/src/main/java/com/example/firstapp/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/example/firstapp/ui/notifications/NotificationsFragment.kt index 7362c83..b3fe265 100644 --- a/app/src/main/java/com/example/firstapp/ui/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/example/firstapp/ui/notifications/NotificationsFragment.kt @@ -312,7 +312,7 @@ val userInfo = response.data // 本地保存我的邀请码 - PreferencesManager.setInviteCode(userInfo.intervialcode); + //PreferencesManager.setInviteCode(userInfo.intervialcode); // 设置头像 Glide.with(this) .load(userInfo.cover) diff --git a/app/src/main/res/layout/activity_reminder_list.xml b/app/src/main/res/layout/activity_reminder_list.xml index 59d3474..699f593 100644 --- a/app/src/main/res/layout/activity_reminder_list.xml +++ b/app/src/main/res/layout/activity_reminder_list.xml @@ -13,18 +13,38 @@ android:elevation="4dp" android:padding="8dp"> - <!-- 将已读按钮改为图标 --> - <ImageButton - android:id="@+id/clearReadMessagesButton" - android:layout_width="30dp" - android:layout_height="30dp" + <!-- 使用 LinearLayout 包裹图标和文字 --> + <LinearLayout + android:id="@+id/clearReadContainer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:layout_marginEnd="16dp" + android:orientation="horizontal" + android:gravity="center_vertical" android:background="?attr/selectableItemBackgroundBorderless" - android:contentDescription="标记所有消息为已读" - android:padding="8dp" - android:src="@drawable/reminder_delete" /> + android:clickable="true" + android:focusable="true"> + + <!-- 调整后的图标按钮 --> + <ImageButton + android:id="@+id/clearReadMessagesButton" + android:layout_width="30dp" + android:layout_height="30dp" + android:background="@null" + android:contentDescription="标记所有消息为已读" + android:padding="8dp" + android:src="@drawable/reminder_delete" /> + + <!-- 添加“全部删除”文字 --> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="全部删除" + android:layout_marginEnd="8dp" + android:textColor="@color/black" /> + </LinearLayout> </RelativeLayout> <androidx.recyclerview.widget.RecyclerView diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml index 82ad433..6af008d 100644 --- a/app/src/main/res/layout/fragment_notifications.xml +++ b/app/src/main/res/layout/fragment_notifications.xml @@ -120,19 +120,28 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="VIP会员 " + android:text="VIP会员" android:textColor="#B8741A" - android:textSize="18sp" + android:textSize="16sp" android:textStyle="bold"/> <!-- 添加间隔 --> + <View + android:layout_width="6dp" + android:layout_height="0dp"/> <TextView android:id="@+id/tv_vip_expire" - android:layout_width="wrap_content" + android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_weight="1" + android:singleLine="true" + android:ellipsize="end" android:textColor="#F2F2F2" - android:textSize="14sp"/> + android:textSize="12sp" + android:clickable="true" + android:focusable="true" + android:background="?attr/selectableItemBackground"/> </LinearLayout> <!-- 第二行:续费提示(上移调整) --> diff --git a/app/src/main/res/values-v23/themes.xml b/app/src/main/res/values-v23/themes.xml index 1553ce1..1b76944 100644 --- a/app/src/main/res/values-v23/themes.xml +++ b/app/src/main/res/values-v23/themes.xml @@ -7,10 +7,10 @@ <!-- <item name="android:windowLightStatusBar">?attr/isLightTheme</item>--> <!-- </style>--> - <style name="Theme.FirstApp" parent="Base.Theme.FirstApp"> - <!-- Transparent system bars for edge-to-edge. --> - <item name="android:navigationBarColor">@android:color/transparent</item> - <item name="android:statusBarColor">@android:color/transparent</item> - <item name="android:windowLightStatusBar">?attr/isLightTheme</item> - </style> +<!-- <style name="Theme.FirstApp" parent="Base.Theme.FirstApp">--> +<!-- <!– Transparent system bars for edge-to-edge. –>--> +<!-- <item name="android:navigationBarColor">@android:color/transparent</item>--> +<!-- <item name="android:statusBarColor">@android:color/transparent</item>--> +<!-- <item name="android:windowLightStatusBar">?attr/isLightTheme</item>--> +<!-- </style>--> </resources> \ No newline at end of file -- Gitblit v1.9.3