跨端: 补「当前选中邮件」高亮 —— 鸿蒙原来完全没有这个概念
用户:「你自己看看跟 webui 相比,观感真的差很多」。逐项比对后找到的**行为缺口** (不是配色问题,是少了一个状态)。 WebUI 一直有:`MailList.tsx:104/116/229` 把 `currentMail?.mail_id` 传进卡片, 卡片据此上 `active ? 'bg-blue-50 border-blue-200'`。 鸿蒙**一个都没有** —— 点开一封邮件后,左侧列表那一行和旁边几行长得一模一样: 你不知道自己正在读哪一封、读完了该往哪回。 修法: · `CommPage` 拥有 `@State currentMailId`,`openMail()` 里记下,以 `@Prop` 下发给 `InboxTab`/`SentTab`。**单点写、多点读** —— 两个 tab 各存一份必然会分叉 (收件箱和发件箱都能触发同一个动作)。 · 存 `mail_id` 而非索引/组键:SSE 会让列表重排,索引会错位。 · 三级优先 **选中 > 未读 > 普通**。★ 这里有个必须成对的理由: 选中与未读底色**相同**(都是 `accentSoft`),只靠底色的话 "选中一封未读邮件"看不出任何变化 ⇒ 选中必须额外加那圈边。 这正是 WebUI 两个 token 并存的原因,不是随手加的边框。 · 新增 `Theme.accentEdge/accentEdgeDark/accentEdgeFor()`(= tailwind blue-200 及其深色值)——我第一版只搬了底、忘了边,选中态淡到几乎看不见。 ★ 顺带记一个工具坑:`devecocli ui tap` 在这台模拟器上**点了不生效** (截图前后一样、布局树无变化),而 `hdc shell "uitest uiInput click X Y"` 有效。以后点不动就先换这条,别以为是代码没生效 —— 我为此白跑了两轮。
This commit is contained in:
@ -464,6 +464,26 @@ export class Theme {
|
||||
*/
|
||||
static readonly accentSoftDark: string = '#1C2536';
|
||||
|
||||
/**
|
||||
* 品牌浅底的**边框**(与 WebUI 的 `border-blue-200` 成对)。
|
||||
*
|
||||
* ★★ 2026-09-20 补。WebUI 的"选中"是**底 + 边**两个 token 一起用
|
||||
* (`MailList.tsx:280`:`active ? 'bg-blue-50 border-blue-200'`):
|
||||
* · 底 `#EFF6FF` = 我们的 `accentSoft`
|
||||
* · 边 `#BFDBFE` = 这一条
|
||||
* 我第一版只搬了底、忘了边 ⇒ 选中态只有一层很淡的蓝,
|
||||
* 在浅色壁纸上几乎看不出来(实测对比 WebUI 明显更弱)。
|
||||
*
|
||||
* 深色取值对齐 WebUI `.dark` 段的 `--c-blue-200`。
|
||||
*/
|
||||
static readonly accentEdge: string = '#BFDBFE';
|
||||
static readonly accentEdgeDark: string = '#2B3B57';
|
||||
|
||||
/** 按当前主题给品牌浅底的边框(与 `accentSoftFor` 同一纪律)。 */
|
||||
static accentEdgeFor(dark?: boolean): string {
|
||||
return Theme.isDarkNow(dark) ? Theme.accentEdgeDark : Theme.accentEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按当前主题给品牌浅底。
|
||||
*
|
||||
|
||||
@ -254,6 +254,24 @@ struct InboxTab {
|
||||
@State accountFilter: string = 'all'; // 'all' 或 accountId
|
||||
@State showAccountPicker: boolean = false;
|
||||
@State accountList: AccountInfo[] = [];
|
||||
/**
|
||||
* **当前正在看的邮件**(点开的那一封)—— 用来给列表里对应的那张卡加高亮。
|
||||
*
|
||||
* ★★ 2026-09-20 补(用户:「邮件展示左侧没有圆角」→ 顺着逐项比对时发现)。
|
||||
*
|
||||
* 之前鸿蒙**完全没有"当前选中邮件"这个概念**:点开一封邮件后,左侧列表
|
||||
* 那一行和旁边几行长得一模一样 —— 你不知道自己正在读哪一封、读完了该往哪回。
|
||||
* 而 WebUI 一直有(`MailList.tsx:104/116/229` 把 `currentMail.mail_id` 传下去,
|
||||
* 卡片据此上 `bg-blue-50 border-blue-200`)。
|
||||
*
|
||||
* 存 `mail_id`(不是索引/组键):SSE 推送会让列表重排,索引会错位;
|
||||
* `mail_id` 才是这一封的稳定身份。
|
||||
*
|
||||
* ★ 由 `CommPage` 拥有、以 `@Prop` 下发 —— 因为"点开了哪一封"是
|
||||
* `CommPage.openMail()` 那个动作产生的(收件箱/发件箱都能触发),
|
||||
* 两个 tab 各存一份必然会分叉。单点写、多点读。
|
||||
*/
|
||||
@Prop currentMailId: string = '';
|
||||
private sseService: SseService | null = null;
|
||||
|
||||
aboutToAppear(): void {
|
||||
@ -589,9 +607,28 @@ struct InboxTab {
|
||||
this.MailItem(mail)
|
||||
}
|
||||
.width('100%').height(64)
|
||||
.backgroundColor(mail.status === 'unread' ? Theme.accentSoftFor(this.isDarkNow) : Theme.surface)
|
||||
/*
|
||||
* 底 + 边**成对**决定这张卡的身份,口径逐项对齐 WebUI(`MailList.tsx:280`):
|
||||
*
|
||||
* active ? 'bg-blue-50 border-blue-200'
|
||||
* : 'border-transparent hover:bg-gray-50'
|
||||
*
|
||||
* 三级优先:**选中 > 未读 > 普通**。
|
||||
* · 选中:`accentSoft` + `accentEdge`(`#EFF6FF` / `#BFDBFE`,与 blue-50/200 同值)
|
||||
* · 未读:`accentSoft`,边仍是普通边框(未读只是"没看过",不是"正在看")
|
||||
* · 普通:`Theme.surface` + 普通边框
|
||||
*
|
||||
* ★ 为什么选中要压过未读:两者底色相同(都是 accentSoft),
|
||||
* 若只靠底色区分,选中一封未读邮件时**看不出任何变化**。
|
||||
* 所以选中额外加那圈 `accentEdge` 边 —— 这正是 WebUI 两个 token 并存的原因。
|
||||
*/
|
||||
.backgroundColor(this.currentMailId === mail.mail_id || mail.status === 'unread'
|
||||
? Theme.accentSoftFor(this.isDarkNow) : Theme.surface)
|
||||
.borderRadius(Theme.radiusCard)
|
||||
.border({ width: 1, color: Theme.border })
|
||||
.border({
|
||||
width: 1,
|
||||
color: this.currentMailId === mail.mail_id ? Theme.accentEdgeFor(this.isDarkNow) : Theme.border
|
||||
})
|
||||
.clip(true)
|
||||
.onClick(() => {
|
||||
this.openMail(mail);
|
||||
@ -797,6 +834,13 @@ struct InboxTab {
|
||||
struct SentTab {
|
||||
/** 背景是否开启:开着就让出页面底(WebUI 的做法是页面底完全透明) */
|
||||
@Prop bgActive: boolean = false;
|
||||
/**
|
||||
* 正在看的那一封(`CommPage` 下发)—— 见 `InboxTab.currentMailId` 的注释。
|
||||
* 发件箱的每一行也要高亮,否则"从发件箱点开一封"就断了同一条线索。
|
||||
*/
|
||||
@Prop currentMailId: string = '';
|
||||
/** 深浅色(`InboxTab` 同名属性同一口径:`Theme` 是静态类,算不出主题,走 AppStorage) */
|
||||
@StorageProp('agentmail.appearance.isDark') isDarkNow: boolean = false;
|
||||
/** 底部悬浮条高度(窄屏非 0)——理由见 `InboxTab` 的 `navReserve` */
|
||||
@Prop navReserve: number = 0;
|
||||
/** 选中邮件回调 */
|
||||
@ -1003,6 +1047,13 @@ struct SentTab {
|
||||
.width('100%')
|
||||
.attributeModifier(GlassCardModifier.of(this.bgActive))
|
||||
.borderRadius(Theme.radiusCard)
|
||||
/* 与 `MailRow` 同一口径:选中(正在读的那一封)上品牌边。
|
||||
WebUI 组内条目也是这么标的(`MailList.tsx:229`
|
||||
把 `currentMailID` 传进 `MailItem` 的 `active`)。 */
|
||||
.border({
|
||||
width: 1,
|
||||
color: this.currentMailId === m.mail_id ? Theme.accentEdgeFor(this.isDarkNow) : Theme.border
|
||||
})
|
||||
.margin({ bottom: 6 })
|
||||
.onClick(() => { this.openMail(m); })
|
||||
}
|
||||
@ -1302,6 +1353,11 @@ struct CommPage {
|
||||
private readonly KEY_NAV_BADGE_CONTACTS: string = 'agentmail.nav.contacts';
|
||||
/** Navigation 路由栈:宽屏 Split 时列表+详情并排,窄屏 Stack 时详情 push 覆盖 */
|
||||
private navPathStack: NavPathStack = new NavPathStack();
|
||||
/**
|
||||
* 正在看的那一封(本页拥有,下发给 `InboxTab`/`SentTab`)—— 见
|
||||
* `InboxTab.currentMailId` 的注释。
|
||||
*/
|
||||
@State currentMailId: string = '';
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.refreshCounts();
|
||||
@ -1490,6 +1546,9 @@ struct CommPage {
|
||||
}
|
||||
|
||||
openMail(mailId: string, accountId: string): void {
|
||||
/* 记下"正在看哪一封" ⇒ 列表里那一行高亮(对齐 WebUI 的 currentMail)。
|
||||
放在 push 之前:即使 push 失败,用户也确实点了这一封。 */
|
||||
this.currentMailId = mailId;
|
||||
const params: MailDetailParams = {
|
||||
mail_id: mailId,
|
||||
account_id: accountId
|
||||
@ -1545,6 +1604,7 @@ struct CommPage {
|
||||
if (this.commTab === 'sent') {
|
||||
SentTab({
|
||||
bgActive: this.bgActive,
|
||||
currentMailId: this.currentMailId,
|
||||
navReserve: this.navReserve,
|
||||
onOpenMail: (mailId: string, accountId: string): void => { this.openMail(mailId, accountId); }
|
||||
})
|
||||
@ -1553,6 +1613,7 @@ struct CommPage {
|
||||
} else {
|
||||
InboxTab({
|
||||
bgActive: this.bgActive,
|
||||
currentMailId: this.currentMailId,
|
||||
navReserve: this.navReserve,
|
||||
onOpenMail: (mailId: string, accountId: string): void => { this.openMail(mailId, accountId); }
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user