- 重构「灵感」模块为「发现」模块,统一页面命名与文案 - 新增flutter_tts语音朗读依赖与鸿蒙Nearby配对方式 - 添加Android/iOS/鸿蒙全平台桌面小组件支持(7种类型) - 完善文件传输模块,新增画布邀请消息与删除会话功能 - 优化协作画布光标广播节流逻辑,修复已知bug - 更新应用英文名与隐私政策入口,新增翻译API抽象层 - 移除用户中心多余的加号按钮,完善空状态组件类型
1512 lines
57 KiB
HTML
1512 lines
57 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>闲言APP — 桌面小部件管理方案</title>
|
||
<style>
|
||
:root {
|
||
--primary: #6C63FF;
|
||
--primary-light: #8B83FF;
|
||
--primary-dark: #4A42E0;
|
||
--secondary: #FF6B6B;
|
||
--accent: #4ECDC4;
|
||
--success: #10B981;
|
||
--warning: #F59E0B;
|
||
--error: #EF4444;
|
||
--info: #3B82F6;
|
||
--bg-primary: #FAFAFA;
|
||
--bg-secondary: #F5F5F5;
|
||
--bg-card: #FFFFFF;
|
||
--bg-elevated: #FFFFFF;
|
||
--text-primary: #1A1A2E;
|
||
--text-secondary: #6B7280;
|
||
--text-hint: #9CA3AF;
|
||
--radius-sm: 4px;
|
||
--radius-md: 8px;
|
||
--radius-lg: 12px;
|
||
--radius-xl: 16px;
|
||
--radius-2xl: 20px;
|
||
--radius-full: 9999px;
|
||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 16px;
|
||
--space-4: 24px;
|
||
--space-5: 32px;
|
||
--space-6: 48px;
|
||
--font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: var(--font-family);
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
.container {
|
||
max-width: 960px;
|
||
margin: 0 auto;
|
||
padding: var(--space-5);
|
||
}
|
||
|
||
/* Header */
|
||
.header {
|
||
text-align: center;
|
||
padding: var(--space-6) 0 var(--space-5);
|
||
}
|
||
.header h1 {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
background: linear-gradient(135deg, var(--primary), var(--accent));
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
.header p {
|
||
color: var(--text-secondary);
|
||
font-size: 1rem;
|
||
}
|
||
|
||
/* Section */
|
||
.section {
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-xl);
|
||
padding: var(--space-5);
|
||
margin-bottom: var(--space-4);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.section-title {
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
margin-bottom: var(--space-4);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
}
|
||
.section-title .icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 16px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* Badge */
|
||
.badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
padding: 2px 10px;
|
||
border-radius: var(--radius-full);
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
gap: 4px;
|
||
}
|
||
.badge-primary { background: rgba(108,99,255,0.12); color: var(--primary); }
|
||
.badge-success { background: rgba(16,185,129,0.12); color: var(--success); }
|
||
.badge-warning { background: rgba(245,158,11,0.12); color: var(--warning); }
|
||
.badge-error { background: rgba(239,68,68,0.12); color: var(--error); }
|
||
.badge-info { background: rgba(59,130,246,0.12); color: var(--info); }
|
||
.badge-accent { background: rgba(78,205,196,0.12); color: var(--accent); }
|
||
|
||
/* Widget Card Grid */
|
||
.widget-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||
gap: var(--space-4);
|
||
}
|
||
|
||
.widget-card {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
transition: all 0.2s ease;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.widget-card:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: var(--shadow-lg);
|
||
border-color: var(--primary-light);
|
||
}
|
||
.widget-card .card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
.widget-card .card-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: var(--radius-lg);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 24px;
|
||
flex-shrink: 0;
|
||
}
|
||
.widget-card .card-title {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
}
|
||
.widget-card .card-subtitle {
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
}
|
||
.widget-card .card-desc {
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: var(--space-3);
|
||
line-height: 1.5;
|
||
}
|
||
.widget-card .card-badges {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
.widget-card .card-preview {
|
||
background: linear-gradient(135deg, #1A1A2E, #2D2D44);
|
||
border-radius: var(--radius-md);
|
||
padding: var(--space-3);
|
||
color: #fff;
|
||
min-height: 120px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: space-between;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.widget-card .card-preview::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: -50%;
|
||
right: -30%;
|
||
width: 120px;
|
||
height: 120px;
|
||
border-radius: 50%;
|
||
background: rgba(108,99,255,0.15);
|
||
filter: blur(30px);
|
||
}
|
||
.widget-card .card-preview .preview-label {
|
||
font-size: 0.7rem;
|
||
color: rgba(255,255,255,0.5);
|
||
text-transform: uppercase;
|
||
letter-spacing: 1px;
|
||
}
|
||
.widget-card .card-preview .preview-content {
|
||
font-size: 1rem;
|
||
font-weight: 500;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.widget-card .card-preview .preview-author {
|
||
font-size: 0.8rem;
|
||
color: rgba(255,255,255,0.6);
|
||
text-align: right;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.widget-card .card-preview .preview-count {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.widget-card .card-preview .preview-unit {
|
||
font-size: 0.8rem;
|
||
color: rgba(255,255,255,0.5);
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
.widget-card .card-status {
|
||
position: absolute;
|
||
top: var(--space-3);
|
||
right: var(--space-3);
|
||
}
|
||
|
||
/* Platform Table */
|
||
.platform-table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
border-radius: var(--radius-lg);
|
||
overflow: hidden;
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
}
|
||
.platform-table th {
|
||
background: var(--bg-primary);
|
||
padding: var(--space-3) var(--space-4);
|
||
text-align: left;
|
||
font-weight: 600;
|
||
font-size: 0.85rem;
|
||
color: var(--text-secondary);
|
||
border-bottom: 1px solid rgba(0,0,0,0.06);
|
||
}
|
||
.platform-table td {
|
||
padding: var(--space-3) var(--space-4);
|
||
font-size: 0.85rem;
|
||
border-bottom: 1px solid rgba(0,0,0,0.04);
|
||
vertical-align: top;
|
||
}
|
||
.platform-table tr:last-child td { border-bottom: none; }
|
||
.platform-table tr:hover td { background: rgba(108,99,255,0.03); }
|
||
|
||
/* Phone Mockup */
|
||
.phone-mockup {
|
||
width: 375px;
|
||
margin: 0 auto;
|
||
background: var(--bg-card);
|
||
border-radius: 40px;
|
||
border: 8px solid #1A1A2E;
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-xl);
|
||
position: relative;
|
||
}
|
||
.phone-mockup .notch {
|
||
width: 150px;
|
||
height: 28px;
|
||
background: #1A1A2E;
|
||
border-radius: 0 0 20px 20px;
|
||
margin: 0 auto;
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
.phone-mockup .screen {
|
||
min-height: 700px;
|
||
background: var(--bg-secondary);
|
||
overflow-y: auto;
|
||
}
|
||
.phone-mockup .nav-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: var(--space-2) var(--space-3);
|
||
background: rgba(255,255,255,0.85);
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 5;
|
||
border-bottom: 0.5px solid rgba(0,0,0,0.08);
|
||
}
|
||
.phone-mockup .nav-bar .back-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 18px;
|
||
color: var(--primary);
|
||
cursor: pointer;
|
||
}
|
||
.phone-mockup .nav-bar .nav-title {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-weight: 600;
|
||
font-size: 1rem;
|
||
}
|
||
.phone-mockup .nav-bar .nav-right {
|
||
width: 32px;
|
||
}
|
||
|
||
/* Widget Management Page UI */
|
||
.mgmt-section {
|
||
padding: var(--space-3);
|
||
}
|
||
.mgmt-section-title {
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
margin-bottom: var(--space-2);
|
||
padding-left: var(--space-1);
|
||
}
|
||
.mgmt-widget-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
padding: var(--space-3);
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-lg);
|
||
margin-bottom: var(--space-2);
|
||
box-shadow: var(--shadow-sm);
|
||
transition: all 0.2s;
|
||
}
|
||
.mgmt-widget-item:hover {
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.mgmt-widget-icon {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 22px;
|
||
flex-shrink: 0;
|
||
}
|
||
.mgmt-widget-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
.mgmt-widget-name {
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
}
|
||
.mgmt-widget-desc {
|
||
font-size: 0.75rem;
|
||
color: var(--text-secondary);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.mgmt-widget-action {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
flex-shrink: 0;
|
||
}
|
||
.mgmt-btn {
|
||
padding: 6px 14px;
|
||
border-radius: var(--radius-full);
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
border: none;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.mgmt-btn-primary {
|
||
background: var(--primary);
|
||
color: #fff;
|
||
}
|
||
.mgmt-btn-primary:hover {
|
||
background: var(--primary-dark);
|
||
}
|
||
.mgmt-btn-outline {
|
||
background: transparent;
|
||
color: var(--primary);
|
||
border: 1.5px solid var(--primary);
|
||
}
|
||
.mgmt-btn-outline:hover {
|
||
background: rgba(108,99,255,0.08);
|
||
}
|
||
.mgmt-btn-success {
|
||
background: var(--success);
|
||
color: #fff;
|
||
}
|
||
|
||
/* Toggle Switch */
|
||
.toggle {
|
||
width: 44px;
|
||
height: 26px;
|
||
border-radius: 13px;
|
||
background: #D1D5DB;
|
||
position: relative;
|
||
cursor: pointer;
|
||
transition: background 0.3s;
|
||
flex-shrink: 0;
|
||
}
|
||
.toggle.active {
|
||
background: var(--success);
|
||
}
|
||
.toggle::after {
|
||
content: '';
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 50%;
|
||
background: #fff;
|
||
position: absolute;
|
||
top: 2px;
|
||
left: 2px;
|
||
transition: transform 0.3s;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
|
||
}
|
||
.toggle.active::after {
|
||
transform: translateX(18px);
|
||
}
|
||
|
||
/* Info Banner */
|
||
.info-banner {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: var(--space-3);
|
||
padding: var(--space-3);
|
||
border-radius: var(--radius-lg);
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
.info-banner-tip {
|
||
background: rgba(59,130,246,0.08);
|
||
border: 1px solid rgba(59,130,246,0.15);
|
||
}
|
||
.info-banner-warn {
|
||
background: rgba(245,158,11,0.08);
|
||
border: 1px solid rgba(245,158,11,0.15);
|
||
}
|
||
.info-banner-icon {
|
||
font-size: 18px;
|
||
flex-shrink: 0;
|
||
margin-top: 1px;
|
||
}
|
||
.info-banner-text {
|
||
font-size: 0.8rem;
|
||
color: var(--text-secondary);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
/* Architecture Diagram */
|
||
.arch-diagram {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
overflow-x: auto;
|
||
}
|
||
.arch-layer {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-3);
|
||
margin-bottom: var(--space-2);
|
||
position: relative;
|
||
}
|
||
.arch-layer:last-child { margin-bottom: 0; }
|
||
.arch-layer-label {
|
||
width: 100px;
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
text-align: right;
|
||
flex-shrink: 0;
|
||
}
|
||
.arch-layer-content {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
flex: 1;
|
||
flex-wrap: wrap;
|
||
}
|
||
.arch-box {
|
||
padding: 6px 12px;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
border: 1.5px solid;
|
||
white-space: nowrap;
|
||
}
|
||
.arch-box-flutter {
|
||
background: rgba(108,99,255,0.08);
|
||
border-color: rgba(108,99,255,0.3);
|
||
color: var(--primary);
|
||
}
|
||
.arch-box-android {
|
||
background: rgba(16,185,129,0.08);
|
||
border-color: rgba(16,185,129,0.3);
|
||
color: var(--success);
|
||
}
|
||
.arch-box-ios {
|
||
background: rgba(59,130,246,0.08);
|
||
border-color: rgba(59,130,246,0.3);
|
||
color: var(--info);
|
||
}
|
||
.arch-box-ohos {
|
||
background: rgba(245,158,11,0.08);
|
||
border-color: rgba(245,158,11,0.3);
|
||
color: var(--warning);
|
||
}
|
||
.arch-connector {
|
||
width: 2px;
|
||
height: 12px;
|
||
background: rgba(0,0,0,0.1);
|
||
margin-left: 106px;
|
||
}
|
||
|
||
/* File Tree */
|
||
.file-tree {
|
||
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
||
font-size: 0.8rem;
|
||
line-height: 1.8;
|
||
color: var(--text-primary);
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
overflow-x: auto;
|
||
}
|
||
.file-tree .dir { color: var(--primary); font-weight: 600; }
|
||
.file-tree .file { color: var(--text-secondary); }
|
||
.file-tree .new { color: var(--success); font-weight: 600; }
|
||
.file-tree .comment { color: var(--text-hint); font-style: italic; }
|
||
|
||
/* Tab system */
|
||
.tabs {
|
||
display: flex;
|
||
gap: 2px;
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-lg);
|
||
padding: 3px;
|
||
margin-bottom: var(--space-4);
|
||
}
|
||
.tab {
|
||
flex: 1;
|
||
padding: 8px 16px;
|
||
border-radius: var(--radius-md);
|
||
font-size: 0.85rem;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
color: var(--text-secondary);
|
||
border: none;
|
||
background: transparent;
|
||
}
|
||
.tab.active {
|
||
background: var(--bg-card);
|
||
color: var(--text-primary);
|
||
box-shadow: var(--shadow-sm);
|
||
font-weight: 600;
|
||
}
|
||
.tab:hover:not(.active) {
|
||
color: var(--text-primary);
|
||
}
|
||
.tab-content { display: none; }
|
||
.tab-content.active { display: block; }
|
||
|
||
/* Progress Steps */
|
||
.steps {
|
||
display: flex;
|
||
gap: var(--space-2);
|
||
margin-bottom: var(--space-5);
|
||
flex-wrap: wrap;
|
||
}
|
||
.step {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-2);
|
||
padding: 6px 14px;
|
||
border-radius: var(--radius-full);
|
||
font-size: 0.8rem;
|
||
font-weight: 500;
|
||
background: var(--bg-primary);
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
}
|
||
.step-num {
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 0.7rem;
|
||
font-weight: 700;
|
||
background: var(--primary);
|
||
color: #fff;
|
||
}
|
||
|
||
/* Comparison cards */
|
||
.compare-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: var(--space-3);
|
||
}
|
||
.compare-card {
|
||
background: var(--bg-primary);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--space-4);
|
||
border: 1px solid rgba(0,0,0,0.06);
|
||
text-align: center;
|
||
}
|
||
.compare-card .platform-logo {
|
||
font-size: 2rem;
|
||
margin-bottom: var(--space-2);
|
||
}
|
||
.compare-card .platform-name {
|
||
font-weight: 700;
|
||
font-size: 1rem;
|
||
margin-bottom: var(--space-1);
|
||
}
|
||
.compare-card .platform-version {
|
||
font-size: 0.75rem;
|
||
color: var(--text-hint);
|
||
margin-bottom: var(--space-3);
|
||
}
|
||
.compare-card .feature-list {
|
||
text-align: left;
|
||
font-size: 0.8rem;
|
||
}
|
||
.compare-card .feature-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 4px 0;
|
||
color: var(--text-secondary);
|
||
}
|
||
.feature-item .check { color: var(--success); }
|
||
.feature-item .cross { color: var(--error); }
|
||
.feature-item .partial { color: var(--warning); }
|
||
|
||
/* Responsive */
|
||
@media (max-width: 768px) {
|
||
.container { padding: var(--space-3); }
|
||
.widget-grid { grid-template-columns: 1fr; }
|
||
.compare-grid { grid-template-columns: 1fr; }
|
||
.phone-mockup { width: 100%; border-radius: 24px; border-width: 4px; }
|
||
.phone-mockup .notch { width: 120px; height: 20px; }
|
||
}
|
||
|
||
/* Animations */
|
||
@keyframes fadeInUp {
|
||
from { opacity: 0; transform: translateY(20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
.animate-in {
|
||
animation: fadeInUp 0.5s ease forwards;
|
||
}
|
||
.delay-1 { animation-delay: 0.1s; opacity: 0; }
|
||
.delay-2 { animation-delay: 0.2s; opacity: 0; }
|
||
.delay-3 { animation-delay: 0.3s; opacity: 0; }
|
||
.delay-4 { animation-delay: 0.4s; opacity: 0; }
|
||
.delay-5 { animation-delay: 0.5s; opacity: 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="container">
|
||
|
||
<!-- Header -->
|
||
<div class="header animate-in">
|
||
<h1>📱 闲言APP — 桌面小部件管理方案</h1>
|
||
<p>将「会员中心」替换为「桌面小部件」入口 · 创建小部件管理页面 · 三端原生代码适配</p>
|
||
</div>
|
||
|
||
<!-- Change Summary -->
|
||
<div class="section animate-in delay-1">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(108,99,255,0.1);">🔄</span>
|
||
变更概览
|
||
</div>
|
||
<div class="steps">
|
||
<div class="step"><span class="step-num">1</span> profile_page 会员中心 → 桌面小部件</div>
|
||
<div class="step"><span class="step-num">2</span> 新建 WidgetManagementPage</div>
|
||
<div class="step"><span class="step-num">3</span> 扩展 HomeWidgetService</div>
|
||
<div class="step"><span class="step-num">4</span> Android 原生 Widget 实现</div>
|
||
<div class="step"><span class="step-num">5</span> iOS Widget Extension 实现</div>
|
||
<div class="step"><span class="step-num">6</span> 鸿蒙 Form Extension 实现</div>
|
||
</div>
|
||
<div class="info-banner info-banner-tip">
|
||
<span class="info-banner-icon">💡</span>
|
||
<span class="info-banner-text">
|
||
项目已有 <code>home_widget</code> 本地 fork(v0.9.1-ohos.1),支持 Android/iOS/鸿蒙三端。
|
||
已有 <code>HomeWidgetService</code> 封装稍后读计数和每日一句数据推送。
|
||
本次扩展将新增更多小部件类型,并创建可视化管理页面。
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget Analysis -->
|
||
<div class="section animate-in delay-2">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(78,205,196,0.1);">🧩</span>
|
||
可创建的小部件分析
|
||
</div>
|
||
|
||
<div class="widget-grid">
|
||
|
||
<!-- Widget 1: Daily Sentence -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-success">✅ 已有基础</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#6C63FF,#8B83FF);">📜</div>
|
||
<div>
|
||
<div class="card-title">每日一句</div>
|
||
<div class="card-subtitle">DailySentenceWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">每日推送一条精选句子,含作者和出处。支持小/中两种尺寸。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×1 / 4×1</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 每日一句</div>
|
||
<div class="preview-content">"人生如逆旅,我亦是行人。"</div>
|
||
<div class="preview-author">—— 苏轼</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 2: Readlater -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-success">✅ 已有基础</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#4ECDC4,#44B8A8);">📖</div>
|
||
<div>
|
||
<div class="card-title">稍后读</div>
|
||
<div class="card-subtitle">ReadlaterWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">显示稍后读未读数量和最新一条预览。点击直接打开稍后读列表。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×1 / 4×2</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 稍后读</div>
|
||
<div style="display:flex;align-items:baseline;gap:8px;">
|
||
<div class="preview-count">12</div>
|
||
<div class="preview-unit">条未读</div>
|
||
</div>
|
||
<div class="preview-content" style="font-size:0.85rem;opacity:0.8;">山有木兮木有枝,心悦君兮...</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 3: Daily Card -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#FF6B6B,#FF8E8E);">🃏</div>
|
||
<div>
|
||
<div class="card-title">日签卡片</div>
|
||
<div class="card-subtitle">DailyCardWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">展示精美日签卡片,含日期、句子和背景图。每日自动更新。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">4×2 / 4×3</span>
|
||
</div>
|
||
<div class="card-preview" style="min-height:140px;">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;">
|
||
<div class="preview-label">闲言 · 日签</div>
|
||
<div style="font-size:0.75rem;opacity:0.5;">5月19日</div>
|
||
</div>
|
||
<div class="preview-content" style="font-size:0.9rem;line-height:1.6;">落霞与孤鹜齐飞,<br>秋水共长天一色。</div>
|
||
<div class="preview-author">—— 王勃《滕王阁序》</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 4: Daily Fortune -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#F59E0B,#FBBF24);">🔮</div>
|
||
<div>
|
||
<div class="card-title">每日运势</div>
|
||
<div class="card-subtitle">DailyFortuneWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">展示今日运势指数和幸运关键词。趣味性强,适合桌面展示。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×1 / 2×2</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 今日运势</div>
|
||
<div style="display:flex;align-items:center;gap:12px;">
|
||
<div style="font-size:2.5rem;">🌟</div>
|
||
<div>
|
||
<div style="font-size:1.1rem;font-weight:700;">大吉</div>
|
||
<div style="font-size:0.75rem;opacity:0.6;">幸运色:青绿 · 宜:读书</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 5: Countdown -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#3B82F6,#60A5FA);">⏳</div>
|
||
<div>
|
||
<div class="card-title">倒计时</div>
|
||
<div class="card-subtitle">CountdownWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">自定义倒计时事件,显示剩余天数。适合考试、节日等场景。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×1 / 4×1</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 倒计时</div>
|
||
<div style="display:flex;align-items:baseline;gap:8px;">
|
||
<div class="preview-count" style="color:#60A5FA;">28</div>
|
||
<div class="preview-unit">天后</div>
|
||
</div>
|
||
<div style="font-size:0.85rem;opacity:0.7;">距离 高考</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 6: Pomodoro -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#EF4444,#F87171);">🍅</div>
|
||
<div>
|
||
<div class="card-title">番茄钟</div>
|
||
<div class="card-subtitle">PomodoroWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">桌面快捷启动番茄钟,显示当前专注进度。交互式小组件。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS ⚠️</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×2 / 4×2</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 番茄钟</div>
|
||
<div style="text-align:center;padding:8px 0;">
|
||
<div style="font-size:2rem;font-weight:700;">25:00</div>
|
||
<div style="font-size:0.75rem;opacity:0.5;margin-top:4px;">点击开始专注</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 7: Solar Term -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#10B981,#34D399);">🌿</div>
|
||
<div>
|
||
<div class="card-title">节气诗词</div>
|
||
<div class="card-subtitle">SolarTermWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">展示当前节气信息和对应诗词。文化气息浓厚,适合桌面展示。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×2 / 4×2</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 节气</div>
|
||
<div style="display:flex;align-items:center;gap:12px;">
|
||
<div style="font-size:2rem;">🌾</div>
|
||
<div>
|
||
<div style="font-size:1rem;font-weight:600;">小满</div>
|
||
<div style="font-size:0.7rem;opacity:0.5;">5月21日 · 夏熟作物初熟</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-size:0.8rem;opacity:0.7;margin-top:6px;">夜莺啼绿柳,皓月醒长空</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Widget 8: Check-in -->
|
||
<div class="widget-card">
|
||
<div class="card-status"><span class="badge badge-info">🆕 新增</span></div>
|
||
<div class="card-header">
|
||
<div class="card-icon" style="background:linear-gradient(135deg,#8B5CF6,#A78BFA);">✅</div>
|
||
<div>
|
||
<div class="card-title">每日签到</div>
|
||
<div class="card-subtitle">CheckinWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="card-desc">展示连续签到天数和今日签到状态。桌面快捷签到按钮。</div>
|
||
<div class="card-badges">
|
||
<span class="badge badge-primary">iOS</span>
|
||
<span class="badge badge-success">Android</span>
|
||
<span class="badge badge-warning">鸿蒙</span>
|
||
<span class="badge badge-accent">2×1 / 4×1</span>
|
||
</div>
|
||
<div class="card-preview">
|
||
<div class="preview-label">闲言 · 签到</div>
|
||
<div style="display:flex;align-items:center;justify-content:space-between;">
|
||
<div>
|
||
<div style="font-size:0.8rem;opacity:0.6;">连续签到</div>
|
||
<div style="font-size:1.8rem;font-weight:700;color:#A78BFA;">7天</div>
|
||
</div>
|
||
<div style="padding:6px 16px;border-radius:20px;background:rgba(167,139,250,0.3);font-size:0.8rem;font-weight:600;">今日签到</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Management Page UI Preview -->
|
||
<div class="section animate-in delay-3">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(108,99,255,0.1);">📱</span>
|
||
管理页面 UI 方案
|
||
</div>
|
||
|
||
<div style="display:flex;gap:var(--space-5);flex-wrap:wrap;justify-content:center;">
|
||
<!-- Phone Mockup -->
|
||
<div class="phone-mockup">
|
||
<div class="notch"></div>
|
||
<div class="screen">
|
||
<div class="nav-bar">
|
||
<div class="back-btn">‹</div>
|
||
<div class="nav-title">桌面小部件</div>
|
||
<div class="nav-right"></div>
|
||
</div>
|
||
|
||
<div class="mgmt-section">
|
||
<div class="info-banner info-banner-tip" style="margin-bottom:var(--space-3);">
|
||
<span class="info-banner-icon">💡</span>
|
||
<span class="info-banner-text">长按桌面空白处可添加小部件,或在下方点击「添加到桌面」</span>
|
||
</div>
|
||
|
||
<div class="mgmt-section-title">已添加的小部件</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#6C63FF,#8B83FF);">📜</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">每日一句</div>
|
||
<div class="mgmt-widget-desc">每日推送精选句子 · 已添加到桌面</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<div class="toggle active" onclick="this.classList.toggle('active')"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#4ECDC4,#44B8A8);">📖</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">稍后读</div>
|
||
<div class="mgmt-widget-desc">12条未读 · 已添加到桌面</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<div class="toggle active" onclick="this.classList.toggle('active')"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#FF6B6B,#FF8E8E);">🃏</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">日签卡片</div>
|
||
<div class="mgmt-widget-desc">精美日签 · 已添加但未启用</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<div class="toggle" onclick="this.classList.toggle('active')"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-section" style="padding-top:0;">
|
||
<div class="mgmt-section-title">更多小部件</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#F59E0B,#FBBF24);">🔮</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">每日运势</div>
|
||
<div class="mgmt-widget-desc">今日运势指数和幸运关键词</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<button class="mgmt-btn mgmt-btn-primary">添加</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#3B82F6,#60A5FA);">⏳</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">倒计时</div>
|
||
<div class="mgmt-widget-desc">自定义倒计时事件</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<button class="mgmt-btn mgmt-btn-primary">添加</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#EF4444,#F87171);">🍅</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">番茄钟</div>
|
||
<div class="mgmt-widget-desc">桌面快捷专注计时</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<button class="mgmt-btn mgmt-btn-primary">添加</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#10B981,#34D399);">🌿</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">节气诗词</div>
|
||
<div class="mgmt-widget-desc">当前节气与对应诗词</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<button class="mgmt-btn mgmt-btn-primary">添加</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-widget-item">
|
||
<div class="mgmt-widget-icon" style="background:linear-gradient(135deg,#8B5CF6,#A78BFA);">✅</div>
|
||
<div class="mgmt-widget-info">
|
||
<div class="mgmt-widget-name">每日签到</div>
|
||
<div class="mgmt-widget-desc">连续签到天数和快捷签到</div>
|
||
</div>
|
||
<div class="mgmt-widget-action">
|
||
<button class="mgmt-btn mgmt-btn-primary">添加</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mgmt-section" style="padding-top:0;">
|
||
<div class="mgmt-section-title">平台说明</div>
|
||
<div class="info-banner info-banner-warn">
|
||
<span class="info-banner-icon">⚠️</span>
|
||
<span class="info-banner-text">
|
||
iOS 小部件需在 WidgetKit 中配置;Android 需在系统桌面长按添加;
|
||
鸿蒙需通过服务卡片添加。各平台操作方式略有差异。
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Cross Platform -->
|
||
<div class="section animate-in delay-4">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(16,185,129,0.1);">🌍</span>
|
||
跨平台兼容性分析
|
||
</div>
|
||
|
||
<div class="compare-grid" style="margin-bottom:var(--space-4);">
|
||
<div class="compare-card">
|
||
<div class="platform-logo">🤖</div>
|
||
<div class="platform-name">Android</div>
|
||
<div class="platform-version">API 26+ (Android 8.0)</div>
|
||
<div class="feature-list">
|
||
<div class="feature-item"><span class="check">✅</span> AppWidgetProvider</div>
|
||
<div class="feature-item"><span class="check">✅</span> RemoteViews 布局</div>
|
||
<div class="feature-item"><span class="check">✅</span> Glance (Jetpack)</div>
|
||
<div class="feature-item"><span class="check">✅</span> requestPinWidget</div>
|
||
<div class="feature-item"><span class="check">✅</span> 交互式按钮</div>
|
||
<div class="feature-item"><span class="check">✅</span> 自由缩放</div>
|
||
<div class="feature-item"><span class="check">✅</span> 后台更新</div>
|
||
<div class="feature-item"><span class="check">✅</span> renderFlutterWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="compare-card">
|
||
<div class="platform-logo">🍎</div>
|
||
<div class="platform-name">iOS</div>
|
||
<div class="platform-version">iOS 16+ (WidgetKit)</div>
|
||
<div class="feature-list">
|
||
<div class="feature-item"><span class="check">✅</span> WidgetKit Extension</div>
|
||
<div class="feature-item"><span class="check">✅</span> SwiftUI 视图</div>
|
||
<div class="feature-item"><span class="check">✅</span> Small/Medium/Large</div>
|
||
<div class="feature-item"><span class="check">✅</span> Live Activity</div>
|
||
<div class="feature-item"><span class="partial">⚠️</span> 交互式按钮 (iOS 17+)</div>
|
||
<div class="feature-item"><span class="partial">⚠️</span> 番茄钟实时刷新受限</div>
|
||
<div class="feature-item"><span class="check">✅</span> App Group 数据共享</div>
|
||
<div class="feature-item"><span class="check">✅</span> renderFlutterWidget</div>
|
||
</div>
|
||
</div>
|
||
<div class="compare-card">
|
||
<div class="platform-logo">🔴</div>
|
||
<div class="platform-name">HarmonyOS</div>
|
||
<div class="platform-version">API 12+ (Form Extension)</div>
|
||
<div class="feature-list">
|
||
<div class="feature-item"><span class="check">✅</span> Form Extension</div>
|
||
<div class="feature-item"><span class="check">✅</span> ArkTS/ArkUI 布局</div>
|
||
<div class="feature-item"><span class="check">✅</span> 1×2 / 2×2 / 2×4 / 4×4</div>
|
||
<div class="feature-item"><span class="partial">⚠️</span> 交互能力有限</div>
|
||
<div class="feature-item"><span class="cross">❌</span> 无 requestPinWidget</div>
|
||
<div class="feature-item"><span class="cross">❌</span> 无实时刷新</div>
|
||
<div class="feature-item"><span class="check">✅</span> Preferences 数据共享</div>
|
||
<div class="feature-item"><span class="cross">❌</span> 无 renderFlutterWidget</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<table class="platform-table">
|
||
<thead>
|
||
<tr>
|
||
<th>小部件</th>
|
||
<th>Android</th>
|
||
<th>iOS</th>
|
||
<th>鸿蒙</th>
|
||
<th>优先级</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><strong>📜 每日一句</strong></td>
|
||
<td><span class="badge badge-success">✅ 完整</span></td>
|
||
<td><span class="badge badge-success">✅ 完整</span></td>
|
||
<td><span class="badge badge-warning">⚠️ 基础</span></td>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>📖 稍后读</strong></td>
|
||
<td><span class="badge badge-success">✅ 完整</span></td>
|
||
<td><span class="badge badge-success">✅ 完整</span></td>
|
||
<td><span class="badge badge-warning">⚠️ 基础</span></td>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>🃏 日签卡片</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-error">P1</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>🔮 每日运势</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-warning">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>⏳ 倒计时</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-warning">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>🍅 番茄钟</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-warning">⚠️ 受限</span></td>
|
||
<td><span class="badge badge-warning">⚠️ 受限</span></td>
|
||
<td><span class="badge badge-accent">P3</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>🌿 节气诗词</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-accent">P3</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><strong>✅ 每日签到</strong></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-info">🆕 新增</span></td>
|
||
<td><span class="badge badge-accent">P3</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<!-- Architecture -->
|
||
<div class="section animate-in delay-5">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(59,130,246,0.1);">🏗️</span>
|
||
架构设计与文件结构
|
||
</div>
|
||
|
||
<div class="tabs">
|
||
<button class="tab active" onclick="switchTab(event, 'arch-diagram-tab')">架构图</button>
|
||
<button class="tab" onclick="switchTab(event, 'flutter-files-tab')">Flutter 文件</button>
|
||
<button class="tab" onclick="switchTab(event, 'android-files-tab')">Android 原生</button>
|
||
<button class="tab" onclick="switchTab(event, 'ios-files-tab')">iOS 原生</button>
|
||
<button class="tab" onclick="switchTab(event, 'ohos-files-tab')">鸿蒙原生</button>
|
||
</div>
|
||
|
||
<!-- Architecture Diagram -->
|
||
<div id="arch-diagram-tab" class="tab-content active">
|
||
<div class="arch-diagram">
|
||
<div class="arch-layer">
|
||
<div class="arch-layer-label">Flutter UI</div>
|
||
<div class="arch-layer-content">
|
||
<div class="arch-box arch-box-flutter">WidgetManagementPage</div>
|
||
<div class="arch-box arch-box-flutter">WidgetCard</div>
|
||
<div class="arch-box arch-box-flutter">WidgetProvider</div>
|
||
</div>
|
||
</div>
|
||
<div class="arch-connector"></div>
|
||
<div class="arch-layer">
|
||
<div class="arch-layer-label">Flutter Service</div>
|
||
<div class="arch-layer-content">
|
||
<div class="arch-box arch-box-flutter">HomeWidgetService</div>
|
||
<div class="arch-box arch-box-flutter">WidgetDataSync</div>
|
||
<div class="arch-box arch-box-flutter">WidgetClickHandler</div>
|
||
</div>
|
||
</div>
|
||
<div class="arch-connector"></div>
|
||
<div class="arch-layer">
|
||
<div class="arch-layer-label">home_widget</div>
|
||
<div class="arch-layer-content">
|
||
<div class="arch-box arch-box-flutter">saveWidgetData</div>
|
||
<div class="arch-box arch-box-flutter">updateWidget</div>
|
||
<div class="arch-box arch-box-flutter">getInstalledWidgets</div>
|
||
<div class="arch-box arch-box-flutter">registerInteractivityCallback</div>
|
||
</div>
|
||
</div>
|
||
<div class="arch-connector"></div>
|
||
<div class="arch-layer">
|
||
<div class="arch-layer-label">Native</div>
|
||
<div class="arch-layer-content">
|
||
<div class="arch-box arch-box-android">AppWidgetProvider</div>
|
||
<div class="arch-box arch-box-android">RemoteViews</div>
|
||
<div class="arch-box arch-box-ios">WidgetKit</div>
|
||
<div class="arch-box arch-box-ios">SwiftUI</div>
|
||
<div class="arch-box arch-box-ohos">FormExtension</div>
|
||
<div class="arch-box arch-box-ohos">ArkUI</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Flutter Files -->
|
||
<div id="flutter-files-tab" class="tab-content">
|
||
<div class="file-tree">
|
||
<span class="dir">lib/features/widget/</span>
|
||
├── <span class="dir">models/</span>
|
||
│ ├── <span class="new">widget_type.dart</span> <span class="comment">// 小部件类型枚举 + 元数据</span>
|
||
│ └── <span class="new">widget_config.dart</span> <span class="comment">// 小部件配置模型</span>
|
||
├── <span class="dir">presentation/</span>
|
||
│ ├── <span class="new">widget_management_page.dart</span> <span class="comment">// 管理页面主入口</span>
|
||
│ └── <span class="dir">widgets/</span>
|
||
│ ├── <span class="new">widget_card.dart</span> <span class="comment">// 单个小部件卡片组件</span>
|
||
│ ├── <span class="new">widget_preview.dart</span> <span class="comment">// 小部件预览组件</span>
|
||
│ └── <span class="new">platform_guide.dart</span> <span class="comment">// 平台操作指引组件</span>
|
||
├── <span class="dir">providers/</span>
|
||
│ └── <span class="new">widget_provider.dart</span> <span class="comment">// 小部件状态管理</span>
|
||
└── <span class="dir">services/</span>
|
||
└── <span class="new">widget_data_service.dart</span> <span class="comment">// 小部件数据推送服务</span>
|
||
|
||
<span class="dir">lib/core/services/data/</span>
|
||
└── <span class="file">home_widget_service.dart</span> <span class="comment">// ← 扩展:新增多种小部件数据推送</span>
|
||
|
||
<span class="dir">lib/core/registry/</span>
|
||
└── <span class="file">page_registry.dart</span> <span class="comment">// ← 修改:注册新路由</span>
|
||
|
||
<span class="dir">lib/features/profile/</span>
|
||
└── <span class="file">profile_page.dart</span> <span class="comment">// ← 修改:会员中心 → 桌面小部件</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Android Files -->
|
||
<div id="android-files-tab" class="tab-content">
|
||
<div class="file-tree">
|
||
<span class="dir">android/app/src/main/</span>
|
||
├── <span class="dir">kotlin/com/xianyan/</span>
|
||
│ ├── <span class="file">MainActivity.kt</span> <span class="comment">// ← 已有</span>
|
||
│ └── <span class="dir">widget/</span>
|
||
│ ├── <span class="new">DailySentenceProvider.kt</span> <span class="comment">// 每日一句 WidgetProvider</span>
|
||
│ ├── <span class="new">ReadlaterProvider.kt</span> <span class="comment">// 稍后读 WidgetProvider</span>
|
||
│ ├── <span class="new">DailyCardProvider.kt</span> <span class="comment">// 日签卡片 WidgetProvider</span>
|
||
│ ├── <span class="new">FortuneProvider.kt</span> <span class="comment">// 每日运势 WidgetProvider</span>
|
||
│ ├── <span class="new">CountdownProvider.kt</span> <span class="comment">// 倒计时 WidgetProvider</span>
|
||
│ ├── <span class="new">PomodoroProvider.kt</span> <span class="comment">// 番茄钟 WidgetProvider</span>
|
||
│ ├── <span class="new">SolarTermProvider.kt</span> <span class="comment">// 节气诗词 WidgetProvider</span>
|
||
│ └── <span class="new">CheckinProvider.kt</span> <span class="comment">// 每日签到 WidgetProvider</span>
|
||
├── <span class="dir">res/</span>
|
||
│ ├── <span class="dir">layout/</span>
|
||
│ │ ├── <span class="new">widget_daily_sentence.xml</span> <span class="comment">// 每日一句布局</span>
|
||
│ │ ├── <span class="new">widget_readlater.xml</span> <span class="comment">// 稍后读布局</span>
|
||
│ │ ├── <span class="new">widget_daily_card.xml</span> <span class="comment">// 日签卡片布局</span>
|
||
│ │ ├── <span class="new">widget_fortune.xml</span> <span class="comment">// 运势布局</span>
|
||
│ │ ├── <span class="new">widget_countdown.xml</span> <span class="comment">// 倒计时布局</span>
|
||
│ │ ├── <span class="new">widget_pomodoro.xml</span> <span class="comment">// 番茄钟布局</span>
|
||
│ │ ├── <span class="new">widget_solar_term.xml</span> <span class="comment">// 节气布局</span>
|
||
│ │ └── <span class="new">widget_checkin.xml</span> <span class="comment">// 签到布局</span>
|
||
│ ├── <span class="dir">drawable/</span>
|
||
│ │ └── <span class="new">widget_background_*.xml</span> <span class="comment">// 各样式背景</span>
|
||
│ └── <span class="dir">xml/</span>
|
||
│ ├── <span class="new">widget_daily_sentence_info.xml</span>
|
||
│ ├── <span class="new">widget_readlater_info.xml</span>
|
||
│ ├── <span class="new">widget_daily_card_info.xml</span>
|
||
│ ├── <span class="new">widget_fortune_info.xml</span>
|
||
│ ├── <span class="new">widget_countdown_info.xml</span>
|
||
│ ├── <span class="new">widget_pomodoro_info.xml</span>
|
||
│ ├── <span class="new">widget_solar_term_info.xml</span>
|
||
│ └── <span class="new">widget_checkin_info.xml</span>
|
||
└── <span class="file">AndroidManifest.xml</span> <span class="comment">// ← 注册 receiver</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- iOS Files -->
|
||
<div id="ios-files-tab" class="tab-content">
|
||
<div class="file-tree">
|
||
<span class="dir">ios/</span>
|
||
├── <span class="dir">Runner/</span> <span class="comment">// ← 已有</span>
|
||
└── <span class="dir">XianyanWidgets/</span> <span class="comment">// Widget Extension (新增)</span>
|
||
├── <span class="new">XianyanWidgets.swift</span> <span class="comment">// Widget 入口 + TimelineProvider</span>
|
||
├── <span class="new">DailySentenceWidget.swift</span> <span class="comment">// 每日一句视图</span>
|
||
├── <span class="new">ReadlaterWidget.swift</span> <span class="comment">// 稍后读视图</span>
|
||
├── <span class="new">DailyCardWidget.swift</span> <span class="comment">// 日签卡片视图</span>
|
||
├── <span class="new">FortuneWidget.swift</span> <span class="comment">// 每日运势视图</span>
|
||
├── <span class="new">CountdownWidget.swift</span> <span class="comment">// 倒计时视图</span>
|
||
├── <span class="new">PomodoroWidget.swift</span> <span class="comment">// 番茄钟视图 (iOS 17+)</span>
|
||
├── <span class="new">SolarTermWidget.swift</span> <span class="comment">// 节气诗词视图</span>
|
||
├── <span class="new">CheckinWidget.swift</span> <span class="comment">// 每日签到视图</span>
|
||
├── <span class="dir">Assets.xcassets/</span>
|
||
│ └── <span class="new">WidgetBackground.imageset/</span>
|
||
└── <span class="new">Info.plist</span>
|
||
|
||
<span class="comment">// 需在 Xcode 中添加 Widget Extension Target</span>
|
||
<span class="comment">// App Group: group.com.xianyan.share</span>
|
||
<span class="comment">// 支持 Small / Medium / Large 三种尺寸</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ohos Files -->
|
||
<div id="ohos-files-tab" class="tab-content">
|
||
<div class="file-tree">
|
||
<span class="dir">ohos/</span>
|
||
├── <span class="dir">entry/src/main/ets/</span>
|
||
│ ├── <span class="dir">entryability/</span>
|
||
│ │ └── <span class="file">EntryAbility.ets</span> <span class="comment">// ← 已有</span>
|
||
│ └── <span class="dir">widget/</span> <span class="comment">// Form Extension (新增)</span>
|
||
│ ├── <span class="new">DailySentenceForm.ets</span> <span class="comment">// 每日一句卡片</span>
|
||
│ ├── <span class="new">ReadlaterForm.ets</span> <span class="comment">// 稍后读卡片</span>
|
||
│ ├── <span class="new">DailyCardForm.ets</span> <span class="comment">// 日签卡片</span>
|
||
│ ├── <span class="new">FortuneForm.ets</span> <span class="comment">// 每日运势卡片</span>
|
||
│ ├── <span class="new">CountdownForm.ets</span> <span class="comment">// 倒计时卡片</span>
|
||
│ ├── <span class="new">SolarTermForm.ets</span> <span class="comment">// 节气诗词卡片</span>
|
||
│ └── <span class="new">CheckinForm.ets</span> <span class="comment">// 每日签到卡片</span>
|
||
├── <span class="dir">entry/src/main/resources/</span>
|
||
│ └── <span class="dir">base/profile/</span>
|
||
│ ├── <span class="new">widget_daily_sentence.json</span> <span class="comment">// 卡片配置</span>
|
||
│ ├── <span class="new">widget_readlater.json</span>
|
||
│ ├── <span class="new">widget_daily_card.json</span>
|
||
│ ├── <span class="new">widget_fortune.json</span>
|
||
│ ├── <span class="new">widget_countdown.json</span>
|
||
│ ├── <span class="new">widget_solar_term.json</span>
|
||
│ └── <span class="new">widget_checkin.json</span>
|
||
└── <span class="file">module.json5</span> <span class="comment">// ← 注册 ExtensionAbility</span>
|
||
|
||
<span class="comment">// 鸿蒙使用 FormExtensionAbility</span>
|
||
<span class="comment">// 数据通过 Preferences 共享</span>
|
||
<span class="comment">// 布局使用 ArkUI 声明式语法</span>
|
||
<span class="comment">// 番茄钟因实时刷新限制,鸿蒙端暂不实现</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Implementation Plan -->
|
||
<div class="section">
|
||
<div class="section-title">
|
||
<span class="icon" style="background:rgba(245,158,11,0.1);">📋</span>
|
||
实施计划
|
||
</div>
|
||
|
||
<table class="platform-table">
|
||
<thead>
|
||
<tr>
|
||
<th>阶段</th>
|
||
<th>内容</th>
|
||
<th>涉及文件</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
<td>
|
||
<strong>1. 修改入口按钮</strong><br>
|
||
profile_page 会员中心 → 桌面小部件<br>
|
||
路由 /member → /widget-management
|
||
</td>
|
||
<td>profile_page.dart, page_registry.dart, app_router.dart</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
<td>
|
||
<strong>2. 创建管理页面</strong><br>
|
||
WidgetManagementPage + Provider<br>
|
||
展示已安装/可添加小部件列表<br>
|
||
平台操作指引
|
||
</td>
|
||
<td>widget_management_page.dart, widget_provider.dart, widget_type.dart</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
<td>
|
||
<strong>3. 扩展 HomeWidgetService</strong><br>
|
||
新增日签/运势/倒计时/节气/签到数据推送<br>
|
||
统一数据 Key 管理
|
||
</td>
|
||
<td>home_widget_service.dart, widget_data_service.dart</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
<td>
|
||
<strong>4. Android 原生实现</strong><br>
|
||
8个 AppWidgetProvider + 布局 XML<br>
|
||
AndroidManifest 注册
|
||
</td>
|
||
<td>android/app/src/main/kotlin/com/xianyan/widget/</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-error">P0</span></td>
|
||
<td>
|
||
<strong>5. iOS Widget Extension</strong><br>
|
||
Xcode 添加 Widget Extension Target<br>
|
||
WidgetKit + SwiftUI 视图<br>
|
||
App Group 数据共享
|
||
</td>
|
||
<td>ios/XianyanWidgets/</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-warning">P1</span></td>
|
||
<td>
|
||
<strong>6. 鸿蒙 Form Extension</strong><br>
|
||
FormExtensionAbility + ArkUI<br>
|
||
module.json5 注册<br>
|
||
Preferences 数据共享
|
||
</td>
|
||
<td>ohos/entry/src/main/ets/widget/</td>
|
||
</tr>
|
||
<tr>
|
||
<td><span class="badge badge-accent">P2</span></td>
|
||
<td>
|
||
<strong>7. 交互式小部件</strong><br>
|
||
番茄钟实时刷新 (Android Glance)<br>
|
||
签到按钮交互<br>
|
||
iOS 17+ Button Intent
|
||
</td>
|
||
<td>PomodoroProvider, CheckinProvider</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<div class="info-banner info-banner-warn" style="margin-top:var(--space-3);">
|
||
<span class="info-banner-icon">⚠️</span>
|
||
<span class="info-banner-text">
|
||
<strong>注意事项:</strong><br>
|
||
1. iOS Widget Extension 需在 Xcode 中手动添加 Target,无法通过 Flutter CLI 自动完成<br>
|
||
2. 鸿蒙 Form Extension 需在 DevEco Studio 中配置,module.json5 需手动注册<br>
|
||
3. Android 的 requestPinWidget 仅部分启动器支持<br>
|
||
4. 番茄钟小部件在 iOS/鸿蒙上受系统限制,无法实时刷新倒计时<br>
|
||
5. 各平台小部件更新频率受系统限制(Android 最少30分钟,iOS 由系统决定)
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
function switchTab(event, tabId) {
|
||
const tabs = event.target.closest('.tabs');
|
||
const section = tabs.closest('.section');
|
||
|
||
tabs.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||
event.target.classList.add('active');
|
||
|
||
section.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
||
document.getElementById(tabId).classList.add('active');
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|