support badge

This commit is contained in:
Julian Freeman
2026-03-27 12:02:41 -04:00
parent c4366e62e1
commit 2d51467bb9
6 changed files with 90 additions and 1 deletions

View File

@@ -14,7 +14,7 @@ import {
retainDays, captureInterval,
TIME_OFFSET_MINUTES, TOTAL_MINUTES, getTagColor, getTagName, mainTags, getSubTags,
logicalMinutesToTime, logicalMinutesFromTime, formatDuration,
loadTags, loadEvents, loadReminders, toISODate
loadTags, loadEvents, loadReminders, toISODate, refreshBadgeCount
} from "./store";
import { DBEvent, TimelineItem } from "./types";
@@ -109,6 +109,8 @@ const updateCurrentMinute = () => {
} else {
currentLogicalMinute.value = -1;
}
// 无论是否看今天,每分钟都尝试刷新全局徽章
refreshBadgeCount();
};
let currentMinuteTimeout: number | null = null;

View File

@@ -1,5 +1,7 @@
import { ref, computed } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { Image } from "@tauri-apps/api/image";
import { Tag, DBEvent, TimelineItem, Toast, Reminder } from "../types";
export const TIME_OFFSET_MINUTES = 180;
@@ -111,4 +113,73 @@ export const loadEvents = async () => {
};
export const loadReminders = async () => {
reminders.value = await invoke("get_reminders", { date: currentDate.value });
refreshBadgeCount();
};
export const overdueCount = ref(0);
// 获取当前真实的逻辑时间和日期(不依赖 UI 状态)
export const getRealNowLogicalTime = () => {
const now = new Date();
const d = new Date(now.getTime() - TIME_OFFSET_MINUTES * 60000);
const date = toISODate(d);
const m = now.getHours() * 60 + now.getMinutes();
const minute = (m < TIME_OFFSET_MINUTES ? m + 1440 : m) - TIME_OFFSET_MINUTES;
return { date, minute };
};
export const refreshBadgeCount = async () => {
if (!dbPath.value) return;
try {
const { date, minute } = getRealNowLogicalTime();
const count: number = await invoke("get_overdue_reminders_count", {
date: date,
minute: minute
});
overdueCount.value = count;
await updateTaskbarBadge(count);
} catch (e) {
console.error("Failed to refresh badge count:", e);
}
};
const updateTaskbarBadge = async (count: number) => {
try {
const win = getCurrentWindow();
if (count <= 0) {
await win.setOverlayIcon(undefined);
return;
}
const canvas = document.createElement('canvas');
const size = 64;
canvas.width = size;
canvas.height = size;
const ctx = canvas.getContext('2d', { willReadFrequently: true });
if (!ctx) return;
// Draw red circle
ctx.fillStyle = '#FF3B30';
ctx.beginPath();
ctx.arc(size/2, size/2, size/2 - 2, 0, Math.PI * 2);
ctx.fill();
// Draw white text
ctx.fillStyle = '#FFFFFF';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = 'bold 38px Arial';
const displayCount = count > 99 ? '99+' : count.toString();
if (displayCount.length > 2) ctx.font = 'bold 28px Arial';
ctx.fillText(displayCount, size/2, size/2 + 2);
// Get raw RGBA pixels and wrap in Tauri Image object
const imageData = ctx.getImageData(0, 0, size, size);
const img = await Image.new(new Uint8Array(imageData.data), size, size);
await win.setOverlayIcon(img);
} catch (e) {
console.error("Failed to set overlay icon:", e);
}
};