Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94138ba7f4 | ||
|
|
33b54fe454 | ||
|
|
901e42a41b | ||
|
|
af8934fe7f | ||
|
|
048c5a9ff4 | ||
|
|
1d4028f486 | ||
|
|
944493a39b | ||
|
|
6d08db54a5 | ||
|
|
3f9256491d | ||
|
|
95e40f31cc | ||
|
|
639d2033f0 | ||
|
|
4da7fb32de | ||
|
|
147ab866e1 | ||
|
|
0526baa3c8 | ||
|
|
b49fb59db4 | ||
|
|
9608e8b9fb | ||
|
|
5ccc06b0f7 | ||
|
|
7c69197396 | ||
|
|
137eca4c69 | ||
|
|
b8b70a87f9 | ||
|
|
3053246bb8 | ||
|
|
5cb5ef6396 | ||
|
|
a6d5b9cd2d | ||
|
|
18abf4eb82 | ||
|
|
70076d71c1 | ||
|
|
6487c0db54 | ||
|
|
ab06fadea8 | ||
|
|
1aa7cf3477 | ||
|
|
3ed58e1596 | ||
|
|
97e4908126 | ||
|
|
154d696e70 | ||
|
|
36f36b815f | ||
|
|
6d789c7b19 | ||
|
|
cdaaa63d67 | ||
|
|
f1d7dbb423 | ||
|
|
a76b872966 | ||
|
|
c21ccbd54d | ||
|
|
fce670664b | ||
|
|
8f3d3509ea | ||
|
|
e2f0d37edd | ||
|
|
1f85ae1e63 | ||
|
|
e2f815e141 | ||
|
|
f831fd1405 | ||
|
|
7e8182259f | ||
|
|
88dd90ed7c | ||
|
|
ae4c4046c3 | ||
|
|
cef00db911 | ||
|
|
4f9aa4f683 | ||
|
|
1a578c925d | ||
|
|
7ffcc848d0 |
@@ -0,0 +1,250 @@
|
|||||||
|
# TODO — Flutter Wisetronic Dart 3 空安全迁移
|
||||||
|
|
||||||
|
> ## ✅ Web 构建已成功!(2026-08-01)
|
||||||
|
> **`flutter build web --no-tree-shake-icons` → ✓ Built build/web/(main.dart.js 4.5M)**
|
||||||
|
> - `dart analyze lib`: 仅剩 **6 error**,全部在 `utils/util_io.dart`(原生路径,Web 已排除,见 §5 延后)。
|
||||||
|
> - Web 可达错误: **0**。
|
||||||
|
> - 峰值 2374 → 6(全部 util_io 原生)。0 语法损坏。分支 `dev2`。
|
||||||
|
> - 构建脚本: `./build_web.sh`(构建)/ `./build_web.sh run`(Chrome 运行)。
|
||||||
|
> - **关键修复**: `cross_file` override 到 `0.3.4+2`(旧版 0.3.1+4 用了 Dart3 移除的 `UnmodifiableUint8ListView`;0.3.5+ 需 Dart 3.10)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 快速恢复(Resume 起点)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /Users/peima/StudioProjects/flutter_wisetronic
|
||||||
|
git log --oneline -1 # 确认在最新提交
|
||||||
|
dart analyze lib | tail -5 # 当前: 仅 6 error(util_io.dart)
|
||||||
|
./build_web.sh # 构建: ✓ Built build/web/
|
||||||
|
./build_web.sh run # Chrome 运行调试
|
||||||
|
|
||||||
|
# 重跑自动修复脚本(安全,带损坏自检,可随时跑)—— 已无 web 可达错误,通常无需再跑
|
||||||
|
python3 tools/nullfix.py --max-rounds 12
|
||||||
|
```
|
||||||
|
|
||||||
|
**核心原则**:每次改动后用 `dart analyze lib | grep -cE '\s+error\s+-'` 数错误;脚本若报"检测到语法损坏"会自动中止,`git checkout -- lib` 回滚。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 剩余错误分布(118 个)
|
||||||
|
|
||||||
|
| 规则 | 数量 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `unchecked_use_of_nullable_value` | 44 | 可空值当非空用(方法调用/条件/迭代器,多为多行) |
|
||||||
|
| `invalid_assignment` | 34 | 赋值类型不匹配(复杂表达式) |
|
||||||
|
| `argument_type_not_assignable` | 22 | 参数类型不匹配(三元/比较/Map字面量) |
|
||||||
|
| `return_of_invalid_type_from_closure` | 4 | 闭包返回类型 |
|
||||||
|
| `undefined_getter` | 3 | 多为 `.buttonColor`(Flutter 3 移除) |
|
||||||
|
| `return_of_invalid_type` | 3 | 函数 `return null` 但返回类型非空 |
|
||||||
|
| `undefined_named_parameter` | 2 | |
|
||||||
|
| `undefined_method` | 2 | |
|
||||||
|
| `creation_with_non_type` | 2 | 类名拼错(util_io 内) |
|
||||||
|
| `extra_positional_arguments_could_be_named` | 1 | |
|
||||||
|
| `body_might_complete_normally` | 1 | |
|
||||||
|
|
||||||
|
**错误最多的文件**(详细见 `dart analyze lib`):
|
||||||
|
|
||||||
|
```
|
||||||
|
6 utils/util_io.dart ← 延后(仅原生,Web 构建已排除)
|
||||||
|
5 widgets/desktop/desktop_edit_address.dart ← .trim() 多行(见 §3,已知修法)
|
||||||
|
5 widgets/mobile/mobile_edit_address.dart ← 同上
|
||||||
|
5 widgets/general/add_remove_button.dart
|
||||||
|
5 widgets/general/parabolic_animation_widget.dart
|
||||||
|
5 widgets/general/sliding_up_panel.dart
|
||||||
|
4 widgets/desktop/desktop_me.dart
|
||||||
|
4 widgets/mobile/mobile_attribute_selection.dart
|
||||||
|
4 widgets/mobile/mobile_order_detail.dart
|
||||||
|
3 widgets/desktop/desktop_coupons.dart / desktop_my_support / desktop_order_detail / shop_products
|
||||||
|
3 widgets/general/animation_point_manager / popup_animation_widget
|
||||||
|
3 widgets/mobile/mobile_coupons / mobile_me / mobile_my_support / mobile_orders / shopping_cart_bar
|
||||||
|
2 约 12 个文件(blog/orders/product_item/shopping_cart 等)
|
||||||
|
1 约 25 个文件(单点错误)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 推荐处理顺序
|
||||||
|
|
||||||
|
1. **edit_address(5+5)** — 已知修法,见 §3,最快。
|
||||||
|
2. **parabolic/popup_animation(5+3)** — `late` 字段已修,可能还有 unchecked_use(offset 计算方法调用),手动看。
|
||||||
|
3. **sliding_up_panel(5)** — 第三方面板 widget 适配,手动。
|
||||||
|
4. **add_remove_button(5)** — badges 相关,手动。
|
||||||
|
5. **散落的 2-error / 1-error 文件** — 用 `dart analyze lib/<file>` 逐个看,多为加 `!`。
|
||||||
|
6. **util_io.dart(6)** — 最后处理(见 §5),不影响 Web 构建。
|
||||||
|
|
||||||
|
**目标**:先清掉 Web 可达错误(`flutter build web` 的 112),让 Web 能跑;`util_io` 原生路径可延后。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 已知具体修法(直接套用)
|
||||||
|
|
||||||
|
### 3.1 edit_address `.trim()` 多行(desktop + mobile,各 5 处)
|
||||||
|
错误:`A nullable expression can't be used to invoke 'trim'`。代码结构:
|
||||||
|
```dart
|
||||||
|
validator: (String? value) {
|
||||||
|
if (value // ← value 是 String?
|
||||||
|
.trim()
|
||||||
|
.isEmpty) {
|
||||||
|
```
|
||||||
|
**修法**:把 `if (value` 行改成 `if (value!`。
|
||||||
|
```python
|
||||||
|
# 上次脚本 bug:用了 rstrip() 应该用 strip()。正确版:
|
||||||
|
for p in ['lib/widgets/desktop/desktop_edit_address.dart','lib/widgets/mobile/mobile_edit_address.dart']:
|
||||||
|
lines=open(p).read().split('\n'); n=0
|
||||||
|
for i in range(len(lines)):
|
||||||
|
if lines[i].strip()=='if (value' and lines[i+1].lstrip().startswith('.trim()'):
|
||||||
|
lines[i]=lines[i].rstrip()+'!'; n+=1 # 注意 rstrip() 保留前导缩进
|
||||||
|
open(p,'w').write('\n'.join(lines))
|
||||||
|
```
|
||||||
|
(`.buttonColor`→`.colorScheme.primary` 已在两个文件修好。)
|
||||||
|
|
||||||
|
### 3.2 通用模式(手动加 `!` / `?? 默认` / `== true`)
|
||||||
|
- `String? → String` 参数:`field` → `field!`(确认运行时非空)。
|
||||||
|
- `num?/int?/double?` 比较:`subtotal > minPrice` → `subtotal > minPrice!` 或 `(minPrice ?? 0)`。
|
||||||
|
- `bool?` 当条件:`if (x)` → `if (x == true)`;`if (!x)` → `if (x != true)`。
|
||||||
|
- `return null;` 但返回类型非空:把函数返回类型加 `?`(如 `CategoryProducts? foo()`)。
|
||||||
|
- 局部变量赋值 nullable:声明加 `?`(如 `Map<String,dynamic>? x = ...`),下游 nullfix 会补 `!`。
|
||||||
|
- 多行方法调用 `.toUpperCase()` / `.trim()`:接收者在上一行末尾,在该行末尾加 `!`。
|
||||||
|
|
||||||
|
### 3.3 可复用的定向脚本(一次性,贴进 bash 跑)
|
||||||
|
|
||||||
|
**a) 条件修复(analyzer 驱动,只修简单 `if (chain)`)** — 已用过,安全:
|
||||||
|
```python
|
||||||
|
python3 -c "
|
||||||
|
import re,subprocess
|
||||||
|
ERR=re.compile(r'\s+error\s+-\s+([\w/.\-]+):(\d+):(\d+)\s+-\s+(.*?)\s+-\s+([a-z_]+)\s*\$')
|
||||||
|
pat=re.compile(r'^(\s*if \()(!?)([\w.!\[\]]+)(\)\s*\{?\s*)\$')
|
||||||
|
out=subprocess.run(['dart','analyze','lib'],capture_output=True,text=True).stdout
|
||||||
|
tg={}
|
||||||
|
for ln in out.splitlines():
|
||||||
|
m=ERR.match(ln)
|
||||||
|
if m and 'used as a condition' in m.group(4): tg.setdefault('lib/'+m.group(1),set()).add(int(m.group(2)))
|
||||||
|
n=0
|
||||||
|
for p,ls in tg.items():
|
||||||
|
L=open(p).read().split('\n');ch=False
|
||||||
|
for i,x in enumerate(L,1):
|
||||||
|
if i in ls:
|
||||||
|
m=pat.match(x.rstrip('\n'))
|
||||||
|
if m: L[i-1]=m.group(1)+m.group(3)+(' != true' if m.group(2) else ' == true')+m.group(4);ch=True;n+=1
|
||||||
|
if ch: open(p,'w').write('\n'.join(L))
|
||||||
|
print('fixed',n)
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
**b) 局部变量改可空(严格类型,已验证安全)** — 跑完再 `python3 tools/nullfix.py` 吃级联:
|
||||||
|
```python
|
||||||
|
python3 -c "
|
||||||
|
import re,subprocess
|
||||||
|
ERR=re.compile(r'\s+error\s+-\s+([\w/.\-]+):(\d+):(\d+)\s+-\s+(.*?)\s+-\s+([a-z_]+)\s*\$')
|
||||||
|
NAMEQ=re.compile(r\"'([^']+)'\"); TYPE=r'(?:[A-Z]\w*(?:<[^;]*>)?|int|double|String|bool|num|dynamic|List<[^;]*>|Map<[^;]*>|Set<[^;]*>)'
|
||||||
|
out=subprocess.run(['dart','analyze','lib'],capture_output=True,text=True).stdout;tg={}
|
||||||
|
for ln in out.splitlines():
|
||||||
|
m=ERR.match(ln)
|
||||||
|
if m and m.group(5)=='not_assigned_potentially_non_nullable_local_variable':
|
||||||
|
nm=NAMEQ.search(m.group(4))
|
||||||
|
if nm: tg.setdefault('lib/'+m.group(1),[]).append((int(m.group(2)),nm.group(1)))
|
||||||
|
dp=re.compile(r'^(\s+(?:final\s+|const\s+)?)('+TYPE+r')\s+(\w+)\s*;\s*\$');n=0
|
||||||
|
for p,it in tg.items():
|
||||||
|
L=open(p).read().split('\n');ch=False;done=set()
|
||||||
|
for ul,nm in it:
|
||||||
|
if (ul,nm) in done: continue
|
||||||
|
done.add((ul,nm))
|
||||||
|
for i in range(ul-2,-1,-1):
|
||||||
|
m=dp.match(L[i])
|
||||||
|
if m and m.group(3)==nm and '?' not in m.group(2): L[i]=m.group(1)+m.group(2)+'? '+nm+';';ch=True;n+=1;break
|
||||||
|
if ch: open(p,'w').write('\n'.join(L))
|
||||||
|
print('fixed',n)
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 工具脚本说明(`tools/`)
|
||||||
|
|
||||||
|
### `tools/nullfix.py` — 主力自动修复
|
||||||
|
```bash
|
||||||
|
python3 tools/nullfix.py # 修整个 lib,默认 5 轮
|
||||||
|
python3 tools/nullfix.py --max-rounds 12
|
||||||
|
python3 tools/nullfix.py lib/widgets/mobile/shop.dart # 只修单文件
|
||||||
|
```
|
||||||
|
- 每轮重新 `dart analyze lib`,按 error 的 (file,line,col) 精确定位修改。
|
||||||
|
- **带腐败自检**:每轮后检测 `expected_token`/`missing_identifier`,一旦 >0 立即中止并提示 `git diff`。
|
||||||
|
- 已实现的 handler:
|
||||||
|
- `insert_bang`:成员访问/方法调用/迭代器/return 加 `!`(按 analyzer 分类)
|
||||||
|
- `insert_arg_bang`:`argument_type`/`invalid_assignment` 在参数值末尾加 `!`(值必须是简单标识符链 `[\w.\[\]()!]`,含运算符/空格跳过)
|
||||||
|
- `late` 实例字段、参数空安全、field-formal 字段空安全
|
||||||
|
- `missing_default_value_for_parameter`、`@required`→`required` 已并入
|
||||||
|
- **已禁用的危险 handler**:基于正则的 `if(x)`→`if(x==true)`(曾破坏 89 文件)。条件修复改用 §3.3a 的 analyzer 驱动版。
|
||||||
|
- **已知边界**:多行表达式(接收者跨行)、含空格/逗号的函数调用参数、三元/比较表达式 → 跳过,需手动。
|
||||||
|
|
||||||
|
### `tools/badge_migrate.py` — 未验证,**已不需要**
|
||||||
|
badges 3.x 迁移已手动完成(`badgeStyle`/`badgeAnimation`),此脚本可忽略/删除。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 延后项
|
||||||
|
|
||||||
|
### `lib/utils/util_io.dart`(6 error,仅原生)
|
||||||
|
- 通过 `dart.library.html` 条件导入从 **Web 构建中排除**,不影响 `flutter build web`。
|
||||||
|
- 错误来自 `flutter_local_notifications` v17 API 变更:
|
||||||
|
- `IOSInitializationSettings` / `IOSNotificationDetails` → v17 改名(`DarwinInitializationSettings` / `DarwinNotificationDetails`)
|
||||||
|
- `onSelectNotification` 参数已移除
|
||||||
|
- `extra_positional_arguments`(构造参数变化)
|
||||||
|
- `body_might_complete_normally`(`Future<void>` 缺 return)
|
||||||
|
- 原生(Android/iOS)构建时才需要修。Web 不阻塞。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 关键上下文 / 决策(避免踩坑)
|
||||||
|
|
||||||
|
- **`late` 用于实例字段**:避免模型 `fromJson` 初始化列表 + State 类的级联错误。模型字段置为可空,调用点加 `!`。
|
||||||
|
- **脚本必须 analyzer 驱动**:盲目正则会损坏代码(如 `return? item;`、`this.?field`)。`nullfix.py` 用 analyzer 的列/列定位 + 腐败自检是关键。
|
||||||
|
- **badges 实际解析 3.2.0**(不是 2.0.3):参数是 `badgeStyle:`/`badgeAnimation:`(不是 `badgeColor`/`animationType`/`animation`)。
|
||||||
|
- **pinput 实际 5.0.2**:类名 `Pinput`(非 `PinPut`),导入 `package:pinput/pinput.dart`,`length`/`onCompleted`/`defaultPinDecoration`。
|
||||||
|
- **youtube_player_iframe 5.2.2**:`YoutubePlayerController.fromVideoId(videoId:, startSeconds:, params:)`。
|
||||||
|
- **BreadCrumb.route 已改可空**:`String? route`,调用点 `BreadCrumb(X, null)` 合法。
|
||||||
|
- **e-Transfer**:Stripe 已全移除,付款走 `payment@wisetronic.com`,备注写 `R#<receipt.id>`。
|
||||||
|
- **搜索框**:自写轻量 `lib/widgets/general/search_bar.dart`(非第三方包)。
|
||||||
|
- **不升级全局 Flutter SDK**:用本地 Flutter 3.29.3 / Dart 3.7.2。
|
||||||
|
|
||||||
|
## 7. 提交历史(基线 f8a90ad 之后)
|
||||||
|
|
||||||
|
```
|
||||||
|
最新 phase3: mobile/shop clean ... 131->118 ← resume 起点
|
||||||
|
phase3: checkout files clean ... 142->131
|
||||||
|
phase3: fix attribute widgets ... ~30 fixed
|
||||||
|
phase3: FIX arg-bang regex (missing \]) ... 235->183 ← 关键 bug 修复
|
||||||
|
...(共约 28 个 phase3 提交)
|
||||||
|
f8a90ad 基线
|
||||||
|
```
|
||||||
|
|
||||||
|
## 8. 最终验收
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flutter build web # 目标:无 error,生成 build/web
|
||||||
|
flutter run -d chrome # 目标:能打开、首页/商品/购物车/结账流程跑通
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 运行时问题(应用已能运行,以下为后续优化,非阻塞)
|
||||||
|
|
||||||
|
应用 `flutter run -d chrome` 已成功启动并加载首页/API 数据/数据库。控制台有以下运行时警告/异常:
|
||||||
|
|
||||||
|
### 9.1 Scrollbar 缺 ScrollPosition(真实,影响滚动条显示)
|
||||||
|
4 个 `Scrollbar(` 未配 `controller`,新版 Flutter 的 Scrollbar 找不到 ScrollPosition:
|
||||||
|
- `lib/pages/home.dart:101` — ✅ 已修:给 `SingleChildScrollView` 加 `primary: true`
|
||||||
|
- `lib/pages/blog.dart:24` — 子是 `DesktopBlog`(自定义组件)
|
||||||
|
- `lib/pages/download.dart:63` — 子是 `DesktopDownloadApps`(自定义组件)
|
||||||
|
- `lib/widgets/desktop/shop.dart:137` — 包裹 `NotificationListener`
|
||||||
|
|
||||||
|
后 3 处的子是自定义组件,需让内部 ListView/ScrollView 暴露 controller(设 `primary: true`)或 Scrollbar 改用 `NotificationListener` 关联。**仅影响滚动条渲染,不影响内容加载/显示。**
|
||||||
|
|
||||||
|
### 9.2 CustomersLogo setState-after-dispose(小 bug)
|
||||||
|
`lib/widgets/desktop/desktop_customers_logo.dart` 的 `Timer.periodic`(每 10s 刷新 logo)未在 `dispose()` 里 `cancel()`,组件卸载后 timer 仍触发 `setState`。建议在 `dispose` 里 `timer?.cancel()`。**热重载时易触发,干净启动偶发。**
|
||||||
|
|
||||||
|
### 9.3 `_business` LateInitializationError(热重载假象)
|
||||||
|
`_business` 是店铺页面组件(`shop_promote.dart`/`shop.dart` 等)的 `late Business` 字段。热重载重建 widget 树时字段状态丢失触发,**干净启动(浏览器刷新 Cmd+R)不会出现**。
|
||||||
|
|
||||||
|
> **验证方式**:在浏览器里 Cmd+R 刷新页面(而非热重载),9.2/9.3 类异常应消失,仅剩 9.1 的滚动条警告。
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
# flutter_wisetronic 升级日志
|
||||||
|
|
||||||
|
## 目标
|
||||||
|
- 升级到 Dart 3 强制空安全(目标 SDK:本机 Flutter 3.29.3 / Dart 3.7.2,不升级全局)
|
||||||
|
- 移除 Stripe 收款,改为页面展示 e-transfer email 让客户自行 e-transfer 付款
|
||||||
|
- 第一阶段:能编译、Web 能跑起来(暂不美化)
|
||||||
|
|
||||||
|
## 关键决策
|
||||||
|
- 目标版本:Flutter 3.29.3 / Dart 3.7.2(钉定本机,不动全局)
|
||||||
|
- e-transfer 邮箱:`payment@wisetronic.com`
|
||||||
|
- 提醒客户在 e-transfer remark 里写 `R#<receipt.id>` 以便自动化处理订单
|
||||||
|
- 搜索框:自写轻量 Web 搜索组件替换 flappy_search_bar
|
||||||
|
- Dart 3 已移除 `dart migrate`,空安全迁移用手工 + IDE 修复
|
||||||
|
|
||||||
|
## 阶段
|
||||||
|
- [x] 阶段 0:基线 & 锁版本
|
||||||
|
- [x] 阶段 1:去掉 Stripe
|
||||||
|
- [x] 阶段 2:依赖替换与升级
|
||||||
|
- [ ] 阶段 3:空安全迁移
|
||||||
|
- [ ] 阶段 4:Web 跑起来
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 改动记录
|
||||||
|
|
||||||
|
### 阶段 0
|
||||||
|
- 创建 UPGRADE_NOTES.md
|
||||||
|
- pubspec.yaml: environment sdk `>=2.7.0 <3.0.0` → `>=3.0.0 <4.0.0`,flutter `>=3.29.0`
|
||||||
|
|
||||||
|
### 阶段 1 — 去掉 Stripe(已完成)
|
||||||
|
- 删除: stripe_pay_web.dart, stripe_pay.dart, desktop/mobile_stripe_pay_web.dart, stripe_payment_method.dart
|
||||||
|
- pubspec: 移除 stripe_payment + stripe_sdk(git)
|
||||||
|
- user.dart: 移除 stripePaymentMethods 字段与解析
|
||||||
|
- utils.dart: 移除 createOrUpdateStripePaymentMethod / stripePaymentIntent / stripeChargedSuccess
|
||||||
|
- util_web.dart / util_io.dart: goPayment 的 stripe/native 分支 → 跳转 ETransferPay
|
||||||
|
- desktop/mobile_pay_now.dart: 移除“已有卡片”区块与 nativePay 死逻辑,简化列表索引
|
||||||
|
- desktop/mobile_my_cards.dart: 重写为 e-Transfer 说明页(保留路由入口)
|
||||||
|
- constants.dart: 新增 ETRANSFER_EMAIL(payment@wisetronic.com) 与 REMARK_PREFIX(R#)
|
||||||
|
- 新增 lib/widgets/general/e_transfer_pay.dart: 展示邮箱 + 提醒备注写 R#<orderId>
|
||||||
|
- 保留: PAYMENT_METHOD_CODE_STRIPE='stripe'(API 仍返回该 code,路由到 e-Transfer);payment_platform.dart 的 'stripe' 显示名(后续美化时调整)
|
||||||
|
|
||||||
|
### 阶段 2 — 依赖替换与升级(已完成)
|
||||||
|
**flutter pub get 成功解析 178 个依赖。**
|
||||||
|
- 升级到 null-safe 最新版:dio ^5.7、cached_network_image ^3.4、url_launcher ^6.3、path_provider ^2.1、image_picker ^1.1、google_maps_flutter ^2.9、geolocator ^12、youtube_player_iframe ^5.2、flutter_local_notifications ^17、uuid ^4、fluttertoast ^8.2、badges ^3、carousel_slider ^5、percent_indicator ^4.2.3、photo_view ^0.15、toggle_switch ^2.3、pinput ^5、email_validator ^3、responsive_builder ^0.7、flutter_redux ^0.10、fluro ^2.0.5、font_awesome_flutter ^10、flutter_spinkit ^5.2、flutter_markdown ^0.7、url_strategy ^0.3、universal_io/html
|
||||||
|
- 删除(0引用或无 null-safe 版):splashscreen(死代码)、flappy_search_bar、searchable_dropdown、share、platform_detect、flutter_inappwebview、countdown、gender_selection、flutter_dash(死 import)、smooth_star_rating、hovering、ffi
|
||||||
|
- 新增:flutter_rating_bar ^4.0
|
||||||
|
- 停维但有 null-safe 版→暂留(Phase 5 再换):pull_to_refresh(→smart_refresher)、hive/hive_flutter(→hive_ce)、catcher ^0.8(→catcher2)
|
||||||
|
- 新建 null-safe 自定义组件替代废弃包(API 兼容, 调用方仅改 import):
|
||||||
|
- lib/utils/countdown.dart (CountDown.stream)
|
||||||
|
- lib/widgets/general/hover_widget.dart (HoverWidget)
|
||||||
|
- lib/widgets/general/gender_selection.dart (Gender 枚举 + GenderSelection)
|
||||||
|
- lib/widgets/general/smooth_star_rating.dart (SmoothStarRating)
|
||||||
|
- lib/widgets/general/search_bar.dart (轻量 Web 搜索 SearchBar + SearchBarController, 含 replayLastSearch 分页)
|
||||||
|
- main.dart:删除未使用的 _buildBody(SplashScreen) 与 _to 字段
|
||||||
|
- ⚠️ 待 Phase 3:API 升级破坏性变更(dio5/badges3/toggle_switch2/pinput5/geolocator12 等用法适配) + 整库空安全迁移,按 dart analyze 驱动修复
|
||||||
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Flutter Wisetronic — Web 构建脚本
|
||||||
|
# 用法:
|
||||||
|
# ./build_web.sh # 构建 release 版本到 build/web/
|
||||||
|
# ./build_web.sh run # 构建并在 Chrome 中运行调试版
|
||||||
|
#
|
||||||
|
# 说明:
|
||||||
|
# - 构建(release)必须 --no-tree-shake-icons: 项目中有 24 处 IconData(codePoint)
|
||||||
|
# 使用来自 JSON/API 的动态 code point(非 const), icon tree-shaking 无法处理。
|
||||||
|
# 注意: --no-tree-shake-icons 仅 build 支持; flutter run(debug)不做 tree-shaking,
|
||||||
|
# 因此 run 分支不带该 flag。
|
||||||
|
# - Dart SDK: 本地 Flutter 3.29.3 / Dart 3.7.2(未升级全局 SDK)。
|
||||||
|
set -e
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
if [ "$1" = "run" ]; then
|
||||||
|
echo ">>> flutter run -d chrome"
|
||||||
|
flutter run -d chrome
|
||||||
|
else
|
||||||
|
echo ">>> flutter build web --no-tree-shake-icons"
|
||||||
|
flutter build web --no-tree-shake-icons
|
||||||
|
echo ""
|
||||||
|
echo "✓ 构建完成: build/web/ (main.dart.js: $(du -h build/web/main.dart.js | cut -f1))"
|
||||||
|
echo " 本地预览: python3 -m http.server --directory build/web 8080"
|
||||||
|
echo " 然后访问 http://localhost:8080/"
|
||||||
|
fi
|
||||||
+6
-4
@@ -49,13 +49,15 @@ class Constants {
|
|||||||
static const String PAYMENT_METHOD_CODE_OTT_ALIPAY = 'ALIPAY';
|
static const String PAYMENT_METHOD_CODE_OTT_ALIPAY = 'ALIPAY';
|
||||||
static const String PAYMENT_METHOD_CODE_OTT_WECHATPAY = 'WECHATPAY';
|
static const String PAYMENT_METHOD_CODE_OTT_WECHATPAY = 'WECHATPAY';
|
||||||
static const String PAYMENT_METHOD_CODE_PAYPAL = 'paypal';
|
static const String PAYMENT_METHOD_CODE_PAYPAL = 'paypal';
|
||||||
static const String PAYMENT_METHOD_CODE_STRIPE = 'stripe';
|
static const String PAYMENT_METHOD_CODE_STRIPE = 'stripe'; // API still returns 'stripe' code; now routed to e-Transfer
|
||||||
static const String PAYMENT_METHOD_CODE_POD = 'payondeliverypickup';
|
static const String PAYMENT_METHOD_CODE_POD = 'payondeliverypickup';
|
||||||
static const String PAYMENT_METHOD_NATIVE_PAY = 'native_pay';
|
static const String PAYMENT_METHOD_NATIVE_PAY = 'native_pay';
|
||||||
|
|
||||||
static const String STRIPE_STATUS_REQUIRES_CONFIRMATION = 'requires_confirmation';
|
// e-Transfer (replaces Stripe)
|
||||||
static const String STRIPE_CLIENT_SECRET = 'client_secret';
|
static const String ETRANSFER_EMAIL = 'payment@wisetronic.com';
|
||||||
static const String STRIPE_STATUS_SUCCEDED = 'succeeded';
|
static const String ETRANSFER_QA = 'wisetronic'; // security question answer placeholder, if needed
|
||||||
|
// Remark template for auto-processing: R#<receipt id> (= order id)
|
||||||
|
static const String ETRANSFER_REMARK_PREFIX = 'R#';
|
||||||
|
|
||||||
static const int STATUS_PENDING = 0;
|
static const int STATUS_PENDING = 0;
|
||||||
static const int STATUS_ACCEPT = 1;
|
static const int STATUS_ACCEPT = 1;
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
|
||||||
class ImageViewer extends StatefulWidget {
|
class ImageViewer extends StatefulWidget {
|
||||||
|
final Key? key;
|
||||||
final ImageProvider imageProvider;
|
final ImageProvider imageProvider;
|
||||||
|
|
||||||
ImageViewer(this.imageProvider, {Key? key}) :
|
ImageViewer(this.imageProvider, {this.key}) :
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -33,15 +33,18 @@ AlertDialog logoutDialog(BuildContext context) {
|
|||||||
.yes_i_am_sure),
|
.yes_i_am_sure),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Utils.prefs?.remove(Constants.KEY_USER_ID);
|
Utils.getBox().then((box) {
|
||||||
Utils.prefs?.remove(Constants.KEY_ACCESS_TOKEN);
|
box.delete(Constants.KEY_USER_ID);
|
||||||
store.dispatch(
|
box.delete(
|
||||||
new UpdateCurrentUser(null));
|
Constants.KEY_ACCESS_TOKEN);
|
||||||
eventBus.fire(
|
store.dispatch(
|
||||||
new OnCurrentUserUpdated());
|
new UpdateCurrentUser(null));
|
||||||
Routes.router.navigateTo(
|
eventBus.fire(
|
||||||
context, '/', replace: true,
|
new OnCurrentUserUpdated());
|
||||||
clearStack: true);
|
Routes.router.navigateTo(
|
||||||
|
context, '/', replace: true,
|
||||||
|
clearStack: true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Map<String, LibraryLoader> _deferredLibraries = {
|
|||||||
'zh_CN': () => new Future.value(null),
|
'zh_CN': () => new Future.value(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
MessageLookupByLibrary _findExact(String localeName) {
|
MessageLookupByLibrary? _findExact(String localeName) {
|
||||||
switch (localeName) {
|
switch (localeName) {
|
||||||
case 'en':
|
case 'en':
|
||||||
return messages_en.messages;
|
return messages_en.messages;
|
||||||
@@ -59,7 +59,7 @@ bool _messagesExistFor(String locale) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageLookupByLibrary _findGeneratedMessagesFor(String locale) {
|
MessageLookupByLibrary? _findGeneratedMessagesFor(String locale) {
|
||||||
var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
|
var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
|
||||||
onFailure: (_) => null);
|
onFailure: (_) => null);
|
||||||
if (actualLocale == null) return null;
|
if (actualLocale == null) return null;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import 'intl/messages_all.dart';
|
|||||||
class S {
|
class S {
|
||||||
S();
|
S();
|
||||||
|
|
||||||
static S current;
|
static S current = S();
|
||||||
|
|
||||||
static const AppLocalizationDelegate delegate =
|
static const AppLocalizationDelegate delegate =
|
||||||
AppLocalizationDelegate();
|
AppLocalizationDelegate();
|
||||||
@@ -32,7 +32,7 @@ class S {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static S of(BuildContext context) {
|
static S of(BuildContext context) {
|
||||||
return Localizations.of<S>(context, S);
|
return Localizations.of<S>(context, S) ?? S.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `About`
|
/// `About`
|
||||||
|
|||||||
+37
-19
@@ -1,4 +1,9 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:catcher/catcher.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:flutter_wisetronic/pages/buy_service.dart';
|
import 'package:flutter_wisetronic/pages/buy_service.dart';
|
||||||
@@ -9,8 +14,11 @@ import 'pages/create_online_store_1.dart';
|
|||||||
import 'pages/download.dart';
|
import 'pages/download.dart';
|
||||||
import 'pages/me.dart';
|
import 'pages/me.dart';
|
||||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
// import 'package:uni_links/uni_links.dart';
|
||||||
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
|
import 'events/eventbus.dart';
|
||||||
|
import 'events/events.dart';
|
||||||
import 'generated/l10n.dart';
|
import 'generated/l10n.dart';
|
||||||
import 'pages/home.dart';
|
import 'pages/home.dart';
|
||||||
import 'pages/plain_page.dart';
|
import 'pages/plain_page.dart';
|
||||||
@@ -25,14 +33,25 @@ import 'utils/utils.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
FlutterError.onError = (details) {
|
||||||
|
FlutterError.presentError(details);
|
||||||
|
print('CK_ERROR: ${details.exceptionAsString()}');
|
||||||
|
print('CK_CTX: ${details.context}');
|
||||||
|
print('CK_STACK: ${details.stack}');
|
||||||
|
};
|
||||||
|
// Enable configureApp will cause route problem.
|
||||||
|
// configureApp();
|
||||||
setPathUrlStrategy();
|
setPathUrlStrategy();
|
||||||
runApp(MyApp());
|
runApp(MyApp());
|
||||||
|
Future.delayed(Duration(seconds: 3), () => Util.devAutologin()); // DEV e2e: 延迟 3s 等 Flutter/Hive ready
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
MyApp() {
|
MyApp() {
|
||||||
Routes.configure();
|
Routes.configure();
|
||||||
Utils().init();
|
Utils().init();
|
||||||
|
Util().init();
|
||||||
|
// getCurrentPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
static getCurrentPosition() async {
|
static getCurrentPosition() async {
|
||||||
@@ -82,6 +101,7 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
debugShowCheckedModeBanner: Constants.DEBUG,
|
debugShowCheckedModeBanner: Constants.DEBUG,
|
||||||
|
navigatorKey: kIsWeb ? null : Catcher.navigatorKey,
|
||||||
localizationsDelegates: [
|
localizationsDelegates: [
|
||||||
GlobalMaterialLocalizations.delegate,
|
GlobalMaterialLocalizations.delegate,
|
||||||
GlobalWidgetsLocalizations.delegate,
|
GlobalWidgetsLocalizations.delegate,
|
||||||
@@ -90,27 +110,25 @@ class MyApp extends StatelessWidget {
|
|||||||
S.delegate,
|
S.delegate,
|
||||||
],
|
],
|
||||||
supportedLocales: S.delegate.supportedLocales,
|
supportedLocales: S.delegate.supportedLocales,
|
||||||
localeResolutionCallback: (Locale? locale, Iterable<Locale>? supportedLocales) {
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) {
|
||||||
print('Language code: ${locale?.languageCode}, Country code: ${locale?.countryCode}');
|
if (locale == null) {
|
||||||
if (locale != null && supportedLocales != null) {
|
|
||||||
for (final supportedLocale in supportedLocales) {
|
|
||||||
if (supportedLocale.languageCode == locale.languageCode) {
|
|
||||||
store.dispatch(UpdateLocale(locale));
|
|
||||||
return supportedLocale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
store.dispatch(UpdateLocale(supportedLocales.first));
|
store.dispatch(UpdateLocale(supportedLocales.first));
|
||||||
return supportedLocales.first;
|
return supportedLocales.first;
|
||||||
}
|
}
|
||||||
return null;
|
print('Language code: ${locale.languageCode}, Country code: ${locale.countryCode}');
|
||||||
|
for (final supportedLocale in supportedLocales) {
|
||||||
|
if (supportedLocale.languageCode == locale.languageCode) {
|
||||||
|
store.dispatch(UpdateLocale(locale));
|
||||||
|
return supportedLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
store.dispatch(UpdateLocale(supportedLocales.first));
|
||||||
|
return supportedLocales.first;
|
||||||
},
|
},
|
||||||
onGenerateRoute: (RouteSettings settings) {
|
onGenerateRoute: (RouteSettings settings) {
|
||||||
final uri = Uri.parse(settings.name!);
|
final List<String> pathElements = settings.name?.split('/') ?? [];
|
||||||
final path = uri.path;
|
print('path elements: $pathElements');
|
||||||
print('path: $path');
|
if (pathElements.isEmpty || pathElements[0] != '') {
|
||||||
final List<String> pathElements = path.split('/');
|
|
||||||
print('path elements --> $pathElements');
|
|
||||||
if (pathElements[0] != '') {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (pathElements[1] == 'me') {
|
if (pathElements[1] == 'me') {
|
||||||
@@ -154,12 +172,12 @@ class MyApp extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (pathElements[1] == 'renew-minioffice') {
|
if (pathElements[1] == 'renew-minioffice' && pathElements.length >= 3) {
|
||||||
return MaterialPageRoute(builder: (BuildContext context) =>
|
return MaterialPageRoute(builder: (BuildContext context) =>
|
||||||
RenewMiniOffice(int.parse(pathElements[2]))
|
RenewMiniOffice(int.parse(pathElements[2]))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (pathElements[1] == 'buy-service') {
|
if (pathElements[1] == 'buy-service' && pathElements.length >= 4) {
|
||||||
return MaterialPageRoute(builder: (BuildContext context) =>
|
return MaterialPageRoute(builder: (BuildContext context) =>
|
||||||
BuyService(int.parse(pathElements[2]), pathElements[3])
|
BuyService(int.parse(pathElements[2]), pathElements[3])
|
||||||
);
|
);
|
||||||
|
|||||||
+12
-12
@@ -4,9 +4,9 @@ import 'dart:convert';
|
|||||||
import 'package:flutter_wisetronic/models/product_attribute.dart';
|
import 'package:flutter_wisetronic/models/product_attribute.dart';
|
||||||
|
|
||||||
class Subproduct {
|
class Subproduct {
|
||||||
int id;
|
int? id;
|
||||||
SimpleProduct product;
|
SimpleProduct? product;
|
||||||
double quantity;
|
double? quantity;
|
||||||
|
|
||||||
Subproduct.fromJson(Map<String, dynamic> json) :
|
Subproduct.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
@@ -26,15 +26,15 @@ class Subproduct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SimpleProduct {
|
class SimpleProduct {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
String sku;
|
String? sku;
|
||||||
double price;
|
double? price;
|
||||||
String description;
|
String? description;
|
||||||
String image;
|
String? image;
|
||||||
List<ProductAttribute> productAttributes;
|
List<ProductAttribute>? productAttributes;
|
||||||
double customerLastPrice;
|
double? customerLastPrice;
|
||||||
String extraData;
|
String? extraData;
|
||||||
|
|
||||||
SimpleProduct.fromJson(Map<String, dynamic> json) :
|
SimpleProduct.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
|
|||||||
+10
-10
@@ -2,8 +2,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Section {
|
class Section {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
|
|
||||||
Section.fromJson(Map<String, dynamic> json) :
|
Section.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
@@ -21,14 +21,14 @@ class Section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Blog {
|
class Blog {
|
||||||
int id;
|
int? id;
|
||||||
String title;
|
String? title;
|
||||||
String body;
|
String? body;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
String thumbUrl;
|
String? thumbUrl;
|
||||||
String imageUrl;
|
String? imageUrl;
|
||||||
String videoUrl;
|
String? videoUrl;
|
||||||
Section section;
|
Section? section;
|
||||||
|
|
||||||
Blog.fromJson(Map<String, dynamic> json) :
|
Blog.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import 'dart:convert';
|
|||||||
import 'booking_time.dart';
|
import 'booking_time.dart';
|
||||||
|
|
||||||
class BookingDateTime {
|
class BookingDateTime {
|
||||||
String viewDate;
|
String? viewDate;
|
||||||
int unixTime;
|
int? unixTime;
|
||||||
String sendTimeTip;
|
String? sendTimeTip;
|
||||||
List<BookingTime> bookTimes;
|
List<BookingTime>? bookTimes;
|
||||||
|
|
||||||
BookingDateTime(this.viewDate, this.unixTime, this.sendTimeTip, this.bookTimes);
|
BookingDateTime(this.viewDate, this.unixTime, this.sendTimeTip, this.bookTimes);
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class BookingTime {
|
class BookingTime {
|
||||||
String viewTime;
|
String? viewTime;
|
||||||
int unixTime;
|
int? unixTime;
|
||||||
String sendTimeTip;
|
String? sendTimeTip;
|
||||||
|
|
||||||
BookingTime(this.viewTime, this.unixTime, this.sendTimeTip);
|
BookingTime(this.viewTime, this.unixTime, this.sendTimeTip);
|
||||||
|
|
||||||
|
|||||||
+42
-42
@@ -8,7 +8,7 @@ import 'product.dart';
|
|||||||
import 'waiting_line.dart';
|
import 'waiting_line.dart';
|
||||||
|
|
||||||
class QuickInput {
|
class QuickInput {
|
||||||
String value;
|
String? value;
|
||||||
QuickInput.fromJson(Map<String, dynamic> json)
|
QuickInput.fromJson(Map<String, dynamic> json)
|
||||||
: value = json['value'];
|
: value = json['value'];
|
||||||
|
|
||||||
@@ -23,48 +23,48 @@ class QuickInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Business {
|
class Business {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
String phone;
|
String? phone;
|
||||||
Address address;
|
Address? address;
|
||||||
String fullAddress;
|
String? fullAddress;
|
||||||
String picUrl;
|
String? picUrl;
|
||||||
int status;
|
int? status;
|
||||||
List<BusinessTime> openingTime;
|
List<BusinessTime>? openingTime;
|
||||||
double shippingFee;
|
double? shippingFee;
|
||||||
double packageFee;
|
double? packageFee;
|
||||||
double minPrice;
|
double? minPrice;
|
||||||
int shippingTime;
|
int? shippingTime;
|
||||||
int monthSales;
|
int? monthSales;
|
||||||
String bulletin;
|
String? bulletin;
|
||||||
int category;
|
int? category;
|
||||||
bool isLike;
|
bool? isLike;
|
||||||
String description;
|
String? description;
|
||||||
String policy;
|
String? policy;
|
||||||
String bannerImageUrl;
|
String? bannerImageUrl;
|
||||||
int todayOpen;
|
int? todayOpen;
|
||||||
int todayClose;
|
int? todayClose;
|
||||||
bool showMonthlySold;
|
bool? showMonthlySold;
|
||||||
List<ImageUrl> slideImages;
|
List<ImageUrl>? slideImages;
|
||||||
List<Product> promoProducts;
|
List<Product>? promoProducts;
|
||||||
String paypalEmail;
|
String? paypalEmail;
|
||||||
bool deliveryCanadaPost;
|
bool? deliveryCanadaPost;
|
||||||
bool deliveryStoreDelivery;
|
bool? deliveryStoreDelivery;
|
||||||
bool deliveryPickup;
|
bool? deliveryPickup;
|
||||||
String currency;
|
String? currency;
|
||||||
List<WaitingLine> waitingLine;
|
List<WaitingLine>? waitingLine;
|
||||||
bool enableWaitingLine;
|
bool? enableWaitingLine;
|
||||||
double pointsToCreditsConversionRate;
|
double? pointsToCreditsConversionRate;
|
||||||
String chaseXLogin;
|
String? chaseXLogin;
|
||||||
String chaseTransactionKey;
|
String? chaseTransactionKey;
|
||||||
String chaseResponseKey;
|
String? chaseResponseKey;
|
||||||
DistanceInfo? distanceInfo;
|
DistanceInfo? distanceInfo;
|
||||||
int commentsCount;
|
int? commentsCount;
|
||||||
bool forceClose;
|
bool? forceClose;
|
||||||
bool isPublic;
|
bool? isPublic;
|
||||||
double referrerCoupon;
|
double? referrerCoupon;
|
||||||
bool instanceDelivery;
|
bool? instanceDelivery;
|
||||||
List<QuickInput> quickInputs;
|
List<QuickInput>? quickInputs;
|
||||||
|
|
||||||
Business.fromJson(Map<String, dynamic> json)
|
Business.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class BusinessTime {
|
class BusinessTime {
|
||||||
String openTime;
|
String? openTime;
|
||||||
String closeTime;
|
String? closeTime;
|
||||||
|
|
||||||
BusinessTime.fromJson(Map<String, dynamic> json)
|
BusinessTime.fromJson(Map<String, dynamic> json)
|
||||||
: openTime = json['open_time'],
|
: openTime = json['open_time'],
|
||||||
|
|||||||
@@ -74,19 +74,19 @@ class CartInfo {
|
|||||||
originPrice = 0.0;
|
originPrice = 0.0;
|
||||||
discountPrice = 0.0;
|
discountPrice = 0.0;
|
||||||
totalPrice = 0.0;
|
totalPrice = 0.0;
|
||||||
for (var i = 0; i < productList!.length; i++) {
|
for (var i = 0; i < (productList?.length ?? 0); i++) {
|
||||||
newTotal += productList![i].getTotalPrice();
|
newTotal += productList![i].getTotalPrice();
|
||||||
}
|
}
|
||||||
originPrice = newTotal;
|
originPrice = newTotal;
|
||||||
totalPrice = newTotal;
|
totalPrice = newTotal;
|
||||||
return totalPrice!;
|
return totalPrice ?? 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getProductListTotalQuantity() {
|
int getProductListTotalQuantity() {
|
||||||
int qty = 0;
|
int qty = 0;
|
||||||
if (productList != null && productList!.length > 0) {
|
if (productList != null && productList!.length > 0) {
|
||||||
for (var i = 0; i < productList!.length; i++) {
|
for (var i = 0; i < productList!.length; i++) {
|
||||||
qty += productList![i].quantity!.round();
|
qty += (productList![i].quantity ?? 0).round();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return qty;
|
return qty;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class CartLineItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double getTotalPrice() {
|
double getTotalPrice() {
|
||||||
totalPrice = unitPrice! * quantity!;
|
totalPrice = (unitPrice ?? 0.0) * (quantity ?? 0);
|
||||||
return totalPrice!;
|
return totalPrice ?? 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Category {
|
class Category {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
|
|
||||||
Category.fromJson(Map<String, dynamic> json)
|
Category.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import 'dart:convert';
|
|||||||
import 'product.dart';
|
import 'product.dart';
|
||||||
|
|
||||||
class CategoryProducts {
|
class CategoryProducts {
|
||||||
int id;
|
int? id;
|
||||||
int businessId;
|
int? businessId;
|
||||||
String name;
|
String? name;
|
||||||
String description;
|
String? description;
|
||||||
String iconUrl;
|
String? iconUrl;
|
||||||
List<Product> products;
|
List<Product>? products;
|
||||||
|
|
||||||
CategoryProducts.fromJson(Map<String, dynamic> json)
|
CategoryProducts.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import 'dart:convert';
|
|||||||
import 'product_image.dart';
|
import 'product_image.dart';
|
||||||
|
|
||||||
class Comment {
|
class Comment {
|
||||||
int id;
|
int? id;
|
||||||
String contact;
|
String? contact;
|
||||||
String content;
|
String? content;
|
||||||
int rating;
|
int? rating;
|
||||||
List<ProductImage> images;
|
List<ProductImage>? images;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
int thumbUp;
|
int? thumbUp;
|
||||||
int thumbDown;
|
int? thumbDown;
|
||||||
String replyFromStore;
|
String? replyFromStore;
|
||||||
|
|
||||||
Comment.fromJson(Map<String, dynamic> json) :
|
Comment.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import 'dart:convert';
|
|||||||
import 'business.dart';
|
import 'business.dart';
|
||||||
|
|
||||||
class Coupon {
|
class Coupon {
|
||||||
int id;
|
int? id;
|
||||||
String code;
|
String? code;
|
||||||
String description;
|
String? description;
|
||||||
String expirationDate;
|
String? expirationDate;
|
||||||
double minAmount;
|
double? minAmount;
|
||||||
Business? store;
|
Business? store;
|
||||||
double valueAmount;
|
double? valueAmount;
|
||||||
bool isPercentage;
|
bool? isPercentage;
|
||||||
|
|
||||||
Coupon.fromJson(Map<String, dynamic> json)
|
Coupon.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class ErrorMessage {
|
class ErrorMessage {
|
||||||
String code;
|
String? code;
|
||||||
String string;
|
String? string;
|
||||||
|
|
||||||
ErrorMessage.fromJson(Map<String, dynamic> json)
|
ErrorMessage.fromJson(Map<String, dynamic> json)
|
||||||
: code = json['code'],
|
: code = json['code'],
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class ExtraFee {
|
class ExtraFee {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
String description;
|
String? description;
|
||||||
double rate;
|
double? rate;
|
||||||
double price;
|
double? price;
|
||||||
|
|
||||||
ExtraFee.fromJson(Map<String, dynamic> json)
|
ExtraFee.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Fulfillment {
|
class Fulfillment {
|
||||||
int id;
|
int? id;
|
||||||
String shippingMethod;
|
String? shippingMethod;
|
||||||
String trackingNumber;
|
String? trackingNumber;
|
||||||
String note;
|
String? note;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
|
|
||||||
Fulfillment.fromJson(Map<String, dynamic> json) :
|
Fulfillment.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Gallery {
|
class Gallery {
|
||||||
int id;
|
int? id;
|
||||||
String image;
|
String? image;
|
||||||
String linkUrl;
|
String? linkUrl;
|
||||||
|
|
||||||
Gallery.fromJson(Map<String, dynamic> json)
|
Gallery.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class Group {
|
class Group {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
|
|
||||||
Group.fromJson(Map<String, dynamic> json) :
|
Group.fromJson(Map<String, dynamic> json) :
|
||||||
id = json['id'],
|
id = json['id'],
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class ImageUrl {
|
class ImageUrl {
|
||||||
int id;
|
int? id;
|
||||||
String imageUrl;
|
String? imageUrl;
|
||||||
|
|
||||||
ImageUrl.fromJson(Map<String, dynamic> json)
|
ImageUrl.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
class KeyValue {
|
class KeyValue {
|
||||||
String name;
|
String? name;
|
||||||
dynamic value;
|
dynamic? value;
|
||||||
|
|
||||||
KeyValue(this.name, this.value);
|
KeyValue(this.name, this.value);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class LocatedAddress {
|
class LocatedAddress {
|
||||||
int storeId;
|
int? storeId;
|
||||||
double latitude;
|
double? latitude;
|
||||||
double longitude;
|
double? longitude;
|
||||||
String streetNumber;
|
String? streetNumber;
|
||||||
String streetName;
|
String? streetName;
|
||||||
String city;
|
String? city;
|
||||||
String locality;
|
String? locality;
|
||||||
String province;
|
String? province;
|
||||||
String country;
|
String? country;
|
||||||
String postalCode;
|
String? postalCode;
|
||||||
String formattedAddress;
|
String? formattedAddress;
|
||||||
|
|
||||||
LocatedAddress.fromJson(Map<String, dynamic> json)
|
LocatedAddress.fromJson(Map<String, dynamic> json)
|
||||||
: storeId = json['store_id'],
|
: storeId = json['store_id'],
|
||||||
|
|||||||
+23
-25
@@ -11,32 +11,32 @@ import 'fulfillment.dart';
|
|||||||
import 'user_position.dart';
|
import 'user_position.dart';
|
||||||
|
|
||||||
class Order {
|
class Order {
|
||||||
int id;
|
int? id;
|
||||||
int userId;
|
int? userId;
|
||||||
int businessId;
|
int? businessId;
|
||||||
Business? businessInfo;
|
Business? businessInfo;
|
||||||
CartInfo? cartInfo;
|
CartInfo? cartInfo;
|
||||||
int status;
|
int? status;
|
||||||
double originPrice;
|
double? originPrice;
|
||||||
double discountPrice;
|
double? discountPrice;
|
||||||
double totalPrice;
|
double? totalPrice;
|
||||||
String consignee;
|
String? consignee;
|
||||||
String phone;
|
String? phone;
|
||||||
String address;
|
String? address;
|
||||||
Address? shippingAddress;
|
Address? shippingAddress;
|
||||||
int payMethod;
|
int? payMethod;
|
||||||
String remark;
|
String? remark;
|
||||||
String orderNum;
|
String? orderNum;
|
||||||
int bookedAt;
|
int? bookedAt;
|
||||||
int createdAt;
|
int? createdAt;
|
||||||
String shippingMethod;
|
String? shippingMethod;
|
||||||
String paymentStatus; // UNPAID, PAID, PARTIALPAID
|
String paymentStatus; // UNPAID, PAID, PARTIALPAID
|
||||||
double amountPaid;
|
double? amountPaid;
|
||||||
List<Fulfillment> fulfillments;
|
List<Fulfillment>? fulfillments;
|
||||||
String? extraData;
|
String? extraData;
|
||||||
bool hasComment;
|
bool? hasComment;
|
||||||
double fee;
|
double? fee;
|
||||||
UserPosition shipperPosition;
|
UserPosition? shipperPosition;
|
||||||
DistanceInfo? deliveryDistance;
|
DistanceInfo? deliveryDistance;
|
||||||
|
|
||||||
Order.fromJson(Map<String, dynamic> json)
|
Order.fromJson(Map<String, dynamic> json)
|
||||||
@@ -100,10 +100,8 @@ class Order {
|
|||||||
|
|
||||||
double getSubtotal() {
|
double getSubtotal() {
|
||||||
double subtotal = 0.0;
|
double subtotal = 0.0;
|
||||||
if (cartInfo != null) {
|
for (CartLineItem lineItem in cartInfo?.productList ?? <CartLineItem>[]) {
|
||||||
for (CartLineItem lineItem in cartInfo!.productList!) {
|
subtotal += lineItem.getTotalPrice();
|
||||||
subtotal += lineItem.getTotalPrice();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return subtotal;
|
return subtotal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,12 +57,16 @@ class PaymentPlatform {
|
|||||||
switch(code) {
|
switch(code) {
|
||||||
case 'chase':
|
case 'chase':
|
||||||
return S.of(context).credit_debit_card;
|
return S.of(context).credit_debit_card;
|
||||||
|
break;
|
||||||
case 'web-credit-card':
|
case 'web-credit-card':
|
||||||
return S.of(context).credit_card;
|
return S.of(context).credit_card;
|
||||||
|
break;
|
||||||
case 'ALIPAY':
|
case 'ALIPAY':
|
||||||
return S.of(context).alipay;
|
return S.of(context).alipay;
|
||||||
|
break;
|
||||||
case 'WECHATPAY':
|
case 'WECHATPAY':
|
||||||
return S.of(context).wechatpay;
|
return S.of(context).wechatpay;
|
||||||
|
break;
|
||||||
case 'paypal':
|
case 'paypal':
|
||||||
return S.of(context).paypal;
|
return S.of(context).paypal;
|
||||||
case 'payondeliverypickup':
|
case 'payondeliverypickup':
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
class Position {
|
class Position {
|
||||||
final double latitude;
|
final double? latitude;
|
||||||
final double longitude;
|
final double? longitude;
|
||||||
|
|
||||||
Position({required this.latitude, required this.longitude});
|
Position({this.latitude, this.longitude});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(other) {
|
bool operator ==(other) {
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import 'dart:convert';
|
|||||||
import 'product_option.dart';
|
import 'product_option.dart';
|
||||||
|
|
||||||
class ProductAttribute {
|
class ProductAttribute {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
List<ProductOption> productOptions;
|
List<ProductOption>? productOptions;
|
||||||
bool singleSelection;
|
bool? singleSelection;
|
||||||
bool byQuantity;
|
bool? byQuantity;
|
||||||
bool required;
|
bool? required;
|
||||||
String? extra;
|
String? extra;
|
||||||
bool disabled;
|
bool? disabled;
|
||||||
|
|
||||||
ProductAttribute.fromJson(Map<String, dynamic> json)
|
ProductAttribute.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -8,30 +8,30 @@ import 'product_attribute.dart';
|
|||||||
import 'product_image.dart';
|
import 'product_image.dart';
|
||||||
|
|
||||||
class ProductDetail {
|
class ProductDetail {
|
||||||
int id;
|
int? id;
|
||||||
String image;
|
String? image;
|
||||||
List<ProductImage> images;
|
List<ProductImage>? images;
|
||||||
String sku;
|
String? sku;
|
||||||
String name;
|
String? name;
|
||||||
double price;
|
double? price;
|
||||||
double regularPrice;
|
double? regularPrice;
|
||||||
String description;
|
String? description;
|
||||||
String description2;
|
String? description2;
|
||||||
String detailDescription;
|
String? detailDescription;
|
||||||
double monthSales;
|
double? monthSales;
|
||||||
int rate;
|
int? rate;
|
||||||
double leftNum;
|
double? leftNum;
|
||||||
List<ProductAttribute> productAttributes;
|
List<ProductAttribute>? productAttributes;
|
||||||
bool nonInventory;
|
bool? nonInventory;
|
||||||
String extraData;
|
String? extraData;
|
||||||
String purchaseNote;
|
String? purchaseNote;
|
||||||
double weight;
|
double? weight;
|
||||||
double dimentionsLength;
|
double? dimentionsLength;
|
||||||
double dimentionsWidth;
|
double? dimentionsWidth;
|
||||||
double dimentionsHeight;
|
double? dimentionsHeight;
|
||||||
bool reviewsAllowed;
|
bool? reviewsAllowed;
|
||||||
List<Category> categories;
|
List<Category>? categories;
|
||||||
List<Subproduct> subproducts;
|
List<Subproduct>? subproducts;
|
||||||
|
|
||||||
ProductDetail.fromJson(Map<String, dynamic> json)
|
ProductDetail.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class ProductImage {
|
class ProductImage {
|
||||||
int id;
|
int? id;
|
||||||
String image;
|
String? image;
|
||||||
|
|
||||||
ProductImage.fromJson(Map<String, dynamic> json)
|
ProductImage.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class ProductOption {
|
class ProductOption {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
double adjustAmount;
|
double? adjustAmount;
|
||||||
String extra;
|
String? extra;
|
||||||
bool disabled;
|
bool? disabled;
|
||||||
|
|
||||||
ProductOption.fromJson(Map<String, dynamic> json)
|
ProductOption.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
class ShippingRate {
|
class ShippingRate {
|
||||||
String name;
|
String? name;
|
||||||
double price;
|
double? price;
|
||||||
List<Rate> rates;
|
List<Rate>? rates;
|
||||||
|
|
||||||
ShippingRate.fromJson(Map<String, dynamic> json)
|
ShippingRate.fromJson(Map<String, dynamic> json)
|
||||||
: name = json['name'],
|
: name = json['name'],
|
||||||
@@ -25,7 +25,7 @@ class ShippingRate {
|
|||||||
other is ShippingRate &&
|
other is ShippingRate &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
name == other.name &&
|
name == other.name &&
|
||||||
price.toStringAsFixed(2) == other.price.toStringAsFixed(2) &&
|
price?.toStringAsFixed(2) == other.price?.toStringAsFixed(2) &&
|
||||||
listEquals(rates, other.rates);
|
listEquals(rates, other.rates);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -41,8 +41,8 @@ class ShippingRate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Rate {
|
class Rate {
|
||||||
String name;
|
String? name;
|
||||||
double rate;
|
double? rate;
|
||||||
|
|
||||||
Rate.fromJson(Map<String, dynamic> json)
|
Rate.fromJson(Map<String, dynamic> json)
|
||||||
: name = json['name'],
|
: name = json['name'],
|
||||||
@@ -59,7 +59,7 @@ class Rate {
|
|||||||
other is Rate &&
|
other is Rate &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
name == other.name &&
|
name == other.name &&
|
||||||
rate.toStringAsFixed(2) == other.rate.toStringAsFixed(2);
|
rate?.toStringAsFixed(2) == other.rate?.toStringAsFixed(2);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import 'dart:convert';
|
|||||||
import 'address.dart';
|
import 'address.dart';
|
||||||
|
|
||||||
class Store {
|
class Store {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
Address address;
|
Address? address;
|
||||||
|
|
||||||
Store.fromJson(Map<String, dynamic> json)
|
Store.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class SimpleProduct {
|
class SimpleProduct {
|
||||||
int id;
|
int? id;
|
||||||
String name;
|
String? name;
|
||||||
double price;
|
double? price;
|
||||||
double regularPrice;
|
double? regularPrice;
|
||||||
String description;
|
String? description;
|
||||||
String imagePath;
|
String? imagePath;
|
||||||
|
|
||||||
SimpleProduct.fromJson(Map<String, dynamic> json)
|
SimpleProduct.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
class StripePaymentMethod {
|
|
||||||
int id;
|
|
||||||
String customerId;
|
|
||||||
String paymentMethodId;
|
|
||||||
String paymentMethodType;
|
|
||||||
String cardBrand;
|
|
||||||
String cardCountry;
|
|
||||||
int cardExpMonth;
|
|
||||||
int cardExpYear;
|
|
||||||
String cardFunding;
|
|
||||||
String cardLast4;
|
|
||||||
|
|
||||||
StripePaymentMethod.fromJson(Map<String, dynamic> json) :
|
|
||||||
id = json['id'],
|
|
||||||
customerId = json['customer_id'],
|
|
||||||
paymentMethodId = json['payment_method_id'],
|
|
||||||
paymentMethodType = json['payment_method_type'],
|
|
||||||
cardBrand = json['card_brand'],
|
|
||||||
cardCountry = json['card_country'],
|
|
||||||
cardExpMonth = json['card_exp_month'],
|
|
||||||
cardExpYear = json['card_exp_year'],
|
|
||||||
cardFunding = json['card_funding'],
|
|
||||||
cardLast4 = json['card_last4'];
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'id': id,
|
|
||||||
'customer_id': customerId,
|
|
||||||
'payment_method_id': paymentMethodId,
|
|
||||||
'payment_method_type': paymentMethodType,
|
|
||||||
'card_brand': cardBrand,
|
|
||||||
'card_country': cardCountry,
|
|
||||||
'card_exp_month': cardExpMonth,
|
|
||||||
'card_exp_year': cardExpYear,
|
|
||||||
'card_funding': cardFunding,
|
|
||||||
'card_last4': cardLast4,
|
|
||||||
};
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return json.encode(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class TextValue {
|
class TextValue {
|
||||||
String text;
|
String? text;
|
||||||
int value;
|
int? value;
|
||||||
|
|
||||||
TextValue.fromJson(Map<String, dynamic> json)
|
TextValue.fromJson(Map<String, dynamic> json)
|
||||||
: text = json['text'],
|
: text = json['text'],
|
||||||
|
|||||||
+18
-18
@@ -4,10 +4,10 @@ import 'dart:convert';
|
|||||||
import 'simple_business.dart';
|
import 'simple_business.dart';
|
||||||
|
|
||||||
class TicketFile {
|
class TicketFile {
|
||||||
int id;
|
int? id;
|
||||||
String url;
|
String? url;
|
||||||
String fileName;
|
String? fileName;
|
||||||
String fileType;
|
String? fileType;
|
||||||
|
|
||||||
TicketFile.fromJson(Map<String, dynamic> json)
|
TicketFile.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
@@ -29,9 +29,9 @@ class TicketFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Issue {
|
class Issue {
|
||||||
int id;
|
int? id;
|
||||||
String msg;
|
String? msg;
|
||||||
List<TicketFile> files;
|
List<TicketFile>? files;
|
||||||
|
|
||||||
Issue.fromJson(Map<String, dynamic> json)
|
Issue.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
@@ -51,11 +51,11 @@ class Issue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FollowUp {
|
class FollowUp {
|
||||||
int id;
|
int? id;
|
||||||
String msg;
|
String? msg;
|
||||||
String poster;
|
String? poster;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
List<TicketFile> files;
|
List<TicketFile>? files;
|
||||||
|
|
||||||
FollowUp.fromJson(Map<String, dynamic> json)
|
FollowUp.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
@@ -79,12 +79,12 @@ class FollowUp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Ticket {
|
class Ticket {
|
||||||
int id;
|
int? id;
|
||||||
Issue issue;
|
Issue? issue;
|
||||||
Store store;
|
Store? store;
|
||||||
List<FollowUp> followUps;
|
List<FollowUp>? followUps;
|
||||||
bool isClosed;
|
bool? isClosed;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
|
|
||||||
Ticket.fromJson(Map<String, dynamic> json)
|
Ticket.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
|
|||||||
+17
-22
@@ -1,26 +1,23 @@
|
|||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'stripe_payment_method.dart';
|
|
||||||
|
|
||||||
class User {
|
class User {
|
||||||
int id;
|
int? id;
|
||||||
String username;
|
String? username;
|
||||||
String nickname;
|
String? nickname;
|
||||||
String mobile;
|
String? mobile;
|
||||||
String email;
|
String? email;
|
||||||
String avatarUrl;
|
String? avatarUrl;
|
||||||
int lastAddressId;
|
int? lastAddressId;
|
||||||
String passCode;
|
String? passCode;
|
||||||
double credit;
|
double? credit;
|
||||||
double wallet;
|
double? wallet;
|
||||||
int coupon;
|
int? coupon;
|
||||||
int points;
|
int? points;
|
||||||
int orderNum;
|
int? orderNum;
|
||||||
double pointsToCreditsConversionRate;
|
double? pointsToCreditsConversionRate;
|
||||||
String contactNumber;
|
String? contactNumber;
|
||||||
String flutterMiniStoreToken;
|
String? flutterMiniStoreToken;
|
||||||
List<StripePaymentMethod> stripePaymentMethods;
|
|
||||||
|
|
||||||
User.fromJson(Map<String, dynamic> json)
|
User.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
@@ -38,8 +35,7 @@ class User {
|
|||||||
orderNum = json['order_num'],
|
orderNum = json['order_num'],
|
||||||
pointsToCreditsConversionRate = double.parse(json['points_to_credits_conversion_rate'].toString()),
|
pointsToCreditsConversionRate = double.parse(json['points_to_credits_conversion_rate'].toString()),
|
||||||
contactNumber = json['contact_number'],
|
contactNumber = json['contact_number'],
|
||||||
flutterMiniStoreToken = json['flutter_ministore_token'],
|
flutterMiniStoreToken = json['flutter_ministore_token'];
|
||||||
stripePaymentMethods = (json['stripe_payment_methods'] as List).map((e) => StripePaymentMethod.fromJson(e)).toList();
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
@@ -58,7 +54,6 @@ class User {
|
|||||||
'points_to_credits_conversion_rate': pointsToCreditsConversionRate,
|
'points_to_credits_conversion_rate': pointsToCreditsConversionRate,
|
||||||
'contact_number': contactNumber,
|
'contact_number': contactNumber,
|
||||||
'flutter_ministore_token': flutterMiniStoreToken,
|
'flutter_ministore_token': flutterMiniStoreToken,
|
||||||
'stripe_payment_methods': stripePaymentMethods,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class UserPosition {
|
class UserPosition {
|
||||||
double lat;
|
double? lat;
|
||||||
double lng;
|
double? lng;
|
||||||
|
|
||||||
UserPosition.fromJson(Map<String, dynamic> json) :
|
UserPosition.fromJson(Map<String, dynamic> json) :
|
||||||
lat = double.parse(json['lat'].toString()),
|
lat = double.parse(json['lat'].toString()),
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
class WaitingLineItem {
|
class WaitingLineItem {
|
||||||
String deviceId;
|
String? deviceId;
|
||||||
String phone;
|
String? phone;
|
||||||
String createdAt;
|
String? createdAt;
|
||||||
int peopleCount;
|
int? peopleCount;
|
||||||
int waitingNumber;
|
int? waitingNumber;
|
||||||
|
|
||||||
WaitingLineItem.fromJson(Map<String, dynamic> json)
|
WaitingLineItem.fromJson(Map<String, dynamic> json)
|
||||||
: deviceId = json['device_id'],
|
: deviceId = json['device_id'],
|
||||||
|
|||||||
@@ -6,18 +6,21 @@ import '../models/business.dart';
|
|||||||
import '../models/product.dart';
|
import '../models/product.dart';
|
||||||
|
|
||||||
class AttributeSelection extends StatelessWidget {
|
class AttributeSelection extends StatelessWidget {
|
||||||
final Product product;
|
final Product? product;
|
||||||
final Business business;
|
final Business? business;
|
||||||
final GlobalKey? startKey;
|
final GlobalKey? startKey;
|
||||||
|
|
||||||
const AttributeSelection({Key? key, required this.product, required this.business, this.startKey}) : super(key: key);
|
const AttributeSelection({Key? key, this.product, this.business, this.startKey}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ScreenTypeLayout.builder(
|
return ResponsiveBuilder(
|
||||||
mobile: (context) => MobileAttributeSelection(product: product, business: business, startKey: startKey),
|
builder: (context, sizingInformation) =>
|
||||||
tablet: (context) => MobileAttributeSelection(product: product, business: business, startKey: startKey),
|
ScreenTypeLayout(
|
||||||
desktop: (context) => MobileAttributeSelection(product: product, business: business, startKey: startKey),
|
mobile: MobileAttributeSelection(product: product!, business: business!, startKey: startKey,),
|
||||||
|
tablet: MobileAttributeSelection(product: product!, business: business!, startKey: startKey,),
|
||||||
|
desktop: MobileAttributeSelection(product: product!, business: business!, startKey: startKey,),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-8
@@ -8,20 +8,24 @@ import '../widgets/desktop/desktop_blog.dart';
|
|||||||
import '../widgets/mobile/mobile_blog.dart';
|
import '../widgets/mobile/mobile_blog.dart';
|
||||||
|
|
||||||
class Blog extends StatelessWidget {
|
class Blog extends StatelessWidget {
|
||||||
|
final Key? key;
|
||||||
final int businessId;
|
final int businessId;
|
||||||
|
|
||||||
const Blog({Key? key, required int businessId}) :
|
const Blog({this.key, int? businessId}) :
|
||||||
businessId = businessId ?? Constants.BUSINESS_ID;
|
businessId = businessId ?? Constants.BUSINESS_ID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ScreenTypeLayout.builder(
|
return ResponsiveBuilder(
|
||||||
mobile: (context) => MobileBlog(businessId: businessId),
|
builder: (context, sizingInformation) =>
|
||||||
tablet: (context) => DesktopBlog(businessId: businessId),
|
ScreenTypeLayout(
|
||||||
desktop: (context) => Scrollbar(
|
mobile: MobileBlog(businessId: businessId,),
|
||||||
thumbVisibility: true,
|
tablet: DesktopBlog(businessId: businessId,),
|
||||||
child: DesktopBlog(businessId: businessId),
|
desktop: Scrollbar(
|
||||||
),
|
thumbVisibility: true,
|
||||||
|
child: DesktopBlog(businessId: businessId,),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class BuyService extends StatefulWidget {
|
|||||||
final int gid;
|
final int gid;
|
||||||
final String serviceName;
|
final String serviceName;
|
||||||
final String? domain;
|
final String? domain;
|
||||||
final int? sid;
|
final int sid;
|
||||||
|
|
||||||
const BuyService(this.gid, this.serviceName, {Key? key, this.domain, this.sid = 0}) :
|
const BuyService(this.gid, this.serviceName, {Key? key, this.domain, this.sid = 0}) :
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@@ -48,10 +48,13 @@ class BuyServiceState extends State<BuyService> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScreenTypeLayout.builder(
|
return ResponsiveBuilder(
|
||||||
mobile: (context) => MobileBuyService(data),
|
builder: (context, sizingInformation) =>
|
||||||
tablet: (context) => DesktopBuyService(data),
|
ScreenTypeLayout(
|
||||||
desktop: (context) => DesktopBuyService(data),
|
mobile: MobileBuyService(data!),
|
||||||
|
tablet: DesktopBuyService(data!),
|
||||||
|
desktop: DesktopBuyService(data!),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,12 +72,16 @@ class BuyServiceState extends State<BuyService> {
|
|||||||
'store_id': '${widget.sid}',
|
'store_id': '${widget.sid}',
|
||||||
}
|
}
|
||||||
).then((value) {
|
).then((value) {
|
||||||
data = value;
|
if (!mounted) return;
|
||||||
data?['domain'] = widget.domain;
|
if (value == null || value is! Map || value['service_selections'] == null) {
|
||||||
print('data: $data');
|
Utils.showMessageDialog(context, 'Service info unavailable');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data = Map<String, dynamic>.from(value);
|
||||||
|
data!['domain'] = widget.domain;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}).onError((error, stackTrace) {
|
}).onError((error, stackTrace) {
|
||||||
Utils.showMessageDialog(context, error);
|
if (mounted) Utils.showMessageDialog(context, error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,15 +31,15 @@ class ChangeMobileOrEmail extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileChangeMobileOrEmail(isMobile),
|
mobile: MobileChangeMobileOrEmail(isMobile),
|
||||||
tablet: (context) => DesktopChangeMobileOrEmail(isMobile),
|
tablet: DesktopChangeMobileOrEmail(isMobile),
|
||||||
desktop: (context) => DesktopChangeMobileOrEmail(isMobile),
|
desktop: DesktopChangeMobileOrEmail(isMobile),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ class ChangePassword extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileChangePassword(),
|
mobile: MobileChangePassword(),
|
||||||
tablet: (context) => DesktopChangePassword(),
|
tablet: DesktopChangePassword(),
|
||||||
desktop: (context) => DesktopChangePassword(),
|
desktop: DesktopChangePassword(),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ class Checkout extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileCheckout(businessId),
|
mobile: MobileCheckout(businessId),
|
||||||
tablet: (context) => DesktopCheckout(businessId),
|
tablet: DesktopCheckout(businessId),
|
||||||
desktop: (context) => DesktopCheckout(businessId),
|
desktop: DesktopCheckout(businessId),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ import '../widgets/desktop/desktop_contact_us.dart';
|
|||||||
import '../widgets/mobile/mobile_contact_us.dart';
|
import '../widgets/mobile/mobile_contact_us.dart';
|
||||||
|
|
||||||
class ContactUs extends StatefulWidget {
|
class ContactUs extends StatefulWidget {
|
||||||
final int businessId;
|
final int? businessId;
|
||||||
|
|
||||||
const ContactUs({required this.businessId, Key? key}) :
|
const ContactUs({this.businessId, Key? key}) :
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -42,10 +42,10 @@ class ContactUsState extends State<ContactUs> {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileContactUs(business!),
|
mobile: MobileContactUs(business!),
|
||||||
tablet: (context) => DesktopContactUs(business!),
|
tablet: DesktopContactUs(business!),
|
||||||
desktop: (context) => DesktopContactUs(business!),
|
desktop: DesktopContactUs(business!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ class ContactUsState extends State<ContactUs> {
|
|||||||
void loadData() {
|
void loadData() {
|
||||||
HttpUtil.httpGet(
|
HttpUtil.httpGet(
|
||||||
'v1/get-business',
|
'v1/get-business',
|
||||||
businessId: widget.businessId,
|
businessId: widget.businessId!,
|
||||||
).then((value) {
|
).then((value) {
|
||||||
business = Business.fromJson(value);
|
business = Business.fromJson(value);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ class Coupons extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileCoupons(contactId,),
|
mobile: MobileCoupons(contactId,),
|
||||||
tablet: (context) => DesktopCoupons(contactId,),
|
tablet: DesktopCoupons(contactId,),
|
||||||
desktop: (context) => DesktopCoupons(contactId,),
|
desktop: DesktopCoupons(contactId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ class CreateOnlineStore1State extends State<CreateOnlineStore1> {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => mobile.CreateOnlineStore1(Constants.BUSINESS_ID),
|
mobile: mobile.CreateOnlineStore1(Constants.BUSINESS_ID),
|
||||||
tablet: (context) => desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
|
tablet: desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
|
||||||
desktop: (context) => desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
|
desktop: desktop.CreateOnlineStore1(Constants.BUSINESS_ID),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,18 +57,18 @@ class DownloadState extends State<Download> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
|
drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileDownloadApps(data!),
|
mobile: MobileDownloadApps(data!),
|
||||||
tablet: (context) => DesktopDownloadApps(data!),
|
tablet: DesktopDownloadApps(data!),
|
||||||
desktop: (context) => Scrollbar(
|
desktop: Scrollbar(
|
||||||
thumbVisibility: true,
|
thumbVisibility: true,
|
||||||
child: DesktopDownloadApps(data!),
|
child: DesktopDownloadApps(data!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(),
|
mobile: MobileBottomNav(),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -79,7 +79,7 @@ class DownloadState extends State<Download> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
eventBus.on<OpenDrawer>().listen((event) {
|
eventBus.on<OpenDrawer>().listen((event) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
_scaffoldKey.currentState?.openDrawer();
|
_scaffoldKey.currentState!.openDrawer();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
_loadData();
|
_loadData();
|
||||||
|
|||||||
@@ -13,19 +13,20 @@ import '../widgets/general/navigationbar.dart';
|
|||||||
import '../widgets/mobile/MobileBottomNav.dart';
|
import '../widgets/mobile/MobileBottomNav.dart';
|
||||||
|
|
||||||
class EditAddress extends StatelessWidget {
|
class EditAddress extends StatelessWidget {
|
||||||
final Address? address;
|
final Key? key;
|
||||||
final int? businessId;
|
final Address address;
|
||||||
const EditAddress(this.address, {Key? key, int? businessId}) :
|
final int businessId;
|
||||||
|
const EditAddress(this.address, {this.key, int? businessId}) :
|
||||||
businessId = businessId ?? Constants.BUSINESS_ID;
|
businessId = businessId ?? Constants.BUSINESS_ID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileEditAddress(address, businessId: businessId,),
|
mobile: MobileEditAddress(address, businessId: businessId,),
|
||||||
tablet: (context) => DesktopEditAddress(address, businessId: businessId,),
|
tablet: DesktopEditAddress(address, businessId: businessId,),
|
||||||
desktop: (context) => DesktopEditAddress(address, businessId: businessId,),
|
desktop: DesktopEditAddress(address, businessId: businessId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ class ForgotPassword extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileForgotPassword(),
|
mobile: MobileForgotPassword(),
|
||||||
tablet: (context) => DesktopForgotPassword(),
|
tablet: DesktopForgotPassword(),
|
||||||
desktop: (context) => DesktopForgotPassword(),
|
desktop: DesktopForgotPassword(),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+20
-21
@@ -74,51 +74,52 @@ class HomeState extends State<Home> {
|
|||||||
appBar: MiniNavigationBar(),
|
appBar: MiniNavigationBar(),
|
||||||
drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
|
drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
|
||||||
body: DoubleBackToCloseAppWrapper(
|
body: DoubleBackToCloseAppWrapper(
|
||||||
child: ScreenTypeLayout.builder(
|
child: ScreenTypeLayout(
|
||||||
mobile: (context) => SingleChildScrollView(
|
mobile: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
MobileIndexCarousel(galleries),
|
MobileIndexCarousel(galleries),
|
||||||
MobileIndexMainContent1(content1Message),
|
MobileIndexMainContent1(content1Message ?? ''),
|
||||||
MobileIndexMainContent2(content2),
|
MobileIndexMainContent2(content2 ?? <String, dynamic>{}),
|
||||||
MobileIndexMainContent3(content2),
|
MobileIndexMainContent3(content2 ?? <String, dynamic>{}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
tablet: (context) => SingleChildScrollView(
|
tablet: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
DesktopIndexCarousel(galleries),
|
DesktopIndexCarousel(galleries),
|
||||||
DesktopIndexMainContent1(content1Message),
|
DesktopIndexMainContent1(content1Message ?? ''),
|
||||||
DesktopIndexMainContent2(content2),
|
DesktopIndexMainContent2(content2 ?? <String, dynamic>{}),
|
||||||
CustomersLogo(),
|
CustomersLogo(),
|
||||||
DesktopIndexMainContent3(content2),
|
DesktopIndexMainContent3(content2 ?? <String, dynamic>{}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
desktop: (context) => Scrollbar(
|
desktop: Scrollbar(
|
||||||
thumbVisibility: true,
|
thumbVisibility: true,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
primary: true,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
DesktopIndexCarousel(galleries),
|
DesktopIndexCarousel(galleries),
|
||||||
DesktopIndexMainContent1(content1Message),
|
DesktopIndexMainContent1(content1Message ?? ''),
|
||||||
DesktopIndexMainContent2(content2),
|
DesktopIndexMainContent2(content2 ?? <String, dynamic>{}),
|
||||||
CustomersLogo(),
|
CustomersLogo(),
|
||||||
DesktopIndexMainContent3(content2),
|
DesktopIndexMainContent3(content2 ?? <String, dynamic>{}),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -163,9 +164,7 @@ class HomeState extends State<Home> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
_latestUri = Uri.base;
|
_latestUri = Uri.base;
|
||||||
print('uri base $_latestUri');
|
print('uri base $_latestUri');
|
||||||
if (_latestUri != null) {
|
eventBus.fire(OnGotDeepLinkUri(_latestUri!));
|
||||||
eventBus.fire(OnGotDeepLinkUri(_latestUri!));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// _sub = getUriLinksStream().listen((Uri uri) {
|
// _sub = getUriLinksStream().listen((Uri uri) {
|
||||||
// print('_sub should get uri $uri');
|
// print('_sub should get uri $uri');
|
||||||
@@ -191,7 +190,7 @@ class HomeState extends State<Home> {
|
|||||||
//
|
//
|
||||||
// if (!mounted) return;
|
// if (!mounted) return;
|
||||||
// _latestUri = initialUri;
|
// _latestUri = initialUri;
|
||||||
// eventBus.fire(OnGotDeepLinkUri(_latestUri));
|
// eventBus.fire(OnGotDeepLinkUri(_latestUri!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,15 +55,15 @@ class IGoShowLearnMoreState extends State<IGoShowLearnMore> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileiGoShowLearnMore(data!),
|
mobile: MobileiGoShowLearnMore(data!),
|
||||||
tablet: (context) => DesktopiGoShowLearnMore(data!),
|
tablet: DesktopiGoShowLearnMore(data!),
|
||||||
desktop: (context) => DesktopiGoShowLearnMore(data!),
|
desktop: DesktopiGoShowLearnMore(data!),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+11
-9
@@ -14,7 +14,9 @@ import '../widgets/mobile/MobileBottomNav.dart';
|
|||||||
import '../widgets/mobile/mobile_login.dart';
|
import '../widgets/mobile/mobile_login.dart';
|
||||||
|
|
||||||
class Login extends StatefulWidget {
|
class Login extends StatefulWidget {
|
||||||
const Login({Key? key}) : super(key: key);
|
final Key? key;
|
||||||
|
|
||||||
|
const Login({this.key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() {
|
State<StatefulWidget> createState() {
|
||||||
@@ -48,15 +50,15 @@ class LoginState extends State<Login> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileLogin(),
|
mobile: MobileLogin(),
|
||||||
tablet: (context) => DesktopLogin(),
|
tablet: DesktopLogin(),
|
||||||
desktop: (context) => DesktopLogin(),
|
desktop: DesktopLogin(),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+11
-9
@@ -15,7 +15,9 @@ import '../widgets/mobile/MobileBottomNav.dart';
|
|||||||
import '../widgets/mobile/mobile_me.dart';
|
import '../widgets/mobile/mobile_me.dart';
|
||||||
|
|
||||||
class Me extends StatefulWidget {
|
class Me extends StatefulWidget {
|
||||||
const Me({Key? key}) : super(key: key);
|
final Key? key;
|
||||||
|
|
||||||
|
const Me({this.key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() {
|
State<StatefulWidget> createState() {
|
||||||
@@ -50,16 +52,16 @@ class MeState extends State<Me> {
|
|||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: DoubleBackToCloseAppWrapper(
|
body: DoubleBackToCloseAppWrapper(
|
||||||
child: ScreenTypeLayout.builder(
|
child: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileMe(),
|
mobile: MobileMe(),
|
||||||
tablet: (context) => DesktopMe(),
|
tablet: DesktopMe(),
|
||||||
desktop: (context) => DesktopMe(),
|
desktop: DesktopMe(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 3,),
|
mobile: MobileBottomNav(currentIndex: 3,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,36 +42,35 @@ class MiniPosLearnMoreState extends State<MiniPosLearnMore> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResponsiveBuilder(
|
return WillPopScope(
|
||||||
builder: (context, sizingInformation) => PopScope(
|
child: ResponsiveBuilder(
|
||||||
canPop: true,
|
builder: (context, sizingInformation) =>
|
||||||
onPopInvokedWithResult: (didPop, result) {
|
Scaffold(
|
||||||
if (didPop) return;
|
key: _scaffoldKey,
|
||||||
// 可以在这里处理返回逻辑
|
appBar: MiniNavigationBar(
|
||||||
},
|
title: S.of(context).minipos,
|
||||||
child: Scaffold(
|
back: true,
|
||||||
key: _scaffoldKey,
|
breadCrumbs: [
|
||||||
appBar: MiniNavigationBar(
|
BreadCrumb(S.of(context).minipos, null),
|
||||||
title: S.of(context).minipos,
|
],
|
||||||
back: true,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
breadCrumbs: [
|
),
|
||||||
BreadCrumb(S.of(context).minipos, null),
|
drawer: null,
|
||||||
],
|
body: ScreenTypeLayout(
|
||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
mobile: MobileMiniPosLearnMore(data!),
|
||||||
|
tablet: DesktopMiniPosLearnMore(data!),
|
||||||
|
desktop: DesktopMiniPosLearnMore(data!),
|
||||||
|
),
|
||||||
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
|
tablet: BottomNav(),
|
||||||
|
desktop: BottomNav(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
drawer: null,
|
|
||||||
body: ScreenTypeLayout.builder(
|
|
||||||
mobile: (context) => MobileMiniPosLearnMore(data!),
|
|
||||||
tablet: (context) => DesktopMiniPosLearnMore(data!),
|
|
||||||
desktop: (context) => DesktopMiniPosLearnMore(data!),
|
|
||||||
),
|
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0),
|
|
||||||
tablet: (context) => BottomNav(),
|
|
||||||
desktop: (context) => BottomNav(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
onWillPop: () async {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ import '../widgets/desktop/desktop_my_addresses.dart';
|
|||||||
import '../widgets/mobile/mobile_my_addresses.dart';
|
import '../widgets/mobile/mobile_my_addresses.dart';
|
||||||
|
|
||||||
class MyAddresses extends StatelessWidget {
|
class MyAddresses extends StatelessWidget {
|
||||||
|
final Key? key;
|
||||||
final int businessId;
|
final int businessId;
|
||||||
|
|
||||||
const MyAddresses({Key? key, int? businessId}) :
|
const MyAddresses({this.key, int? businessId}) :
|
||||||
businessId = businessId ?? Constants.BUSINESS_ID;
|
businessId = businessId ?? Constants.BUSINESS_ID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileMyAddresses(businessId: businessId,),
|
mobile: MobileMyAddresses(businessId: businessId,),
|
||||||
tablet: (context) => DesktopMyAddresses(businessId: businessId,),
|
tablet: DesktopMyAddresses(businessId: businessId,),
|
||||||
desktop: (context) => DesktopMyAddresses(businessId: businessId,),
|
desktop: DesktopMyAddresses(businessId: businessId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ class MyCards extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileMyCards(),
|
mobile: MobileMyCards(),
|
||||||
tablet: (context) => DesktopMyCards(),
|
tablet: DesktopMyCards(),
|
||||||
desktop: (context) => DesktopMyCards(),
|
desktop: DesktopMyCards(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,19 +8,20 @@ import '../widgets/desktop/desktop_my_support.dart';
|
|||||||
import '../widgets/mobile/mobile_my_support.dart';
|
import '../widgets/mobile/mobile_my_support.dart';
|
||||||
|
|
||||||
class MySupport extends StatelessWidget {
|
class MySupport extends StatelessWidget {
|
||||||
|
final Key? key;
|
||||||
final int businessId;
|
final int businessId;
|
||||||
|
|
||||||
const MySupport({Key? key, int? businessId}) :
|
const MySupport({this.key, int? businessId}) :
|
||||||
businessId = businessId ?? Constants.BUSINESS_ID;
|
businessId = businessId ?? Constants.BUSINESS_ID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileMySupport(businessId: businessId,),
|
mobile: MobileMySupport(businessId: businessId,),
|
||||||
tablet: (context) => DesktopMySupport(businessId: businessId,),
|
tablet: DesktopMySupport(businessId: businessId,),
|
||||||
desktop: (context) => DesktopMySupport(businessId: businessId,),
|
desktop: DesktopMySupport(businessId: businessId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,24 +7,25 @@ import '../widgets/desktop/desktop_new_address.dart';
|
|||||||
import '../widgets/mobile/mobile_new_address.dart';
|
import '../widgets/mobile/mobile_new_address.dart';
|
||||||
|
|
||||||
class NewAddress extends StatelessWidget {
|
class NewAddress extends StatelessWidget {
|
||||||
|
final Key? key;
|
||||||
final LocatedAddress? locatedAddress;
|
final LocatedAddress? locatedAddress;
|
||||||
final int? businessId;
|
final int? businessId;
|
||||||
const NewAddress({Key? key, this.locatedAddress, this.businessId}) : super(key: key);
|
const NewAddress({this.key, this.locatedAddress, this.businessId}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileNewAddress(
|
mobile: MobileNewAddress(
|
||||||
locatedAddress: locatedAddress,
|
locatedAddress: locatedAddress,
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
),
|
),
|
||||||
tablet: (context) => DesktopNewAddress(
|
tablet: DesktopNewAddress(
|
||||||
locatedAddress: locatedAddress,
|
locatedAddress: locatedAddress,
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
),
|
),
|
||||||
desktop: (context) => DesktopNewAddress(
|
desktop: DesktopNewAddress(
|
||||||
locatedAddress: locatedAddress,
|
locatedAddress: locatedAddress,
|
||||||
businessId: businessId,
|
businessId: businessId,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ class NewComment extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileNewComment(orderId,),
|
mobile: MobileNewComment(orderId,),
|
||||||
tablet: (context) => DesktopNewComment(orderId,),
|
tablet: DesktopNewComment(orderId,),
|
||||||
desktop: (context) => DesktopNewComment(orderId,),
|
desktop: DesktopNewComment(orderId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-10
@@ -14,9 +14,10 @@ import '../widgets/mobile/MobileBottomNav.dart';
|
|||||||
import '../widgets/mobile/mobile_new_ticket.dart';
|
import '../widgets/mobile/mobile_new_ticket.dart';
|
||||||
|
|
||||||
class NewTicket extends StatefulWidget {
|
class NewTicket extends StatefulWidget {
|
||||||
final int? businessId;
|
final Key? key;
|
||||||
|
final int businessId;
|
||||||
|
|
||||||
const NewTicket({Key? key, int? businessId}) :
|
const NewTicket({this.key, int? businessId}) :
|
||||||
businessId = businessId ?? Constants.BUSINESS_ID;
|
businessId = businessId ?? Constants.BUSINESS_ID;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -51,15 +52,15 @@ class NewTicketState extends State<NewTicket> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileNewTicket(businessId: widget.businessId!,),
|
mobile: MobileNewTicket(businessId: widget.businessId,),
|
||||||
tablet: (context) => DesktopNewTicket(businessId: widget.businessId!,),
|
tablet: DesktopNewTicket(businessId: widget.businessId,),
|
||||||
desktop: (context) => DesktopNewTicket(businessId: widget.businessId!,),
|
desktop: DesktopNewTicket(businessId: widget.businessId,),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,15 +28,15 @@ class NewUser extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileNewUser(),
|
mobile: MobileNewUser(),
|
||||||
tablet: (context) => DesktopNewUser(),
|
tablet: DesktopNewUser(),
|
||||||
desktop: (context) => DesktopNewUser(),
|
desktop: DesktopNewUser(),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ class OrderDetail extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileOrderDetail(orderId, fromOrders: fromOrders,),
|
mobile: MobileOrderDetail(orderId, fromOrders: fromOrders,),
|
||||||
tablet: (context) => DesktopOrderDetail(orderId, fromOrders: fromOrders,),
|
tablet: DesktopOrderDetail(orderId, fromOrders: fromOrders,),
|
||||||
desktop: (context) => DesktopOrderDetail(orderId, fromOrders: fromOrders,),
|
desktop: DesktopOrderDetail(orderId, fromOrders: fromOrders,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ class PayNow extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobilePayNow(orderId,),
|
mobile: MobilePayNow(orderId,),
|
||||||
tablet: (context) => DesktopPayNow(orderId,),
|
tablet: DesktopPayNow(orderId,),
|
||||||
desktop: (context) => DesktopPayNow(orderId,),
|
desktop: DesktopPayNow(orderId,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import '../utils/http_util.dart';
|
|||||||
import '../utils/utils.dart';
|
import '../utils/utils.dart';
|
||||||
|
|
||||||
class PlainPage extends StatefulWidget {
|
class PlainPage extends StatefulWidget {
|
||||||
final int businessId;
|
final int? businessId;
|
||||||
final String? slug;
|
final String slug;
|
||||||
|
|
||||||
const PlainPage(this.slug, {required this.businessId, Key? key}) :
|
const PlainPage(this.slug, {this.businessId, Key? key}) :
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -43,10 +43,10 @@ class PlainPageState extends State<PlainPage> {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobilePlainPage(blog!),
|
mobile: MobilePlainPage(blog!),
|
||||||
tablet: (context) => DesktopPlainPage(blog!),
|
tablet: DesktopPlainPage(blog!),
|
||||||
desktop: (context) => DesktopPlainPage(blog!),
|
desktop: DesktopPlainPage(blog!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ class PlainPageState extends State<PlainPage> {
|
|||||||
void loadData() {
|
void loadData() {
|
||||||
HttpUtil.httpGet(
|
HttpUtil.httpGet(
|
||||||
'v1/special-page',
|
'v1/special-page',
|
||||||
businessId: widget.businessId,
|
businessId: widget.businessId!,
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'bid': widget.slug,
|
'bid': widget.slug,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import '../widgets/desktop/desktop_product_detail_page.dart';
|
|||||||
import '../widgets/mobile/mobile_product_detail_page.dart';
|
import '../widgets/mobile/mobile_product_detail_page.dart';
|
||||||
|
|
||||||
class ProductDetailPage extends StatelessWidget {
|
class ProductDetailPage extends StatelessWidget {
|
||||||
final Business business;
|
final Business? business;
|
||||||
final Product product;
|
final Product? product;
|
||||||
|
|
||||||
const ProductDetailPage({required this.business, required this.product, Key? key}) :
|
const ProductDetailPage({this.business, this.product, Key? key}) :
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
|
|
||||||
@@ -23,10 +23,10 @@ class ProductDetailPage extends StatelessWidget {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileProductDetailPage(business: business, product: product,),
|
mobile: MobileProductDetailPage(business: business!, product: product!,),
|
||||||
tablet: (context) => DesktopProductDetailPage(business: business, product: product,),
|
tablet: DesktopProductDetailPage(business: business!, product: product!,),
|
||||||
desktop: (context) => DesktopProductDetailPage(business: business, product: product,),
|
desktop: DesktopProductDetailPage(business: business!, product: product!,),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ class ProductSearch extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => mobile.ProductSearch(business),
|
mobile: mobile.ProductSearch(business),
|
||||||
tablet: (context) => desktop.ProductSearch(business),
|
tablet: desktop.ProductSearch(business),
|
||||||
desktop: (context) => desktop.ProductSearch(business),
|
desktop: desktop.ProductSearch(business),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ class RenewLicenseState extends State<RenewLicense> {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileRenewLicense(Constants.BUSINESS_ID),
|
mobile: MobileRenewLicense(Constants.BUSINESS_ID),
|
||||||
tablet: (context) => DesktopRenewLicense(Constants.BUSINESS_ID),
|
tablet: DesktopRenewLicense(Constants.BUSINESS_ID),
|
||||||
desktop: (context) => DesktopRenewLicense(Constants.BUSINESS_ID),
|
desktop: DesktopRenewLicense(Constants.BUSINESS_ID),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,10 @@ class RenewMiniOfficeState extends State<RenewMiniOffice> {
|
|||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileRenewMiniOffice(data!),
|
mobile: MobileRenewMiniOffice(data!),
|
||||||
tablet: (context) => DesktopRenewMiniOffice(data!),
|
tablet: DesktopRenewMiniOffice(data!),
|
||||||
desktop: (context) => DesktopRenewMiniOffice(data!),
|
desktop: DesktopRenewMiniOffice(data!),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import '../widgets/mobile/mobile_reset_password.dart';
|
|||||||
|
|
||||||
class ResetPassword extends StatelessWidget {
|
class ResetPassword extends StatelessWidget {
|
||||||
final String mobile;
|
final String mobile;
|
||||||
final String code;
|
final String? code;
|
||||||
const ResetPassword(this.mobile, {Key? key, required this.code}) : super(key: key);
|
const ResetPassword(this.mobile, {Key? key, this.code}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -30,15 +30,15 @@ class ResetPassword extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileResetPassword(mobile, code: code,),
|
mobile: MobileResetPassword(mobile, code: code,),
|
||||||
tablet: (context) => DesktopResetPassword(mobile, code: code,),
|
tablet: DesktopResetPassword(mobile, code: code,),
|
||||||
desktop: (context) => DesktopResetPassword(mobile, code: code,),
|
desktop: DesktopResetPassword(mobile, code: code,),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,17 +5,18 @@ import '../widgets/mobile/mobile_search_place.dart';
|
|||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
class SearchPlace extends StatelessWidget {
|
class SearchPlace extends StatelessWidget {
|
||||||
|
final Key? key;
|
||||||
final int businessId;
|
final int businessId;
|
||||||
const SearchPlace(this.businessId, {Key? key}) : super(key: key);
|
const SearchPlace(this.businessId, {this.key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) =>
|
builder: (context, sizingInformation) =>
|
||||||
ScreenTypeLayout.builder(
|
ScreenTypeLayout(
|
||||||
mobile: (context) => MobileSearchPlace(businessId),
|
mobile: MobileSearchPlace(businessId),
|
||||||
tablet: (context) => DesktopSearchPlace(businessId),
|
tablet: DesktopSearchPlace(businessId),
|
||||||
desktop: (context) => DesktopSearchPlace(businessId),
|
desktop: DesktopSearchPlace(businessId),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -13,8 +13,8 @@ import '../widgets/mobile/mobile_set_password.dart';
|
|||||||
|
|
||||||
class SetPassword extends StatelessWidget {
|
class SetPassword extends StatelessWidget {
|
||||||
final String mobile;
|
final String mobile;
|
||||||
final String code;
|
final String? code;
|
||||||
const SetPassword(this.mobile, {Key? key, required this.code}) : super(key: key);
|
const SetPassword(this.mobile, {Key? key, this.code}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -30,15 +30,15 @@ class SetPassword extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileSetPassword(mobile, code: code,),
|
mobile: MobileSetPassword(mobile, code: code,),
|
||||||
tablet: (context) => DesktopSetPassword(mobile, code: code,),
|
tablet: DesktopSetPassword(mobile, code: code,),
|
||||||
desktop: (context) => DesktopSetPassword(mobile, code: code,),
|
desktop: DesktopSetPassword(mobile, code: code,),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
+4
-4
@@ -23,14 +23,14 @@ class ShopState extends State<Shop> {
|
|||||||
widget.businessId == null ? Utils.getBusinessId() : widget.businessId!;
|
widget.businessId == null ? Utils.getBusinessId() : widget.businessId!;
|
||||||
|
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
builder: (context, sizingInformation) => ScreenTypeLayout.builder(
|
builder: (context, sizingInformation) => ScreenTypeLayout(
|
||||||
mobile: (context) => mobile.Shop(
|
mobile: mobile.Shop(
|
||||||
businessId: _businessId,
|
businessId: _businessId,
|
||||||
),
|
),
|
||||||
tablet: (context) => desktop.Shop(
|
tablet: desktop.Shop(
|
||||||
businessId: _businessId,
|
businessId: _businessId,
|
||||||
),
|
),
|
||||||
desktop: (context) => desktop.Shop(
|
desktop: desktop.Shop(
|
||||||
businessId: _businessId,
|
businessId: _businessId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ class StoreProductSearch extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileStoreProductSearch(business,),
|
mobile: MobileStoreProductSearch(business,),
|
||||||
tablet: (context) => DesktopStoreProductSearch(business),
|
tablet: DesktopStoreProductSearch(business),
|
||||||
desktop: (context) => DesktopStoreProductSearch(business),
|
desktop: DesktopStoreProductSearch(business),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 1,),
|
mobile: MobileBottomNav(currentIndex: 1,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
|
||||||
|
|
||||||
import '../models/order.dart';
|
|
||||||
import '../models/payment_platform.dart';
|
|
||||||
import '../models/stripe_payment_method.dart';
|
|
||||||
import '../store/actions.dart';
|
|
||||||
import '../store/store.dart';
|
|
||||||
import '../widgets/desktop/desktop_stripe_pay_web.dart';
|
|
||||||
import '../widgets/mobile/mobile_stripe_pay_web.dart';
|
|
||||||
|
|
||||||
class StripePayWeb extends StatelessWidget {
|
|
||||||
final Order order;
|
|
||||||
final PaymentPlatform paymentPlatform;
|
|
||||||
final StripePaymentMethod? stripePaymentMethod;
|
|
||||||
|
|
||||||
const StripePayWeb(this.order, this.paymentPlatform, {this.stripePaymentMethod});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
store.dispatch(UpdateContext(context));
|
|
||||||
|
|
||||||
return ResponsiveBuilder(
|
|
||||||
builder: (context, sizingInformation) =>
|
|
||||||
ScreenTypeLayout.builder(
|
|
||||||
mobile: (context) => MobileStripePayWeb(order, paymentPlatform, stripePaymentMethod: stripePaymentMethod,),
|
|
||||||
tablet: (context) => DesktopStripePayWeb(order, paymentPlatform, stripePaymentMethod: stripePaymentMethod,),
|
|
||||||
desktop: (context) => DesktopStripePayWeb(order, paymentPlatform, stripePaymentMethod: stripePaymentMethod,),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -29,15 +29,15 @@ class UserProfile extends StatelessWidget {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileUserProfile(),
|
mobile: MobileUserProfile(),
|
||||||
tablet: (context) => DesktopUserProfile(),
|
tablet: DesktopUserProfile(),
|
||||||
desktop: (context) => DesktopUserProfile(),
|
desktop: DesktopUserProfile(),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ import '../widgets/mobile/MobileBottomNav.dart';
|
|||||||
import '../widgets/mobile/mobile_view_blog.dart';
|
import '../widgets/mobile/mobile_view_blog.dart';
|
||||||
|
|
||||||
class ViewBlog extends StatefulWidget {
|
class ViewBlog extends StatefulWidget {
|
||||||
|
final Key? key;
|
||||||
final int bid;
|
final int bid;
|
||||||
|
|
||||||
const ViewBlog(this.bid, {Key? key}) : super(key: key);
|
const ViewBlog(this.bid, {this.key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() {
|
State<StatefulWidget> createState() {
|
||||||
@@ -50,15 +51,15 @@ class ViewBlogState extends State<ViewBlog> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileViewBlog(widget.bid),
|
mobile: MobileViewBlog(widget.bid),
|
||||||
tablet: (context) => DesktopViewBlog(widget.bid),
|
tablet: DesktopViewBlog(widget.bid),
|
||||||
desktop: (context) => DesktopViewBlog(widget.bid),
|
desktop: DesktopViewBlog(widget.bid),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ import '../widgets/mobile/MobileBottomNav.dart';
|
|||||||
import '../widgets/mobile/mobile_view_ticket.dart';
|
import '../widgets/mobile/mobile_view_ticket.dart';
|
||||||
|
|
||||||
class ViewTicket extends StatefulWidget {
|
class ViewTicket extends StatefulWidget {
|
||||||
|
final Key? key;
|
||||||
final int ticketId;
|
final int ticketId;
|
||||||
|
|
||||||
const ViewTicket(this.ticketId, {Key? key}) : super(key: key);
|
const ViewTicket(this.ticketId, {this.key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() {
|
State<StatefulWidget> createState() {
|
||||||
@@ -50,15 +51,15 @@ class ViewTicketState extends State<ViewTicket> {
|
|||||||
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
breadCrumbHeight: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? null : Constants.BREADCRUMB_HEIGHT,
|
||||||
),
|
),
|
||||||
drawer: null,
|
drawer: null,
|
||||||
body: ScreenTypeLayout.builder(
|
body: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileViewTicket(widget.ticketId),
|
mobile: MobileViewTicket(widget.ticketId),
|
||||||
tablet: (context) => DesktopViewTicket(widget.ticketId),
|
tablet: DesktopViewTicket(widget.ticketId),
|
||||||
desktop: (context) => DesktopViewTicket(widget.ticketId),
|
desktop: DesktopViewTicket(widget.ticketId),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: ScreenTypeLayout.builder(
|
bottomNavigationBar: ScreenTypeLayout(
|
||||||
mobile: (context) => MobileBottomNav(currentIndex: 0,),
|
mobile: MobileBottomNav(currentIndex: 0,),
|
||||||
tablet: (context) => BottomNav(),
|
tablet: BottomNav(),
|
||||||
desktop: (context) => BottomNav(),
|
desktop: BottomNav(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class UpdateContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UpdateLocale {
|
class UpdateLocale {
|
||||||
final Locale? locale;
|
final Locale locale;
|
||||||
UpdateLocale(this.locale);
|
UpdateLocale(this.locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ final cartInfoReducer = combineReducers<List<CartInfo>?>([
|
|||||||
TypedReducer<List<CartInfo>?, UpdateCartInfo>(_updateCartInfo)
|
TypedReducer<List<CartInfo>?, UpdateCartInfo>(_updateCartInfo)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
List<CartInfo> _updateCartInfo(List<CartInfo>? cartInfos, action) {
|
List<CartInfo>? _updateCartInfo(List<CartInfo>? cartInfos, action) {
|
||||||
return action.cartInfos;
|
return action.cartInfos;
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,6 @@ final contextReducer = combineReducers<BuildContext?>([
|
|||||||
TypedReducer<BuildContext?, UpdateContext>(_updateContext)
|
TypedReducer<BuildContext?, UpdateContext>(_updateContext)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
BuildContext _updateContext(BuildContext? context, action) {
|
BuildContext? _updateContext(BuildContext? context, action) {
|
||||||
return action.context;
|
return action.context;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ final deviceIdReducer = combineReducers<String?>([
|
|||||||
TypedReducer<String?, UpdateDeviceId>(_updateDeviceId)
|
TypedReducer<String?, UpdateDeviceId>(_updateDeviceId)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
String _updateDeviceId(String? deviceId, action) {
|
String? _updateDeviceId(String? deviceId, action) {
|
||||||
return action.deviceId;
|
return action.deviceId;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ final fcmtokenReducer = combineReducers<String?>([
|
|||||||
TypedReducer<String?, UpdateFcmToken>(_updateFcmToken)
|
TypedReducer<String?, UpdateFcmToken>(_updateFcmToken)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
String _updateFcmToken(String? token, action) {
|
String? _updateFcmToken(String? token, action) {
|
||||||
return action.token;
|
return action.token;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ final lastVisitReducer = combineReducers<List<int>?>([
|
|||||||
TypedReducer<List<int>?, UpdateLastVisit>(_updateLastVisit)
|
TypedReducer<List<int>?, UpdateLastVisit>(_updateLastVisit)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
List<int> _updateLastVisit(List<int>? lastVisit, action) {
|
List<int>? _updateLastVisit(List<int>? lastVisit, action) {
|
||||||
return action.lastVisit;
|
return action.lastVisit;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ final localeReducer = combineReducers<Locale?>([
|
|||||||
TypedReducer<Locale?, UpdateLocale>(_updateLocale)
|
TypedReducer<Locale?, UpdateLocale>(_updateLocale)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Locale _updateLocale(Locale? locale, action) {
|
Locale? _updateLocale(Locale? locale, action) {
|
||||||
return action.locale;
|
return action.locale;
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,6 @@ final locatedAddressReducer = combineReducers<LocatedAddress?>([
|
|||||||
TypedReducer<LocatedAddress?, UpdateLocatedAddress>(_updateLocatedAddress)
|
TypedReducer<LocatedAddress?, UpdateLocatedAddress>(_updateLocatedAddress)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
LocatedAddress _updateLocatedAddress(LocatedAddress? locatedAddress, action) {
|
LocatedAddress? _updateLocatedAddress(LocatedAddress? locatedAddress, action) {
|
||||||
return action.locatedAddress;
|
return action.locatedAddress;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,6 @@ final tableNumberReducer = combineReducers<String?>([
|
|||||||
TypedReducer<String?, UpdateTableNumber>(_updateTableNumber)
|
TypedReducer<String?, UpdateTableNumber>(_updateTableNumber)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
String _updateTableNumber(String? tableNumber, action) {
|
String? _updateTableNumber(String? tableNumber, action) {
|
||||||
return action.tableNumber;
|
return action.tableNumber;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
/// 自定义实现,替代已停维的 `countdown` 包的 [CountDown]。
|
||||||
|
///
|
||||||
|
/// 用法与原包兼容:
|
||||||
|
/// ```dart
|
||||||
|
/// var listener = CountDown(Duration(seconds: 90)).stream.listen(null);
|
||||||
|
/// listener.onData((Duration d) { ... d.inSeconds ... });
|
||||||
|
/// listener.onDone(() { ... });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// `stream` 每秒发出剩余 [Duration](从满时长倒数到 0),到达 0 后关闭。
|
||||||
|
class CountDown {
|
||||||
|
CountDown(this.duration) : assert(!duration.isNegative);
|
||||||
|
|
||||||
|
final Duration duration;
|
||||||
|
|
||||||
|
Stream<Duration> get stream => _countdownStream();
|
||||||
|
|
||||||
|
Stream<Duration> _countdownStream() async* {
|
||||||
|
int remaining = duration.inSeconds;
|
||||||
|
while (remaining > 0) {
|
||||||
|
yield Duration(seconds: remaining);
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 1));
|
||||||
|
remaining--;
|
||||||
|
}
|
||||||
|
yield Duration.zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
-36
@@ -7,15 +7,15 @@ import 'package:crypto/crypto.dart';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import '../store/store.dart';
|
import '../store/store.dart';
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:universal_io/io.dart';
|
||||||
|
|
||||||
import '../constants.dart';
|
import '../constants.dart';
|
||||||
|
|
||||||
typedef void PostCallback(Response response);
|
typedef void PostCallback(Response response);
|
||||||
|
|
||||||
String generateSignature(String string, {String? key}) {
|
String generateSignature(String string, {String? key}) {
|
||||||
if (key == null) {
|
key ??= Constants.API_SECRET;
|
||||||
key = Constants.API_SECRET;
|
|
||||||
}
|
|
||||||
Hmac mac = new Hmac(sha256, utf8.encode(key));
|
Hmac mac = new Hmac(sha256, utf8.encode(key));
|
||||||
Digest digest = mac.convert(utf8.encode(string + key));
|
Digest digest = mac.convert(utf8.encode(string + key));
|
||||||
String base64Mac = base64.encode(utf8.encode("$digest"));
|
String base64Mac = base64.encode(utf8.encode("$digest"));
|
||||||
@@ -35,8 +35,8 @@ class HttpUtil {
|
|||||||
'Http-Contact-Authorization': '',
|
'Http-Contact-Authorization': '',
|
||||||
'Http-Device-Type': Utils.getOs(checkWeb: true),
|
'Http-Device-Type': Utils.getOs(checkWeb: true),
|
||||||
'Http-Api-Branch': 'flutter',
|
'Http-Api-Branch': 'flutter',
|
||||||
'Http-Language-Code': (store == null || store.state == null || store.state.locale == null) ? 'en' : store.state.locale!.languageCode,
|
'Http-Language-Code': store.state.locale!.languageCode,
|
||||||
'Http-Country-Code': (store == null || store.state == null || store.state.locale == null) ? 'US' : store.state.locale!.countryCode!,
|
'Http-Country-Code': store.state.locale!.countryCode ?? '',
|
||||||
};
|
};
|
||||||
|
|
||||||
static Future<dynamic> httpGet(String url,
|
static Future<dynamic> httpGet(String url,
|
||||||
@@ -57,7 +57,8 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
||||||
localHeaders['Http-Contact-Authorization'] = Utils.prefs?.getString(Constants.KEY_ACCESS_TOKEN) ?? '';
|
Box box = await Utils.getBox();
|
||||||
|
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
|
||||||
localHeaders['Http-App-Key'] = platformName;
|
localHeaders['Http-App-Key'] = platformName;
|
||||||
localHeaders['Http-Device-Type'] = platformName;
|
localHeaders['Http-Device-Type'] = platformName;
|
||||||
String requestUrl = Constants.BASE_API_URL + url;
|
String requestUrl = Constants.BASE_API_URL + url;
|
||||||
@@ -66,9 +67,7 @@ class HttpUtil {
|
|||||||
requestUrl = url;
|
requestUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryParameters != null) {
|
Utils.jsonPrettyPrint(queryParameters ?? {});
|
||||||
Utils.jsonPrettyPrint(queryParameters!);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dio dio = Dio();
|
Dio dio = Dio();
|
||||||
try {
|
try {
|
||||||
@@ -83,7 +82,6 @@ class HttpUtil {
|
|||||||
// print('response data: ${response.data}');
|
// print('response data: ${response.data}');
|
||||||
// Utils.jsonPrettyPrint(response.data);
|
// Utils.jsonPrettyPrint(response.data);
|
||||||
|
|
||||||
int statusCode = response.statusCode!;
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} on DioException catch(e) {
|
} on DioException catch(e) {
|
||||||
print('HttpGet failed, request: $requestUrl, headers: $localHeaders, error ${e.response}');
|
print('HttpGet failed, request: $requestUrl, headers: $localHeaders, error ${e.response}');
|
||||||
@@ -94,7 +92,7 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> httpPost(String url, PostCallback? callback,
|
static Future<dynamic> httpPost(String url, PostCallback callback,
|
||||||
{
|
{
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
int businessId = 0,
|
int businessId = 0,
|
||||||
@@ -115,7 +113,8 @@ class HttpUtil {
|
|||||||
localHeaders['Http-Signature'] = generateSignature(url);
|
localHeaders['Http-Signature'] = generateSignature(url);
|
||||||
}
|
}
|
||||||
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
||||||
localHeaders['Http-Contact-Authorization'] = Utils.prefs?.getString(Constants.KEY_ACCESS_TOKEN) ?? '';
|
Box box = await Utils.getBox();
|
||||||
|
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
|
||||||
localHeaders['Http-App-Key'] = platformName;
|
localHeaders['Http-App-Key'] = platformName;
|
||||||
localHeaders['Http-Device-Type'] = platformName;
|
localHeaders['Http-Device-Type'] = platformName;
|
||||||
|
|
||||||
@@ -128,15 +127,15 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't print body will cause upload Multipart file failed
|
// Don't print body will cause upload Multipart file failed
|
||||||
//Utils.jsonPrettyPrint(body);
|
//Utils.jsonPrettyPrint(body ?? {});
|
||||||
|
|
||||||
Dio dio = Dio();
|
Dio dio = Dio();
|
||||||
dio.interceptors.add(LogInterceptor());
|
dio.interceptors.add(LogInterceptor());
|
||||||
try {
|
try {
|
||||||
Response response = await dio.post(
|
Response response = await dio.post(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
queryParameters: queryParameters == null ? {} : queryParameters,
|
queryParameters: queryParameters ?? {},
|
||||||
data: isFormData ? ((formData != null)?formData:FormData.fromMap(body!)) : json.encode(body),
|
data: isFormData ? ((formData != null)?formData:FormData.fromMap(body ?? {})) : json.encode(body),
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: localHeaders,
|
headers: localHeaders,
|
||||||
contentType: isFormData ? Headers.formUrlEncodedContentType : Headers.jsonContentType,
|
contentType: isFormData ? Headers.formUrlEncodedContentType : Headers.jsonContentType,
|
||||||
@@ -147,7 +146,6 @@ class HttpUtil {
|
|||||||
|
|
||||||
// Utils.jsonPrettyPrint(response.data);
|
// Utils.jsonPrettyPrint(response.data);
|
||||||
|
|
||||||
int statusCode = response.statusCode!;
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(response);
|
callback(response);
|
||||||
}
|
}
|
||||||
@@ -155,9 +153,9 @@ class HttpUtil {
|
|||||||
} on DioException catch(e, stacktrace) {
|
} on DioException catch(e, stacktrace) {
|
||||||
if (e.response != null) {
|
if (e.response != null) {
|
||||||
try {
|
try {
|
||||||
Utils.jsonPrettyPrint(e.response?.data);
|
Utils.jsonPrettyPrint(e.response!.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(e.response?.data);
|
print(e.response!.data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (returnError) {
|
if (returnError) {
|
||||||
@@ -167,7 +165,7 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> httpPut(String url, PostCallback? callback,
|
static Future<dynamic> httpPut(String url, PostCallback callback,
|
||||||
{
|
{
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
int businessId = 0,
|
int businessId = 0,
|
||||||
@@ -188,7 +186,8 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
||||||
localHeaders['Http-Contact-Authorization'] = Utils.prefs?.getString(Constants.KEY_ACCESS_TOKEN) ?? '';
|
Box box = await Utils.getBox();
|
||||||
|
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
|
||||||
localHeaders['Http-App-Key'] = platformName;
|
localHeaders['Http-App-Key'] = platformName;
|
||||||
localHeaders['Http-Device-Type'] = platformName;
|
localHeaders['Http-Device-Type'] = platformName;
|
||||||
|
|
||||||
@@ -204,7 +203,7 @@ class HttpUtil {
|
|||||||
try {
|
try {
|
||||||
Response response = await dio.put(
|
Response response = await dio.put(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
queryParameters: queryParameters == null ? {} : queryParameters,
|
queryParameters: queryParameters ?? {},
|
||||||
data: json.encode(body),
|
data: json.encode(body),
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: localHeaders,
|
headers: localHeaders,
|
||||||
@@ -215,7 +214,6 @@ class HttpUtil {
|
|||||||
|
|
||||||
// Utils.jsonPrettyPrint(response.data);
|
// Utils.jsonPrettyPrint(response.data);
|
||||||
|
|
||||||
int statusCode = response.statusCode!;
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(response);
|
callback(response);
|
||||||
}
|
}
|
||||||
@@ -231,7 +229,7 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> httpPatch(String url, PostCallback? callback,
|
static Future<dynamic> httpPatch(String url, PostCallback callback,
|
||||||
{
|
{
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
int businessId = 0,
|
int businessId = 0,
|
||||||
@@ -252,7 +250,8 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
||||||
localHeaders['Http-Contact-Authorization'] = Utils.prefs?.getString(Constants.KEY_ACCESS_TOKEN) ?? '';
|
Box box = await Utils.getBox();
|
||||||
|
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
|
||||||
localHeaders['Http-App-Key'] = platformName;
|
localHeaders['Http-App-Key'] = platformName;
|
||||||
localHeaders['Http-Device-Type'] = platformName;
|
localHeaders['Http-Device-Type'] = platformName;
|
||||||
|
|
||||||
@@ -264,15 +263,13 @@ class HttpUtil {
|
|||||||
requestUrl = url;
|
requestUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body != null) {
|
Utils.jsonPrettyPrint(body ?? {});
|
||||||
Utils.jsonPrettyPrint(body!);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dio dio = Dio();
|
Dio dio = Dio();
|
||||||
try {
|
try {
|
||||||
Response response = await dio.patch(
|
Response response = await dio.patch(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
queryParameters: queryParameters == null ? {} : queryParameters,
|
queryParameters: queryParameters ?? {},
|
||||||
data: json.encode(body),
|
data: json.encode(body),
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: localHeaders,
|
headers: localHeaders,
|
||||||
@@ -283,7 +280,6 @@ class HttpUtil {
|
|||||||
|
|
||||||
// Utils.jsonPrettyPrint(response.data);
|
// Utils.jsonPrettyPrint(response.data);
|
||||||
|
|
||||||
int statusCode = response.statusCode!;
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(response);
|
callback(response);
|
||||||
}
|
}
|
||||||
@@ -299,7 +295,7 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<dynamic> httpDelete(String url, PostCallback? callback,
|
static Future<dynamic> httpDelete(String url, PostCallback callback,
|
||||||
{
|
{
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
int businessId = 0,
|
int businessId = 0,
|
||||||
@@ -318,7 +314,8 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
localHeaders['Http-Business-Id'] = businessId == 0 ? '${Constants.BUSINESS_ID}' : businessId.toString();
|
||||||
localHeaders['Http-Contact-Authorization'] = Utils.prefs?.getString(Constants.KEY_ACCESS_TOKEN) ?? '';
|
Box box = await Utils.getBox();
|
||||||
|
localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
|
||||||
localHeaders['Http-App-Key'] = platformName;
|
localHeaders['Http-App-Key'] = platformName;
|
||||||
localHeaders['Http-Device-Type'] = platformName;
|
localHeaders['Http-Device-Type'] = platformName;
|
||||||
|
|
||||||
@@ -330,15 +327,13 @@ class HttpUtil {
|
|||||||
requestUrl = url;
|
requestUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (body != null) {
|
Utils.jsonPrettyPrint(body ?? {});
|
||||||
Utils.jsonPrettyPrint(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dio dio = Dio();
|
Dio dio = Dio();
|
||||||
try {
|
try {
|
||||||
Response response = await dio.delete(
|
Response response = await dio.delete(
|
||||||
requestUrl,
|
requestUrl,
|
||||||
queryParameters: queryParameters == null ? {} : queryParameters,
|
queryParameters: queryParameters ?? {},
|
||||||
data: json.encode(body),
|
data: json.encode(body),
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: localHeaders,
|
headers: localHeaders,
|
||||||
@@ -347,7 +342,6 @@ class HttpUtil {
|
|||||||
|
|
||||||
// Utils.jsonPrettyPrint(response.data);
|
// Utils.jsonPrettyPrint(response.data);
|
||||||
|
|
||||||
int statusCode = response.statusCode!;
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback(response);
|
callback(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
import '../vendor/stripe_sdk/lib/stripe_sdk.dart';
|
|
||||||
import '../vendor/stripe_sdk/lib/stripe_sdk_ui.dart';
|
|
||||||
|
|
||||||
import 'mini_stripe_api_handler.dart';
|
|
||||||
|
|
||||||
class MiniStripeApi {
|
|
||||||
static MiniStripeApi? _instance;
|
|
||||||
|
|
||||||
final MiniStripeApiHandler _apiHandler;
|
|
||||||
|
|
||||||
final String publishableKey;
|
|
||||||
|
|
||||||
final String apiVersion;
|
|
||||||
|
|
||||||
/// Create a new instance, which can be used with e.g. dependency injection.
|
|
||||||
/// Throws a [Exception] if an invalid [publishableKey] has been submitted.
|
|
||||||
///
|
|
||||||
/// [publishableKey] is your publishable key, beginning with "sk_".
|
|
||||||
/// Your can copy your key from https://dashboard.stripe.com/account/apikeys
|
|
||||||
///
|
|
||||||
/// [stripeAccount] is the id of a stripe customer and stats with "cus_".
|
|
||||||
/// This is a optional parameter.
|
|
||||||
MiniStripeApi(this.publishableKey, {this.apiVersion = defaultApiVersion, String? stripeAccount})
|
|
||||||
: _apiHandler = MiniStripeApiHandler(stripeAccount: stripeAccount) {
|
|
||||||
_validateKey(publishableKey);
|
|
||||||
_apiHandler.apiVersion = apiVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initialize the managed singleton instance of [StripeApi].
|
|
||||||
/// Afterwards you can use [StripeApi.instance] to access the created instance.
|
|
||||||
///
|
|
||||||
/// [publishableKey] is your publishable key, beginning with "sk_".
|
|
||||||
/// Your can copy your key from https://dashboard.stripe.com/account/apikeys
|
|
||||||
///
|
|
||||||
/// [stripeAccount] is the id of a stripe customer and stats with "cus_".
|
|
||||||
/// This is a optional parameter.
|
|
||||||
static void init(String publishableKey, {String apiVersion = defaultApiVersion, String? stripeAccount}) {
|
|
||||||
// _instance ??= MiniStripeApi(publishableKey, uuidString, apiVersion: apiVersion, stripeAccount: stripeAccount);
|
|
||||||
_instance = MiniStripeApi(publishableKey, apiVersion: apiVersion, stripeAccount: stripeAccount);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the singleton instance of [StripeApi].
|
|
||||||
/// Throws an [Exception] if [StripeApi.init] hasn't been called previously.
|
|
||||||
static MiniStripeApi get instance {
|
|
||||||
if (_instance == null) {
|
|
||||||
throw Exception('Attempted to get singleton instance of StripeApi without initialization');
|
|
||||||
}
|
|
||||||
return _instance!;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a stripe Token
|
|
||||||
/// https://stripe.com/docs/api/tokens
|
|
||||||
Future<Map<String, dynamic>> createToken(Map<String, dynamic> data) async {
|
|
||||||
final path = '/tokens';
|
|
||||||
return _apiHandler.request(RequestMethod.post, path, publishableKey, apiVersion, params: data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a PaymentMethod.
|
|
||||||
/// https://stripe.com/docs/api/payment_methods/create
|
|
||||||
Future<Map<String, dynamic>> createPaymentMethod(Map<String, dynamic> data) async {
|
|
||||||
final path = '/payment_methods';
|
|
||||||
return _apiHandler.request(RequestMethod.post, path, publishableKey, apiVersion, params: data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a PaymentMethod from a card.
|
|
||||||
/// This will only create a PaymentMethod with the minimum required properties.
|
|
||||||
/// To include additional properties such as billing details, use [StripeCard.toPaymentMethod], add additional details
|
|
||||||
/// and then use [createPaymentMethod].
|
|
||||||
Future<Map<String, dynamic>> createPaymentMethodFromCard(StripeCard card) async {
|
|
||||||
return createPaymentMethod(card.toPaymentMethod());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new Source object.
|
|
||||||
/// https://stripe.com/docs/api/sources/create
|
|
||||||
Future<Map<String, dynamic>> createSource(Map<String, dynamic> data) async {
|
|
||||||
final path = '/sources';
|
|
||||||
return _apiHandler.request(RequestMethod.post, path, publishableKey, apiVersion, params: data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve a PaymentIntent.
|
|
||||||
/// https://stripe.com/docs/api/payment_intents/retrieve
|
|
||||||
Future<Map<String, dynamic>> retrievePaymentIntent(String clientSecret, {String? apiVersion}) async {
|
|
||||||
final intentId = _parseIdFromClientSecret(clientSecret);
|
|
||||||
final path = '/payment_intents/$intentId';
|
|
||||||
final params = {'client_secret': clientSecret};
|
|
||||||
return _apiHandler.request(RequestMethod.get, path, publishableKey, apiVersion ?? this.apiVersion, params: params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Confirm a PaymentIntent
|
|
||||||
/// https://stripe.com/docs/api/payment_intents/confirm
|
|
||||||
Future<Map<String, dynamic>> confirmPaymentIntent(String clientSecret, {Map<String, dynamic>? data, String? idempotencyKey}) async {
|
|
||||||
final params = data ?? {};
|
|
||||||
final intent = _parseIdFromClientSecret(clientSecret);
|
|
||||||
params['client_secret'] = clientSecret;
|
|
||||||
final path = '/payment_intents/$intent/confirm';
|
|
||||||
return _apiHandler.request(RequestMethod.post, path, publishableKey, apiVersion, params: params, idempotencyKey: idempotencyKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve a SetupIntent.
|
|
||||||
/// https://stripe.com/docs/api/setup_intents/retrieve
|
|
||||||
Future<Map<String, dynamic>> retrieveSetupIntent(String clientSecret, {String? apiVersion}) async {
|
|
||||||
final intentId = _parseIdFromClientSecret(clientSecret);
|
|
||||||
final path = '/setup_intents/$intentId';
|
|
||||||
final params = {'client_secret': clientSecret};
|
|
||||||
return _apiHandler.request(RequestMethod.get, path, publishableKey, apiVersion, params: params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Confirm a SetupIntent
|
|
||||||
/// https://stripe.com/docs/api/setup_intents/confirm
|
|
||||||
Future<Map<String, dynamic>> confirmSetupIntent(String clientSecret, {Map<String, dynamic>? data}) async {
|
|
||||||
final params = data ?? {};
|
|
||||||
final intent = _parseIdFromClientSecret(clientSecret);
|
|
||||||
params['client_secret'] = clientSecret;
|
|
||||||
final path = '/setup_intents/$intent/confirm';
|
|
||||||
return _apiHandler.request(RequestMethod.post, path, publishableKey, apiVersion, params: params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Validates the received [publishableKey] and throws a [Exception] if an
|
|
||||||
/// invalid key has been submitted.
|
|
||||||
static void _validateKey(String publishableKey) {
|
|
||||||
if (publishableKey == null || publishableKey.isEmpty) {
|
|
||||||
throw Exception('Invalid Publishable Key: '
|
|
||||||
'You must use a valid publishable key to create a token. '
|
|
||||||
'For more info, see https://stripe.com/docs/stripe.js.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishableKey.startsWith('sk_')) {
|
|
||||||
throw Exception('Invalid Publishable Key: '
|
|
||||||
'You are using a secret key to create a token, '
|
|
||||||
'instead of the publishable one. For more info, '
|
|
||||||
'see https://stripe.com/docs/stripe.js');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String _parseIdFromClientSecret(String clientSecret) {
|
|
||||||
return clientSecret.split('_secret')[0];
|
|
||||||
}
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:convert' show json;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import '../vendor/stripe_sdk/lib/stripe_sdk.dart';
|
|
||||||
|
|
||||||
class MiniStripeApiHandler {
|
|
||||||
static const String LIVE_API_BASE = 'https://api.stripe.com';
|
|
||||||
static const String LIVE_LOGGING_BASE = 'https://q.stripe.com';
|
|
||||||
static const String LOGGING_ENDPOINT = 'https://m.stripe.com/4';
|
|
||||||
static const String LIVE_API_PATH = LIVE_API_BASE + '/v1';
|
|
||||||
|
|
||||||
static const String CHARSET = 'UTF-8';
|
|
||||||
static const String CUSTOMERS = 'customers';
|
|
||||||
static const String TOKENS = 'tokens';
|
|
||||||
static const String SOURCES = 'sources';
|
|
||||||
|
|
||||||
static const String HEADER_KEY_REQUEST_ID = 'Request-Id';
|
|
||||||
static const String FIELD_ERROR = 'error';
|
|
||||||
static const String FIELD_SOURCE = 'source';
|
|
||||||
|
|
||||||
String apiVersion = defaultApiVersion;
|
|
||||||
|
|
||||||
static const String MALFORMED_RESPONSE_MESSAGE = 'An improperly formatted error response was found.';
|
|
||||||
|
|
||||||
final http.Client _client = http.Client();
|
|
||||||
|
|
||||||
final String? stripeAccount;
|
|
||||||
|
|
||||||
MiniStripeApiHandler({this.stripeAccount});
|
|
||||||
|
|
||||||
Future<Map<String, dynamic>> request(RequestMethod method, String path, String key, String? apiVersion,
|
|
||||||
{final Map<String, dynamic>? params, String? idempotencyKey}) {
|
|
||||||
final options = RequestOptions(key: key, apiVersion: apiVersion, stripeAccount: stripeAccount, idempotencyKey: idempotencyKey);
|
|
||||||
return _getStripeResponse(method, LIVE_API_PATH + path, options, params: params);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<Map<String, dynamic>> _getStripeResponse(RequestMethod method, final String url, final RequestOptions options,
|
|
||||||
{final Map<String, dynamic>? params}) async {
|
|
||||||
print('url: $url');
|
|
||||||
final headers = _headers(options: options);
|
|
||||||
|
|
||||||
print('headers: $headers');
|
|
||||||
http.Response response;
|
|
||||||
|
|
||||||
switch (method) {
|
|
||||||
case RequestMethod.get:
|
|
||||||
var fUrl = url;
|
|
||||||
if (params != null && params.isNotEmpty) {
|
|
||||||
fUrl = '$url?${_encodeMap(params)}';
|
|
||||||
}
|
|
||||||
response = await _client.get(Uri.parse(fUrl), headers: headers);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RequestMethod.post:
|
|
||||||
response = await _client.post(
|
|
||||||
Uri.parse(url),
|
|
||||||
headers: headers,
|
|
||||||
body: params != null ? _urlEncodeMap(params) : null,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RequestMethod.delete:
|
|
||||||
response = await _client.delete(Uri.parse(url), headers: headers);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception('Request Method: $method not implemented');
|
|
||||||
}
|
|
||||||
|
|
||||||
final requestId = response.headers[HEADER_KEY_REQUEST_ID];
|
|
||||||
|
|
||||||
final statusCode = response.statusCode;
|
|
||||||
Map<String, dynamic> resp;
|
|
||||||
try {
|
|
||||||
resp = json.decode(response.body);
|
|
||||||
} catch (error) {
|
|
||||||
final stripeError = StripeApiError(requestId, {StripeApiError.fieldMessage: MALFORMED_RESPONSE_MESSAGE});
|
|
||||||
throw StripeApiException(stripeError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (statusCode < 200 || statusCode >= 300) {
|
|
||||||
final Map<String, dynamic> errBody = resp[FIELD_ERROR];
|
|
||||||
final stripeError = StripeApiError(requestId, errBody);
|
|
||||||
throw StripeApiException(stripeError);
|
|
||||||
} else {
|
|
||||||
return resp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
|
||||||
static Map<String, String> _headers({RequestOptions? options}) {
|
|
||||||
final headers = <String, String>{};
|
|
||||||
headers['Accept-Charset'] = CHARSET;
|
|
||||||
headers['Accept'] = 'application/json';
|
|
||||||
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
||||||
headers['User-Agent'] = 'StripeSDK/v2';
|
|
||||||
|
|
||||||
if (options != null) {
|
|
||||||
headers['Authorization'] = 'Bearer ${options.key}';
|
|
||||||
}
|
|
||||||
|
|
||||||
// debug headers
|
|
||||||
final propertyMap = <String, String>{};
|
|
||||||
propertyMap['os.name'] = defaultTargetPlatform.toString();
|
|
||||||
propertyMap['lang'] = 'Dart';
|
|
||||||
propertyMap['publisher'] = 'lars.dahl@gmail.com';
|
|
||||||
|
|
||||||
headers['X-Stripe-Client-User-Agent'] = json.encode(propertyMap);
|
|
||||||
|
|
||||||
if (options != null) {
|
|
||||||
if (options.apiVersion != null) {
|
|
||||||
headers['Stripe-Version'] = options.apiVersion!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.stripeAccount != null) {
|
|
||||||
headers['Stripe-Account'] = options.stripeAccount!;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.idempotencyKey != null) {
|
|
||||||
headers['Idempotency-Key'] = options.idempotencyKey!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers;
|
|
||||||
}
|
|
||||||
|
|
||||||
static String _encodeMap(Map<String, dynamic> params) {
|
|
||||||
return params.keys
|
|
||||||
.map((key) => '${Uri.encodeComponent(key)}=${Uri.encodeComponent(params[key].toString())}')
|
|
||||||
.join('&');
|
|
||||||
}
|
|
||||||
|
|
||||||
static String _urlEncodeMap(dynamic data) {
|
|
||||||
final urlData = StringBuffer('');
|
|
||||||
var first = true;
|
|
||||||
void urlEncode(dynamic sub, String path) {
|
|
||||||
if (sub is List) {
|
|
||||||
for (var i = 0; i < sub.length; i++) {
|
|
||||||
urlEncode(sub[i], '$path%5B%5D');
|
|
||||||
}
|
|
||||||
} else if (sub is Map) {
|
|
||||||
sub.forEach((k, v) {
|
|
||||||
if (path == '') {
|
|
||||||
urlEncode(v, '${Uri.encodeQueryComponent(k)}');
|
|
||||||
} else {
|
|
||||||
urlEncode(v, '$path%5B${Uri.encodeQueryComponent(k)}%5D');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!first) {
|
|
||||||
urlData.write('&');
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
urlData.write('$path=${Uri.encodeQueryComponent(sub.toString())}');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
urlEncode(data, '');
|
|
||||||
return urlData.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@ class ShopScrollController extends ScrollController {
|
|||||||
this.coordinator, {
|
this.coordinator, {
|
||||||
double initialScrollOffset = 0.0,
|
double initialScrollOffset = 0.0,
|
||||||
this.keepScrollOffset = true,
|
this.keepScrollOffset = true,
|
||||||
required this.debugLabel,
|
this.debugLabel,
|
||||||
}) : assert(initialScrollOffset != null),
|
}) : assert(initialScrollOffset != null),
|
||||||
assert(keepScrollOffset != null),
|
assert(keepScrollOffset != null),
|
||||||
_initialScrollOffset = initialScrollOffset;
|
_initialScrollOffset = initialScrollOffset;
|
||||||
@@ -38,7 +38,7 @@ class ShopScrollController extends ScrollController {
|
|||||||
final bool keepScrollOffset;
|
final bool keepScrollOffset;
|
||||||
|
|
||||||
/// [toString]输出中使用的标签。 旨在帮助在调试输出中标识滚动控制器实例。
|
/// [toString]输出中使用的标签。 旨在帮助在调试输出中标识滚动控制器实例。
|
||||||
final String debugLabel;
|
final String? debugLabel;
|
||||||
|
|
||||||
/// The currently attached positions. 当前附加的 [positions]。
|
/// The currently attached positions. 当前附加的 [positions]。
|
||||||
/// 这不应直接突变。 可以使用[attach]和[detach]添加和删除[ScrollPosition]对象。
|
/// 这不应直接突变。 可以使用[attach]和[detach]添加和删除[ScrollPosition]对象。
|
||||||
@@ -175,7 +175,7 @@ class ShopScrollController extends ScrollController {
|
|||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void debugFillDescription(List<String> description) {
|
void debugFillDescription(List<String> description) {
|
||||||
super.debugFillDescription(description);
|
super.debugFillDescription(description);
|
||||||
if (debugLabel != null) description.add(debugLabel);
|
if (debugLabel != null) description.add(debugLabel!);
|
||||||
if (initialScrollOffset != 0.0)
|
if (initialScrollOffset != 0.0)
|
||||||
description.add(
|
description.add(
|
||||||
'initialScrollOffset: ${initialScrollOffset.toStringAsFixed(1)}, ');
|
'initialScrollOffset: ${initialScrollOffset.toStringAsFixed(1)}, ');
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ class ShopScrollCoordinator {
|
|||||||
/// 页面主 CustomScrollView 控制
|
/// 页面主 CustomScrollView 控制
|
||||||
final String pageLabel = "page";
|
final String pageLabel = "page";
|
||||||
|
|
||||||
ShopScrollController? _pageScrollController;
|
late ShopScrollController _pageScrollController;
|
||||||
double Function()? pinnedHeaderSliverHeightBuilder;
|
double Function()? pinnedHeaderSliverHeightBuilder;
|
||||||
|
|
||||||
ShopScrollPosition get _pageScrollPosition => _pageScrollController!.position;
|
ShopScrollPosition get _pageScrollPosition => _pageScrollController.position;
|
||||||
|
|
||||||
ScrollDragController? scrollDragController;
|
late ScrollDragController scrollDragController;
|
||||||
|
|
||||||
/// 主页面滑动部件默认位置
|
/// 主页面滑动部件默认位置
|
||||||
double? _pageInitialOffset;
|
late double _pageInitialOffset;
|
||||||
|
|
||||||
/// 获取主页面滑动控制器
|
/// 获取主页面滑动控制器
|
||||||
ShopScrollController pageScrollController([double initialOffset = 0.0]) {
|
ShopScrollController pageScrollController([double initialOffset = 0.0]) {
|
||||||
@@ -28,12 +28,12 @@ class ShopScrollCoordinator {
|
|||||||
_pageInitialOffset = initialOffset;
|
_pageInitialOffset = initialOffset;
|
||||||
_pageScrollController = ShopScrollController(this,
|
_pageScrollController = ShopScrollController(this,
|
||||||
debugLabel: pageLabel, initialScrollOffset: initialOffset);
|
debugLabel: pageLabel, initialScrollOffset: initialOffset);
|
||||||
return _pageScrollController!;
|
return _pageScrollController;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 创建并获取一个子滑动控制器
|
/// 创建并获取一个子滑动控制器
|
||||||
ShopScrollController newChildScrollController([String? debugLabel]) =>
|
ShopScrollController newChildScrollController([String? debugLabel]) =>
|
||||||
ShopScrollController(this, debugLabel: debugLabel ?? '');
|
ShopScrollController(this, debugLabel: debugLabel);
|
||||||
|
|
||||||
/// 子部件滑动数据协调
|
/// 子部件滑动数据协调
|
||||||
/// [userScrollDirection]用户滑动方向
|
/// [userScrollDirection]用户滑动方向
|
||||||
@@ -51,7 +51,7 @@ class ShopScrollCoordinator {
|
|||||||
updateUserScrollDirection(position!, userScrollDirection!);
|
updateUserScrollDirection(position!, userScrollDirection!);
|
||||||
final outerDelta = position.applyClampedDragUpdate(delta);
|
final outerDelta = position.applyClampedDragUpdate(delta);
|
||||||
if (outerDelta != 0.0) {
|
if (outerDelta != 0.0) {
|
||||||
updateUserScrollDirection(_pageScrollPosition, userScrollDirection);
|
updateUserScrollDirection(_pageScrollPosition, userScrollDirection!);
|
||||||
_pageScrollPosition.applyFullDragUpdate(outerDelta);
|
_pageScrollPosition.applyFullDragUpdate(outerDelta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,9 +77,9 @@ class ShopScrollCoordinator {
|
|||||||
/// 当手指离开屏幕
|
/// 当手指离开屏幕
|
||||||
void onPointerUp(PointerUpEvent event) {
|
void onPointerUp(PointerUpEvent event) {
|
||||||
final double _pagePixels = _pageScrollPosition.pixels;
|
final double _pagePixels = _pageScrollPosition.pixels;
|
||||||
if (0.0 < _pagePixels && _pagePixels < _pageInitialOffset!) {
|
if (0.0 < _pagePixels && _pagePixels < _pageInitialOffset) {
|
||||||
if (pageExpand == PageExpandState.NotExpand &&
|
if (pageExpand == PageExpandState.NotExpand &&
|
||||||
_pageInitialOffset! - _pagePixels > _scrollRedundancy) {
|
_pageInitialOffset - _pagePixels > _scrollRedundancy) {
|
||||||
_pageScrollPosition
|
_pageScrollPosition
|
||||||
.animateTo(0.0,
|
.animateTo(0.0,
|
||||||
duration: const Duration(milliseconds: 400), curve: Curves.ease)
|
duration: const Duration(milliseconds: 400), curve: Curves.ease)
|
||||||
@@ -87,7 +87,7 @@ class ShopScrollCoordinator {
|
|||||||
} else {
|
} else {
|
||||||
pageExpand = PageExpandState.Expanding;
|
pageExpand = PageExpandState.Expanding;
|
||||||
_pageScrollPosition
|
_pageScrollPosition
|
||||||
.animateTo(_pageInitialOffset!,
|
.animateTo(_pageInitialOffset,
|
||||||
duration: const Duration(milliseconds: 400), curve: Curves.ease)
|
duration: const Duration(milliseconds: 400), curve: Curves.ease)
|
||||||
.then((value) => pageExpand = PageExpandState.NotExpand);
|
.then((value) => pageExpand = PageExpandState.NotExpand);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user