Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
6d9bf84
feat: encapsulate conditional exports with entry points
AustinChangLinksys Jan 9, 2026
577bf64
feat(dashboard): decompose widgets into atomic components for Bento Grid
AustinChangLinksys Jan 12, 2026
9f12509
feat(dashboard): refine constraints, lock topology, fix internet stat…
AustinChangLinksys Jan 12, 2026
1fe3601
feat(dashboard): Refactor Topology interaction, localize comments, an…
AustinChangLinksys Jan 12, 2026
b789a42
feat(dashboard): Enhance widget metadata, IoC support, and cancel edi…
AustinChangLinksys Jan 12, 2026
431fa81
feat: enhance dashboard interactivity and visual consistency
AustinChangLinksys Jan 13, 2026
56da1ec
feat(dashboard): improve custom layout dynamic constraints and UX
AustinChangLinksys Jan 14, 2026
d865b0c
feat(dashboard): isolate standard layout widgets into fixed_layout an…
AustinChangLinksys Jan 15, 2026
7eda0e7
refactor(dashboard): improve SliverDashboardView layout architecture
AustinChangLinksys Jan 15, 2026
77081a1
feat(dashboard): refine Expanded Mode layouts (Quick Panel, Speed Tes…
AustinChangLinksys Jan 15, 2026
ef65a03
feat(dashboard): add custom layout and localization
AustinChangLinksys Jan 16, 2026
1f27d9c
Merge origin/dev-2.0.0 into demo/custom-dashboard-layout
AustinChangLinksys Jan 16, 2026
258c67b
fix: use systemStatsState for cpuLoad/memoryLoad in dashboard service
AustinChangLinksys Jan 16, 2026
c10e9ff
fix: address PR review issues
AustinChangLinksys Jan 16, 2026
30da5b7
Refactor NodeLightSettings to Clean Architecture
AustinChangLinksys Jan 16, 2026
0204595
refactor(core): resolve P1 cross-page dependencies and fix test regre…
AustinChangLinksys Jan 16, 2026
ecb018f
refactor: fix P0 and P1 architecture violations
AustinChangLinksys Jan 16, 2026
37ca844
refactor: separate DeviceInfo into UI and JNAP protocol models
AustinChangLinksys Jan 19, 2026
a25e08e
fix(firmware-views): remove direct JNAP model imports from Views
AustinChangLinksys Jan 19, 2026
aa5103d
feat(dashboard): Implement A2UI widget extension with async loading a…
AustinChangLinksys Jan 19, 2026
59d4fb8
feat(a2ui): implement DBC assertions, remove hardcoded layouts, and r…
AustinChangLinksys Jan 20, 2026
85a8e91
feat: Enhance A2UI dashboard system with new widgets, actions, and va…
AustinChangLinksys Jan 23, 2026
dda0ef9
docs: translate documentation and test data to English
AustinChangLinksys Feb 3, 2026
f3b08d3
fix: address PR compliance issues (raw error exposure, HTML injection)
AustinChangLinksys Feb 3, 2026
83919d3
docs: translate accessibility examples to English
AustinChangLinksys Feb 3, 2026
54a1fca
Merge branch 'dev-2.0.0': Resolve conflicts in dashboard view, factor…
AustinChangLinksys Feb 3, 2026
687f9ba
refactor: address PR code suggestions (security, logic, cleanup)
AustinChangLinksys Feb 3, 2026
9b143ca
fix: resolve RenderFlex overflow in wifi_card.dart for small screens
AustinChangLinksys Feb 3, 2026
62e8365
fix: final cleanup (remove duplicate calls, fix syntax, revert import)
AustinChangLinksys Feb 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 70 additions & 70 deletions APPGAP_MAPPING.md
Original file line number Diff line number Diff line change
@@ -1,148 +1,148 @@
# AppGap 對照表 (AppGap Mapping Reference)
# AppGap Mapping Reference

## 基本對照表 (Basic Mapping)
## Basic Mapping

| privacygui_widgets | ui_kit_library | 像素值 (Pixels) | 使用場景 (Usage) |
| privacygui_widgets | ui_kit_library | Pixels | Usage |
|-------------------|----------------|----------------|------------------|
| `AppGap.small()` | `AppGap.xs()` | 4px | 最小間距 (Minimal spacing) |
| `AppGap.small2()` | `AppGap.sm()` | 8px | 小間距 (Small spacing) |
| `AppGap.small3()` | `AppGap.md()` | 12px | 預設間距 (Default spacing) |
| `AppGap.medium()` | `AppGap.lg()` | 16px | 中等間距 (Medium spacing) |
| `AppGap.large()` | `AppGap.xl()` | 20px | 大間距 (Large spacing) |
| `AppGap.large2()` | `AppGap.xxl()` | 24px | 特大間距 (Extra large spacing) |
| `AppGap.large3()` | `AppGap.xxxl()` | 32px | 最大間距 (Maximum spacing) |
| `AppGap.gutter()` | `AppGap.gutter()` | 16px | 版面溝槽 (Layout gutter) |
| `AppGap.small()` | `AppGap.xs()` | 4px | Minimal spacing |
| `AppGap.small2()` | `AppGap.sm()` | 8px | Small spacing |
| `AppGap.small3()` | `AppGap.md()` | 12px | Default spacing |
| `AppGap.medium()` | `AppGap.lg()` | 16px | Medium spacing |
| `AppGap.large()` | `AppGap.xl()` | 20px | Large spacing |
| `AppGap.large2()` | `AppGap.xxl()` | 24px | Extra large spacing |
| `AppGap.large3()` | `AppGap.xxxl()` | 32px | Maximum spacing |
| `AppGap.gutter()` | `AppGap.gutter()` | 16px | Layout gutter |

## 常見使用場景建議 (Common Usage Recommendations)
## Common Usage Recommendations

### 表單間距 (Form Spacing)
- **表單欄位間距**: `AppGap.md()` (12px) - 表單欄位之間
- **表單區塊間距**: `AppGap.lg()` (16px) - 表單區塊之間
- **標籤與輸入框**: `AppGap.xs()` (4px) - 標籤與輸入框之間
### Form Spacing
- **Form field spacing**: `AppGap.md()` (12px) - Between form fields
- **Form section spacing**: `AppGap.lg()` (16px) - Between form sections
- **Label and Input**: `AppGap.xs()` (4px) - Between label and input box

### 卡片間距 (Card Spacing)
- **卡片內部間距**: `AppGap.lg()` (16px) - 卡片內容間距
- **卡片外部邊距**: `AppGap.sm()` (8px) - 卡片之間的間距
### Card Spacing
- **Internal card spacing**: `AppGap.lg()` (16px) - Padding within cards
- **External card margin**: `AppGap.sm()` (8px) - Spacing between cards

### 按鈕間距 (Button Spacing)
- **按鈕群組間距**: `AppGap.sm()` (8px) - 按鈕群組內按鈕間距
- **按鈕區塊間距**: `AppGap.lg()` (16px) - 按鈕區塊之間
### Button Spacing
- **Button group spacing**: `AppGap.sm()` (8px) - Spacing between buttons in a group
- **Button block spacing**: `AppGap.lg()` (16px) - Between button blocks

### 版面間距 (Layout Spacing)
- **頁面區塊間距**: `AppGap.xl()` (20px) - 主要頁面區塊間
- **清單項目間距**: `AppGap.sm()` (8px) - 清單項目之間
- **主要標題間距**: `AppGap.xxxl()` (32px) - 重要標題區塊
### Layout Spacing
- **Page section spacing**: `AppGap.xl()` (20px) - Between major page sections
- **List item spacing**: `AppGap.sm()` (8px) - Between list items
- **Main heading spacing**: `AppGap.xxxl()` (32px) - For important heading sections

### 元件間距 (Component Spacing)
- **圖標文字間距**: `AppGap.xs()` (4px) - 圖標與文字之間
- **開關元件間距**: `AppGap.sm()` (8px) - 開關與標籤之間
### Component Spacing
- **Icon and Text spacing**: `AppGap.xs()` (4px) - Between icon and text
- **Toggle component spacing**: `AppGap.sm()` (8px) - Between toggle and label

## 解決命名衝突 (Resolving Naming Conflicts)
## Resolving Naming Conflicts

當同時導入兩個庫時,使用 `hide` 來避免衝突:
When importing both libraries at the same time, use `hide` to avoid conflicts:

```dart
// 隱藏 ui_kit_library 的 AppGap
// Hide AppGap from ui_kit_library
import 'package:ui_kit_library/ui_kit.dart' hide AppGap;
import 'package:privacygui_widgets/widgets/gap/gap.dart';

// 或者隱藏 privacygui_widgets 的 AppGap
// Or hide AppGap from privacygui_widgets
import 'package:privacygui_widgets/widgets/_widgets.dart' hide AppGap;
import 'package:ui_kit_library/ui_kit.dart';
```

## 使用映射工具 (Using Mapping Utilities)
## Using Mapping Utilities

```dart
import 'package:privacy_gui/util/appgap_mapping.dart';

// 取得對應間距
Widget gap = AppGapMapper.getUiKitGap('medium'); // 返回 AppGap.lg()
Widget gap2 = AppGapMapper.getPrivacyGap('lg'); // 返回 AppGap.medium()
// Get corresponding gap
Widget gap = AppGapMapper.getUiKitGap('medium'); // Returns AppGap.lg()
Widget gap2 = AppGapMapper.getPrivacyGap('lg'); // Returns AppGap.medium()

// 使用擴展方法
// Use extension methods
Widget gap3 = 'medium'.toGap(useUiKit: true); // ui_kit AppGap.lg()
double pixels = 'medium'.gapPixels; // 16.0

// 轉換間距系統
// Convert gap systems
String uiKitSize = 'medium'.toUiKitGap(); // 'lg'
String privacySize = 'lg'.toPrivacyGap(); // 'medium'
```

## 遷移指南 (Migration Guide)
## Migration Guide

### 步驟 1:識別現有用法
### Step 1: Identify existing usage
```dart
// 舊代碼 (privacygui_widgets)
// Old code (privacygui_widgets)
const AppGap.small2(),
const AppGap.medium(),
const AppGap.large3(),
```

### 步驟 2:轉換到新格式
### Step 2: Convert to new format
```dart
// 新代碼 (ui_kit_library)
AppGap.sm(), // 替代 AppGap.small2()
AppGap.lg(), // 替代 AppGap.medium()
AppGap.xxxl(), // 替代 AppGap.large3()
// New code (ui_kit_library)
AppGap.sm(), // Alternative to AppGap.small2()
AppGap.lg(), // Alternative to AppGap.medium()
AppGap.xxxl(), // Alternative to AppGap.large3()
```

### 步驟 3:更新導入語句
### Step 3: Update import statements
```dart
// 添加 hide 子句避免衝突
// Add hide clauses to avoid conflicts
import 'package:ui_kit_library/ui_kit.dart' hide AppGap, AppText;
import 'package:privacygui_widgets/widgets/gap/gap.dart';
import 'package:privacygui_widgets/widgets/text/app_text.dart';
```

## 常見錯誤與解決方案 (Common Issues & Solutions)
## Common Issues & Solutions

### 錯誤 1: `prefix_shadowed_by_local_declaration`
### Issue 1: `prefix_shadowed_by_local_declaration`
```dart
// 問題: AppGap 被本地聲明遮蔽
// Problem: AppGap is shadowed by a local declaration
error - The prefix 'AppGap' can't be used here because it's shadowed by a local declaration.

// 解決方案: 使用 hide 隱藏衝突的名稱
// Solution: Use hide to hide conflicting names
import 'package:ui_kit_library/ui_kit.dart' hide AppGap;
```

### 錯誤 2: `ambiguous_import`
### Issue 2: `ambiguous_import`
```dart
// 問題: 兩個庫都定義了相同名稱
// Problem: Both libraries define the same name
error - The name 'AppGap' is defined in multiple libraries.

// 解決方案: 使用別名或隱藏
// Solution: Use aliases or hide
import 'package:ui_kit_library/ui_kit.dart' as UiKit;
import 'package:privacygui_widgets/widgets/gap/gap.dart' as PrivacyGap;
```

### 錯誤 3: 屬性名稱不匹配
### Issue 3: Property name mismatch
```dart
// ui_kit_library 使用簡化名稱
AppGap.sm() // ✓ 正確
AppGap.small2() // ✗ 錯誤 - 這是 privacygui_widgets 語法
// ui_kit_library uses simplified names
AppGap.sm() // ✓ Correct
AppGap.small2() // ✗ Incorrect - This is privacygui_widgets syntax
```

## 最佳實踐 (Best Practices)
## Best Practices

1. **保持一致性**: 在單一檔案中使用同一套間距系統
2. **使用語意化名稱**: 優先使用 `AppGapMapper.getRecommendedSpacing('form_field')`
3. **避免硬編碼**: 使用預定義的間距值而非自定義像素
4. **測試響應式**: 確保間距在不同螢幕尺寸下正常顯示
1. **Maintain Consistency**: Use a single gap system within a single file.
2. **Use Semantic Names**: Prefer `AppGapMapper.getRecommendedSpacing('form_field')`.
3. **Avoid Hard-coding**: Use predefined gap values instead of custom pixels.
4. **Test Responsiveness**: Ensure spacing displays correctly across different screen sizes.

## 工具類使用範例 (Utility Examples)
## Utility Examples

```dart
// 取得所有可用間距
// Get all available gap sizes
Map<String, double> gaps = AppGapMapper.getAllGapSizes();

// 驗證間距大小
// Validate gap size
bool isValid = AppGapMapper.isValidGapSize('medium'); // true

// 取得建議間距
// Get recommended spacing
Widget spacing = AppGapMapper.getRecommendedSpacing('form_field');

// 使用常數
// Use constants
Widget box = AppGapConstants.lgBox; // SizedBox(height: 16, width: 16)
Widget vertical = AppGapConstants.lgVertical; // SizedBox(height: 16)
```
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,13 @@ To run tests that are specifically tagged for UI widgets (and are not screenshot

```bash
flutter test --tags ui

```

## ♿ Accessibility (WCAG)

PrivacyGUI adheres to WCAG 2.1 Level AA standards. For detailed documentation on accessibility testing, integration, and compliance analysis, please refer to the **[Accessibility Documentation](doc/accessibility/README.md)**.

## Contributing

Please follow the existing code style and conventions. Ensure that any new feature or bug fix is accompanied by relevant tests.
73 changes: 73 additions & 0 deletions assets/a2ui/widgets/device_count.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"widgetId": "a2ui_device_count",
"displayName": "Connected Devices",
"description": "Shows the number of connected devices with navigation to device list",
"constraints": {
"minColumns": 2,
"maxColumns": 4,
"preferredColumns": 3,
"minRows": 2,
"maxRows": 3,
"preferredRows": 2
},
"template": {
"type": "Card",
"properties": {
"padding": 16.0,
"onTap": {
"$action": "navigation.push",
"params": {
"route": "menuInstantDevices"
}
},
"style": {
"elevation": 2,
"borderRadius": 12
}
},
"children": [
{
"type": "Column",
"properties": {
"mainAxisAlignment": "center",
"crossAxisAlignment": "center",
"mainAxisSize": "min"
},
"children": [
{
"type": "Icon",
"properties": {
"icon": "devices",
"size": 32.0,
"color": "primary"
}
},
{
"type": "SizedBox",
"properties": {
"height": 8.0
}
},
{
"type": "Text",
"properties": {
"text": {
"$bind": "router.deviceCount"
},
"variant": "headlineMedium",
"color": "primary"
}
},
{
"type": "Text",
"properties": {
"text": "Connected Devices",
"variant": "bodyMedium",
"textAlign": "center"
}
}
]
}
]
}
}
Loading