Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
036bd29855 | ||
|
|
d2f2459a96 | ||
|
|
e90217bdfd | ||
|
|
ea1a9f424b | ||
|
|
18a1d06821 | ||
|
|
a66cdb2e1b | ||
|
|
6c72f8bf22 | ||
|
|
c892d9b995 | ||
|
|
2ae4aedac0 | ||
|
|
db6fbd58ea | ||
|
|
8dc9d55106 | ||
|
|
4908dc9d76 | ||
|
|
5b4526cb97 | ||
|
|
bac42bc653 | ||
|
|
bc971c17d5 | ||
|
|
cb58f649c1 | ||
|
|
f9f77090d9 | ||
|
|
5d459dd08a | ||
|
|
c3e6e02e47 | ||
|
|
e86daf559a | ||
|
|
9c0c1b8982 | ||
|
|
e0024ed123 | ||
|
|
c8ac2c9823 | ||
|
|
282f51c24b | ||
|
|
aa14d0a835 | ||
|
|
50edbf40c4 | ||
|
|
fc877f25bf | ||
|
|
f87b0d2689 | ||
|
|
146cd2a29e | ||
|
|
425ea4c0b7 | ||
|
|
a142a6c318 | ||
|
|
d081cff3e4 | ||
|
|
9876772d06 | ||
|
|
bc4c84a4ae | ||
|
|
a7c0576a03 | ||
|
|
ad69ef7f54 | ||
|
|
de99c09454 | ||
|
|
1776c622ae | ||
|
|
33b49c161a | ||
|
|
c7b230263a | ||
|
|
226ac5920c | ||
|
|
9bd46521aa | ||
|
|
838beaaa3e | ||
|
|
519cab20fe | ||
|
|
8b51a7c18e | ||
|
|
dbeb9883a5 | ||
|
|
5160ab437d | ||
|
|
ab476cab7d | ||
|
|
97735763a1 | ||
|
|
2659c29501 | ||
|
|
22cb74ded4 | ||
|
|
7862e0be09 | ||
|
|
bdd3a53632 | ||
|
|
5e2b8d9e4d | ||
|
|
97bbced02c | ||
|
|
cbb9f60f7f | ||
|
|
35de4095b0 | ||
|
|
4b1aea29c7 | ||
|
|
e6a31a60df | ||
|
|
622dc2f9e8 | ||
|
|
62f87040d6 | ||
|
|
7fccd16750 | ||
|
|
c06a67c4b0 | ||
|
|
1993ff1102 | ||
|
|
72708630ba | ||
|
|
d6b2d308eb | ||
|
|
0ba6ea9c52 | ||
|
|
cf4b07aa69 | ||
|
|
76cc52ad66 | ||
|
|
99b45e4f12 | ||
|
|
c0697c01e3 | ||
|
|
8c04099d97 | ||
|
|
3a636ca894 | ||
|
|
d13b601ae8 | ||
|
|
827c972da0 | ||
|
|
92bfc76e50 | ||
|
|
1dbc3acd80 | ||
|
|
66e9062ba5 | ||
|
|
ac1202c329 | ||
|
|
0c6a103c1c | ||
|
|
51c363540a | ||
|
|
9ebb54ecfd | ||
|
|
2c5ff3579c | ||
|
|
3fefd544fb | ||
|
|
d2174c5b74 | ||
|
|
7871b0cfbb | ||
|
|
c76b388814 | ||
|
|
9b31d83e39 | ||
|
|
1199db760f | ||
|
|
8f60046ec3 | ||
|
|
210ccc97cb | ||
|
|
699fd427b8 | ||
|
|
911f13f464 | ||
|
|
4c8ae7bcec | ||
|
|
51e94029e4 | ||
|
|
0aa5a99a22 | ||
|
|
9eec9ed77a | ||
|
|
983e99a4b6 | ||
|
|
7c2fd090e0 | ||
|
|
a756faca6c | ||
|
|
da549492b0 | ||
|
|
398dc3f8b4 | ||
|
|
576f2b95f4 | ||
|
|
6b397015b1 | ||
|
|
ca6776580f | ||
|
|
c259b0b543 | ||
|
|
eab5d3e230 | ||
|
|
730a96559b | ||
|
|
d68734cdab | ||
|
|
aac9195e05 | ||
|
|
ae11846b63 | ||
|
|
a63334f5a5 | ||
|
|
23059578d2 | ||
|
|
bb92996db5 | ||
|
|
a11ba50b13 | ||
|
|
fe5b6e6efa | ||
|
|
53591abcd0 | ||
|
|
c147645824 | ||
|
|
fcf30ff39c | ||
|
|
dfaff9714a | ||
|
|
04609ace7c | ||
|
|
7e60e5ebc4 | ||
|
|
375b013b1c | ||
|
|
353196aaa3 | ||
|
|
da78d8723d | ||
|
|
15570f117a | ||
|
|
499e42b511 | ||
|
|
5034ac7670 | ||
|
|
030a0e7986 | ||
|
|
420da29658 | ||
|
|
3ce2599754 | ||
|
|
5af70c345a | ||
|
|
3041849344 | ||
|
|
107ae40d2a | ||
|
|
8bcd882aa5 | ||
|
|
9870502901 | ||
|
|
fb0585c9cf | ||
|
|
69eaacd74f | ||
|
|
8f3049f374 | ||
|
|
c4dcb714ab | ||
|
|
805762f761 | ||
|
|
5bdcb989bb | ||
|
|
0ad2cd5e95 | ||
|
|
b2a8bfa59f | ||
|
|
dc73f4e3bb | ||
|
|
0d2680e6c1 | ||
|
|
37802b24bf | ||
|
|
1d8582dfaa | ||
|
|
4c9bb18403 | ||
|
|
f62324084e | ||
|
|
9f4dc93d11 | ||
|
|
794dc87083 | ||
|
|
7285a1cd4e | ||
|
|
81bb1543bb | ||
|
|
f72cb41670 | ||
|
|
c1dd033581 | ||
|
|
230f16a44a | ||
|
|
870a170fad | ||
|
|
a5c84b0297 | ||
|
|
8493c4ef3b | ||
|
|
457d2fa6f2 | ||
|
|
d0c1a5f499 | ||
|
|
1eea9fafe7 | ||
|
|
fa5fd124a4 | ||
|
|
9864c8e102 | ||
|
|
1c6c92170d | ||
|
|
7b2970d5c5 | ||
|
|
69faa7818c | ||
|
|
7250b5f0f9 | ||
|
|
850f8e7c8c | ||
|
|
85ba2a4fec | ||
|
|
4f81bcf2b1 | ||
|
|
fdee89b345 | ||
|
|
6463436a0d | ||
|
|
fcc1995d8b | ||
|
|
6e9a93c920 | ||
|
|
72410b2a87 | ||
|
|
d1abfd47c7 | ||
|
|
963f376159 | ||
|
|
720fd26935 | ||
|
|
9949b61560 | ||
|
|
04a1a4ee82 | ||
|
|
d80fff74ba | ||
|
|
881088a428 | ||
|
|
ffedde0db5 | ||
|
|
bfba2b7c72 | ||
|
|
7a75ee6de8 | ||
|
|
eccd3c6dc1 | ||
|
|
63ace3b574 | ||
|
|
5283ab2549 | ||
|
|
f9d4f982f0 | ||
|
|
9175a7f253 | ||
|
|
1cb4c56261 | ||
|
|
551da77e67 | ||
|
|
33de925f65 | ||
|
|
b2c219d6bd | ||
|
|
8327c1dd13 | ||
|
|
c87798fb16 | ||
|
|
9b99d96a07 | ||
|
|
bc8f3bcab7 | ||
|
|
28ff9a7642 | ||
|
|
7e415f6f4f | ||
|
|
e800f5971f | ||
|
|
ea9ea6e606 | ||
|
|
564c0dbbef | ||
|
|
82fe237c24 | ||
|
|
a3126723d2 | ||
|
|
636b369bd4 | ||
|
|
f94926cff5 | ||
|
|
521ebfc1ab | ||
|
|
c3f5f43744 | ||
|
|
321c62664c | ||
|
|
435fbbbbb1 | ||
|
|
d36d62f6a6 | ||
|
|
ea28420489 | ||
|
|
ee6f0d7e72 | ||
|
|
d6b055dc62 | ||
|
|
fe84244e7d | ||
|
|
53cd2dbba1 | ||
|
|
b7926d64a5 | ||
|
|
698fb12e07 | ||
|
|
5e2fba1746 | ||
|
|
edfef61ee5 | ||
|
|
5a51af4264 | ||
|
|
2abb8c7032 | ||
|
|
524b7f5b35 | ||
|
|
e32fa58979 | ||
|
|
1fc25ec5d1 | ||
|
|
40e23793b4 | ||
|
|
124ba75ab8 | ||
|
|
8e2cd5c838 | ||
|
|
7cc65b7b09 | ||
|
|
cfc41efddc | ||
|
|
0e48c0773e | ||
|
|
290b92c6a7 | ||
|
|
a24f1fa7c0 | ||
|
|
36c71e63b4 | ||
|
|
033ae5987c | ||
|
|
7a7bf0c207 | ||
|
|
96074bc5e8 | ||
|
|
7bb2714941 | ||
|
|
a72adcfc3f | ||
|
|
b8d2617873 | ||
|
|
8013cc18ad | ||
|
|
ac73bf2208 | ||
|
|
02763c3dfb | ||
|
|
427e7a7897 | ||
|
|
90769de3b7 | ||
|
|
ced0fae64a | ||
|
|
8709b64dec | ||
|
|
edcd25fe68 | ||
|
|
9493ad23bb | ||
|
|
ced1ec3d9e | ||
|
|
bed6bbb75b | ||
|
|
e39aa766ac | ||
|
|
d25519bed7 | ||
|
|
55d22a9940 | ||
|
|
0af5de9641 | ||
|
|
3b2bdb8e5a | ||
|
|
f083a161e6 | ||
|
|
1e3e5b64dc | ||
|
|
c4797cd239 | ||
|
|
08440b0160 | ||
|
|
d849834ce6 | ||
|
|
b26ca6cb9f | ||
|
|
3068eb99da | ||
|
|
a26b0071e4 | ||
|
|
0af68f2455 | ||
|
|
d762511412 | ||
|
|
1dbe2cb8e9 | ||
|
|
b2284b3a74 | ||
|
|
1666bc220e | ||
|
|
9429257d62 | ||
|
|
e2162773e2 | ||
|
|
cc26c5472b | ||
|
|
cf93d8d794 | ||
|
|
7b4a792c12 | ||
|
|
6dbeb3e505 | ||
|
|
c4ad5d72d7 | ||
|
|
8c43e9e385 | ||
|
|
f1efbc5be8 | ||
|
|
9a4269b847 | ||
|
|
148fbc3c93 | ||
|
|
03c3964353 | ||
|
|
d50c6e6d9f | ||
|
|
73aef4e44e | ||
|
|
678b976ce1 | ||
|
|
2f1a4c5c69 | ||
|
|
e448003f1b | ||
|
|
634b63e16c | ||
|
|
0d2367431d | ||
|
|
49f3e63ed0 | ||
|
|
f981f88e0d | ||
|
|
959edc0a32 | ||
|
|
99c72e2c32 | ||
|
|
6022d789ed | ||
|
|
842e716ea6 | ||
|
|
12e57de3b3 | ||
|
|
35338cbfc8 | ||
|
|
dc8ca7b743 | ||
|
|
19caaa0a22 | ||
|
|
7ca7d20630 | ||
|
|
7850dfc746 | ||
|
|
2b2b7e9913 | ||
|
|
30a5fa0776 | ||
|
|
ade0cc3566 | ||
|
|
730e38622f | ||
|
|
ec2db6842e | ||
|
|
dfc650456a | ||
|
|
7b927c794e | ||
|
|
061aac6577 | ||
|
|
2b95c79931 | ||
|
|
136ee74618 | ||
|
|
de941c841c | ||
|
|
190e4f9c67 | ||
|
|
d75b69621f | ||
|
|
75438c204d | ||
|
|
cb2fa920ea | ||
|
|
53b77263ca | ||
|
|
501446b3a6 | ||
|
|
75dacf22ab | ||
|
|
d271c43feb | ||
|
|
cabc0e72f5 | ||
|
|
884687d10a | ||
|
|
bbae8cf4ed | ||
|
|
4c2384fea9 | ||
|
|
149b51b2c1 | ||
|
|
16175803ed | ||
|
|
1eaab2a150 | ||
|
|
4d7173d035 | ||
|
|
87628e7d10 | ||
|
|
3a7e0bc4b7 | ||
|
|
5ca5846a26 | ||
|
|
5b7a8bd775 | ||
|
|
99a57ec502 | ||
|
|
71e317f4ab | ||
|
|
b1747afbe8 | ||
|
|
0d977da75b | ||
|
|
bc5feebf39 | ||
|
|
aea130be11 | ||
|
|
a2de5e8eb7 | ||
|
|
e2e809e2d5 | ||
|
|
3fcfd68660 | ||
|
|
0eabb0a763 | ||
|
|
60ec19f08d | ||
|
|
f613033088 | ||
|
|
f4e1a5424e | ||
|
|
fbfb9769a0 | ||
|
|
cbbd4c80e4 | ||
|
|
2fd92cdbea | ||
|
|
e03ea76505 | ||
|
|
03e34b3b57 | ||
|
|
568f051b7a | ||
|
|
f0c53542ef | ||
|
|
c82502559b | ||
|
|
5422581f8b | ||
|
|
a5398daab3 | ||
|
|
8767b5644b | ||
|
|
fecc5b0d27 | ||
|
|
21d457fd98 | ||
|
|
87db548591 | ||
|
|
eefabb6898 | ||
|
|
1c94b727fb | ||
|
|
04fddce1d1 | ||
|
|
689063a694 | ||
|
|
ec163f905d | ||
|
|
4553606ec2 | ||
|
|
e8c1859e70 | ||
|
|
eae1c533ce | ||
|
|
b1c69e22af | ||
|
|
8a96f341c8 | ||
|
|
e44fbdf6f2 | ||
|
|
5f1df401dc | ||
|
|
c5bfd006fa | ||
|
|
df5fbe5b08 | ||
|
|
42ce1d1d84 | ||
|
|
27ab7cebfb | ||
|
|
9b3ab9d5de | ||
|
|
7151bc9d8b | ||
|
|
6fce24d9ec | ||
|
|
da095115d4 | ||
|
|
c68f02449f | ||
|
|
ef7f4ce3b6 | ||
|
|
44f6feb249 | ||
|
|
7d68699523 | ||
|
|
60043d1e41 | ||
|
|
9df36bc358 | ||
|
|
c1cb7d1c11 | ||
|
|
4778ce2c75 | ||
|
|
c4694c6f18 | ||
|
|
9fe62d13cb | ||
|
|
213c86e93c | ||
|
|
27e5286b10 | ||
|
|
5a28845b5e | ||
|
|
f95325d581 | ||
|
|
907562a874 | ||
|
|
b76228905c | ||
|
|
2dd4627bdc | ||
|
|
b5a8656ff0 | ||
|
|
f0db631fa2 | ||
|
|
0466b4b425 | ||
|
|
6d08330388 | ||
|
|
19babb8f4a | ||
|
|
2c30f83ab3 | ||
|
|
a4415c872d | ||
|
|
2c381be5e8 | ||
|
|
cf03178cc5 | ||
|
|
99f64ab870 | ||
|
|
45c3c645ff | ||
|
|
6cc5bfc3be | ||
|
|
5058853af3 | ||
|
|
3e8703b840 | ||
|
|
b870956665 | ||
|
|
b7b1c50427 | ||
|
|
732483465c | ||
|
|
ac706a42a5 | ||
|
|
cc037a2956 | ||
|
|
0cedaab795 | ||
|
|
8a481d5c62 | ||
|
|
e609e3ad8d | ||
|
|
e52d81881c | ||
|
|
10d448c8ba | ||
|
|
e1147cfcba | ||
|
|
1488ee8f85 | ||
|
|
9db6935308 | ||
|
|
d361034226 | ||
|
|
45f5f25640 | ||
|
|
cc4d7c5a9d | ||
|
|
00280ca0da | ||
|
|
84a1f58a0a | ||
|
|
d7eff4ca59 | ||
|
|
94ff9f1177 | ||
|
|
61454e36b1 | ||
|
|
0e5d550b50 | ||
|
|
1853e1845c | ||
|
|
ae49b10407 | ||
|
|
feecc349a0 | ||
|
|
e1b98df509 | ||
|
|
77d5748dbb |
No files matched your search
@@ -45,7 +45,13 @@ app.*.map.json
|
||||
/android/app/release
|
||||
|
||||
# Local demo media and internal planning are absent from the public repo.
|
||||
/assets/
|
||||
# Launcher/splash source icons are required at build time, so keep them tracked.
|
||||
/assets/*
|
||||
!/assets/icon/
|
||||
!/assets/icon/*.png
|
||||
!/assets/fonts/
|
||||
!/assets/fonts/*.ttf
|
||||
!/assets/fonts/OFL-*.txt
|
||||
/server/
|
||||
/docs/
|
||||
/AGENTS.md
|
||||
|
||||
@@ -1,17 +1,155 @@
|
||||
一个使用 Flutter 开发的短剧播放 App 原型,面向海外用户,重点探索沉浸式刷剧、找剧和连续观看的移动端体验
|
||||
# FruitShorts(ReelShort)客户端
|
||||
|
||||
## 主要功能
|
||||
FruitShorts 是面向印尼市场的短剧 Flutter 客户端。当前版本已连接
|
||||
`FruitServer` 的 `/app/**` 接口,支持沉浸播放、找剧、账号、观看记录、收藏、
|
||||
下载授权、评论互动、站内通知和中英印尼三语界面。
|
||||
|
||||
- **沉浸式首页**:竖屏播放,上下滑切换短剧,左右滑切换内容类别;支持拖动进度、横屏全屏观看。
|
||||
- **剧集播放**:从详情页进入后按集连续播放,支持选集和本地续看。
|
||||
- **找剧与个人页**:浏览、搜索和查看剧集详情;在个人页查看观看记录、收藏与喜欢的内容。
|
||||
- **互动与多语言**:本地演示评论、系统分享,以及英文和简体中文界面。
|
||||
- **画中画**:Android 接入系统画中画;iOS 画中画尚未实现。
|
||||
## 技术栈
|
||||
|
||||
## 技术实现
|
||||
- Flutter 3.47.7 / Dart 3.13.5
|
||||
- Provider 状态管理与依赖注入
|
||||
- dio 网络请求
|
||||
- video_player 播放
|
||||
- shared_preferences 与 `SharedPreferencesAsync` 本地配置
|
||||
- flutter_localizations,支持 `en`、`zh`、`id`
|
||||
- Android 系统画中画
|
||||
|
||||
项目使用 Flutter、Provider 和 `video_player`。播放会话统一管理播放器生命周期;观看进度和演示互动数据保存在本机。首页、找剧、我的共用同一个根页面,切换时保留页面状态。
|
||||
## 目录结构
|
||||
|
||||
## 当前说明
|
||||
```text
|
||||
lib/
|
||||
core/
|
||||
config/ 地址、语言和运行时配置
|
||||
data/ models、remote API、repository、controller
|
||||
formatting/ 文案与日期格式化
|
||||
platform/ 触觉等平台能力
|
||||
theme/ 颜色与主题
|
||||
widgets/ 跨页面复用组件
|
||||
l10n/ 三语 ARB 与生成代码
|
||||
pages/ 业务页面
|
||||
test/ 单元、组件、页面和联调测试
|
||||
integration_test/ 设备侧集成测试
|
||||
android/ Android 工程
|
||||
ios/ iOS 工程与 SPM 配置
|
||||
assets/ 图标、图片和本地媒体文件
|
||||
```
|
||||
|
||||
现阶段的剧目与剧集是演示数据,多部剧暂时复用同一段测试视频。
|
||||
## 已接接口
|
||||
|
||||
以下接口均在 `lib/core/data/remote/` 中有实际调用,共 26 个不同路径、
|
||||
31 个 HTTP 方法级调用。
|
||||
|
||||
| 分组 | 契约 | 接口 |
|
||||
| --- | --- | --- |
|
||||
| 账号 | §1.1 | `POST /app/auth/register`、`/login`、`/refresh`、`/logout` |
|
||||
| 内容 | §1.3、§1.4 | `GET /app/home/feed`、`/app/discover/feed`、`/app/categories`、`/app/dramas/{id}`、`/app/episodes/{id}/play` |
|
||||
| 观看记录 | §1.5 | `POST/GET /app/watch/progress`、`GET /app/watch/recent`、`DELETE /app/watch/progress/{dramaId}`、`DELETE /app/watch/progress` |
|
||||
| 收藏 | §1.5 | `POST /app/favorites/toggle`、`GET /app/favorites`、`DELETE /app/favorites/{dramaId}` |
|
||||
| 下载授权 | §1.6 | `GET /app/downloads/policy`、`PUT /app/downloads/settings`、`POST/GET /app/downloads`、`GET /app/downloads/{episodeId}/url`、`POST /app/downloads/{episodeId}/progress`、`DELETE /app/downloads/{episodeId}`、`DELETE /app/downloads` |
|
||||
| 互动 | §1.7 | `GET/POST /app/comments`、`DELETE /app/comments/{id}`、`POST /app/likes/toggle`、`POST /app/reports` |
|
||||
| 公告 | §1.9.2 | `GET /app/notices` |
|
||||
|
||||
客户端没有调用 `/app/config` 或创作者入驻接口。
|
||||
|
||||
## 运行
|
||||
|
||||
### 安装依赖
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
```
|
||||
|
||||
### Android USB
|
||||
|
||||
手机开启 USB 调试并连接电脑后:
|
||||
|
||||
```bash
|
||||
adb devices
|
||||
adb reverse tcp:8081 tcp:8081
|
||||
flutter run -d <device> \
|
||||
--dart-define=API_BASE_URL=http://127.0.0.1:8081
|
||||
```
|
||||
|
||||
`adb reverse` 将手机的 `127.0.0.1:8081` 转发到电脑;USB 断开或重新连接后需要
|
||||
重新执行。
|
||||
|
||||
Android 模拟器访问宿主机时使用:
|
||||
|
||||
```bash
|
||||
flutter run --dart-define=API_BASE_URL=http://10.0.2.2:8081
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
手机与 Mac 需在同一网络,首次启动允许“本地网络”权限:
|
||||
|
||||
```bash
|
||||
flutter run -d <udid> \
|
||||
--dart-define=API_BASE_URL=http://<Mac局域网IP>:8081
|
||||
```
|
||||
|
||||
### Debug 运行时地址
|
||||
|
||||
debug 版本可在「我的 → 设置 → 服务器地址」修改后端地址,保存后重启 App 生效。
|
||||
地址优先级:
|
||||
|
||||
```text
|
||||
本地运行时设置 > --dart-define(API_BASE_URL) > 平台默认地址
|
||||
```
|
||||
|
||||
因此不带 `--dart-define` 构建的 debug APK 也可在安装后改成当前电脑 IP。
|
||||
release 版本不显示入口,也不会读取本地覆盖。
|
||||
|
||||
## 环境注意
|
||||
|
||||
### iOS Swift 版本
|
||||
|
||||
`pubspec.yaml` 将 `shared_preferences_foundation` 固定为 `2.5.6`。该版本兼容
|
||||
Xcode 16.2 / Swift 6.0.3;`2.6.0` 的生成代码使用 Swift 6.1 才支持的 trailing
|
||||
comma。不要手工升级该依赖,`flutter pub get` 后应显示
|
||||
`shared_preferences_foundation 2.5.6 (overridden)`。
|
||||
|
||||
### iOS SPM 包缺失
|
||||
|
||||
如果 Xcode 报 `Missing package product FlutterGeneratedPluginSwiftPackage`:
|
||||
|
||||
```bash
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData/Runner-*
|
||||
flutter clean
|
||||
flutter pub get
|
||||
xcodebuild -resolvePackageDependencies \
|
||||
-project ios/Runner.xcodeproj \
|
||||
-scheme Runner
|
||||
```
|
||||
|
||||
随后重新打开工程构建。`Runner.xcscheme` 的 PreAction 会先执行
|
||||
`flutter pub get`,再执行 Flutter prepare。
|
||||
|
||||
### Android libdartjni
|
||||
|
||||
若启动时报 `libdartjni.so` 加载失败,通常是旧安装中的原生库残留:
|
||||
|
||||
```bash
|
||||
adb uninstall com.stormg.lumadrama
|
||||
flutter run -d <device> \
|
||||
--dart-define=API_BASE_URL=http://127.0.0.1:8081
|
||||
```
|
||||
|
||||
## 门禁
|
||||
|
||||
```bash
|
||||
dart analyze lib test
|
||||
flutter test
|
||||
flutter build apk --debug
|
||||
```
|
||||
|
||||
测试文件按模块放在 `test/` 下,用例名使用
|
||||
`should_<期望>_when_<条件>`。真实后端联调测试在服务未启动时会跳过。
|
||||
|
||||
## 当前边界
|
||||
|
||||
- 下载仅管理服务端授权,不落盘、不续传、不支持离线播放。
|
||||
- 没有独立搜索接口,搜索能力尚未形成完整闭环。
|
||||
- 站内通知没有已读/未读和红点状态。
|
||||
- 支付、金币和会员权益尚未形成客户端闭环。
|
||||
- Android 支持系统画中画;iOS 画中画尚未接入。
|
||||
@@ -6,4 +6,6 @@
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<!-- 开发期后端是明文 HTTP,仅调试构建放开。 -->
|
||||
<application android:usesCleartextTraffic="true"/>
|
||||
</manifest>
|
||||
@@ -1,10 +1,12 @@
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<application
|
||||
android:label="Nontonki"
|
||||
android:label="FruitShorts"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:usesCleartextTraffic="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
@@ -15,7 +17,7 @@
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:windowSoftInputMode="adjustNothing">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
|
||||
@@ -8,6 +8,8 @@ import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.util.Rational
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
@@ -16,6 +18,8 @@ class MainActivity : FlutterActivity() {
|
||||
private val shareRequestCode = 9041
|
||||
private var pendingShare: MethodChannel.Result? = null
|
||||
private var pipChannel: MethodChannel? = null
|
||||
private var keyboardChannel: MethodChannel? = null
|
||||
private var imeInset = 0
|
||||
|
||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||
super.configureFlutterEngine(flutterEngine)
|
||||
@@ -62,6 +66,37 @@ class MainActivity : FlutterActivity() {
|
||||
result.error("share_failed", error.message, null)
|
||||
}
|
||||
}
|
||||
keyboardChannel = MethodChannel(
|
||||
flutterEngine.dartExecutor.binaryMessenger,
|
||||
"com.stormg.lumadrama/keyboard"
|
||||
)
|
||||
keyboardChannel?.setMethodCallHandler { call, result ->
|
||||
if (call.method != "get") {
|
||||
result.notImplemented()
|
||||
return@setMethodCallHandler
|
||||
}
|
||||
val inset = currentImeInset()
|
||||
emitImeInset(inset)
|
||||
result.success(inset)
|
||||
}
|
||||
val decorView = window.decorView
|
||||
ViewCompat.setOnApplyWindowInsetsListener(decorView) { view, insets ->
|
||||
emitImeInset(insets.getInsets(WindowInsetsCompat.Type.ime()).bottom)
|
||||
ViewCompat.onApplyWindowInsets(view, insets)
|
||||
}
|
||||
ViewCompat.requestApplyInsets(decorView)
|
||||
}
|
||||
|
||||
private fun currentImeInset(): Int =
|
||||
ViewCompat.getRootWindowInsets(window.decorView)
|
||||
?.getInsets(WindowInsetsCompat.Type.ime())
|
||||
?.bottom
|
||||
?: 0
|
||||
|
||||
private fun emitImeInset(value: Int) {
|
||||
if (value == imeInset) return
|
||||
imeInset = value
|
||||
keyboardChannel?.invokeMethod("insetsChanged", value)
|
||||
}
|
||||
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
|
||||
@@ -77,4 +112,11 @@ class MainActivity : FlutterActivity() {
|
||||
pendingShare = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(window.decorView, null)
|
||||
keyboardChannel?.setMethodCallHandler(null)
|
||||
keyboardChannel = null
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splash_background" />
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splash_background" />
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 69 B |
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splash_background" />
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@drawable/splash_icon" />
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splash_background" />
|
||||
</layer-list>
|
||||
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 69 B |
@@ -1,11 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@color/splash_background" />
|
||||
<item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@drawable/splash_icon" />
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -1,11 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground>
|
||||
<inset
|
||||
android:drawable="@drawable/ic_launcher_foreground"
|
||||
android:inset="16%" />
|
||||
</foreground>
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 813 B After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 24 KiB |
@@ -6,6 +6,8 @@
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowSplashScreenBackground">@color/splash_background</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">@color/splash_background</item>
|
||||
</style>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">@color/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -1,12 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
@@ -15,6 +18,6 @@
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
<item name="android:windowBackground">@color/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -6,6 +6,8 @@
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:windowSplashScreenBackground">@color/splash_background</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">@color/splash_background</item>
|
||||
</style>
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">@color/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -2,6 +2,5 @@
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<resources>
|
||||
<color name="splash_background">#FF000000</color>
|
||||
<color name="ic_launcher_background">#D74A7D</color>
|
||||
</resources>
|
||||
<color name="splash_background">#1F1B16</color>
|
||||
</resources>
|
||||
@@ -1,12 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Author: fruit.com.cn -->
|
||||
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
@@ -15,6 +18,6 @@
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
<item name="android:windowBackground">@color/splash_background</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -6,4 +6,6 @@
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<!-- 开发期后端是明文 HTTP,仅调试构建放开。 -->
|
||||
<application android:usesCleartextTraffic="true"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2021 The Outfit Project Authors (https://github.com/Outfitio/Outfit-Fonts)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Plus Jakarta Sans Project Authors (https://github.com/tokotype/PlusJakartaSans)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 928 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1004 B |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,99 @@
|
||||
# 客户端文件说明
|
||||
|
||||
## 目录树
|
||||
|
||||
```text
|
||||
.
|
||||
├── android/ Android 工程与 Gradle 配置
|
||||
├── assets/
|
||||
│ ├── icon/ 启动图标
|
||||
│ ├── images/ 本地图片
|
||||
│ └── media/ 本地视频文件(当前未在 pubspec 声明)
|
||||
├── integration_test/ 设备侧集成测试
|
||||
├── ios/
|
||||
│ ├── Flutter/ Flutter 生成配置与 SPM 临时包
|
||||
│ ├── Runner/ iOS Runner
|
||||
│ ├── Runner.xcodeproj/ Xcode 工程与共享 Scheme
|
||||
│ └── RunnerTests/ iOS 原生测试
|
||||
├── lib/
|
||||
│ ├── core/
|
||||
│ │ ├── config/ 地址、语言、运行时服务器设置
|
||||
│ │ ├── data/ models、remote、repositories、services
|
||||
│ │ ├── formatting/ 多语言文案、日期和错误文本
|
||||
│ │ ├── platform/ 平台能力封装
|
||||
│ │ ├── theme/ 颜色与 ThemeData
|
||||
│ │ └── widgets/ 通用组件
|
||||
│ ├── l10n/ ARB 与本地化生成代码
|
||||
│ └── pages/ 业务页面
|
||||
├── test/ 单元和 Widget 测试
|
||||
├── docs/ 客户端任务与文件说明
|
||||
├── pubspec.yaml 依赖、资源和 Flutter 配置
|
||||
└── README.md 运行、接口与环境说明
|
||||
```
|
||||
|
||||
## 关键文件
|
||||
|
||||
| 路径 | 职责 |
|
||||
| --- | --- |
|
||||
| `lib/main.dart` | 初始化 Flutter、屏幕方向、debug 服务器覆盖并启动 App |
|
||||
| `lib/app.dart` | Provider、repository、controller、ApiClient 和主题装配 |
|
||||
| `lib/core/config/app_config.dart` | 地址优先级、超时、媒体 URL 和平台默认地址 |
|
||||
| `lib/core/config/server_endpoint.dart` | debug 运行时地址规范化、读取、保存和清除 |
|
||||
| `lib/core/config/locale_controller.dart` | 语言选择与系统语言回退 |
|
||||
| `lib/core/data/models/` | 账号、剧目、评论、观看、下载、公告等数据结构 |
|
||||
| `lib/core/data/remote/` | `/app/**` 接口调用;`api_client.dart` 统一鉴权和错误映射 |
|
||||
| `lib/core/data/repositories/` | HTTP 与内存实现的 repository 边界 |
|
||||
| `lib/core/data/services/` | 页面 controller、播放会话、分享、画中画等业务服务 |
|
||||
| `lib/core/formatting/` | 本地化内容、日期与错误文本 |
|
||||
| `lib/core/platform/haptics.dart` | 可注入的触觉反馈封装 |
|
||||
| `lib/core/theme/app_colors.dart` | 克莱因蓝和界面颜色 token |
|
||||
| `lib/core/theme/app_theme.dart` | light/dark ColorScheme 与组件主题 |
|
||||
| `lib/core/widgets/empty_state.dart` | 统一空列表占位 |
|
||||
| `lib/core/widgets/remote_image.dart` | 后端相对图片地址与失败占位 |
|
||||
| `lib/core/widgets/auth_gate.dart` | 未登录操作拦截 |
|
||||
| `lib/core/widgets/download_action.dart` | 下载授权操作 |
|
||||
| `lib/pages/home/` | 根页面、四个底部 tab 和抽屉 |
|
||||
| `lib/pages/player/` | 竖屏播放、选集、进度和播放器交互 |
|
||||
| `lib/pages/discover/` | 首页/发现信息流、轮播、分类与三列剧目网格 |
|
||||
| `lib/pages/drama_detail/` | 剧目详情与剧集入口 |
|
||||
| `lib/pages/auth/` | 登录/注册页面与表单逻辑 |
|
||||
| `lib/pages/mine/` | 我的页、片单、设置、语言与 debug 地址入口 |
|
||||
| `lib/pages/favorites/` | 收藏列表 |
|
||||
| `lib/pages/watch_records/` | 独立观看记录页 |
|
||||
| `lib/pages/downloads/` | 下载授权与策略页面 |
|
||||
| `lib/pages/notices/` | 站内通知分页和详情 |
|
||||
| `lib/pages/interaction/` | 举报弹窗 |
|
||||
| `lib/l10n/*.arb` | en/zh/id 源文案,修改后执行 `flutter gen-l10n` |
|
||||
| `ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme` | iOS SPM 预构建脚本 |
|
||||
|
||||
## 测试结构
|
||||
|
||||
| 目录 | 覆盖范围 |
|
||||
| --- | --- |
|
||||
| `test/auth/` | 登录 controller、表单、视觉与交互 |
|
||||
| `test/catalog/`、`test/category/` | 首页数据、分类和模型解析 |
|
||||
| `test/comment/`、`test/interaction/` | 评论、点赞、举报和弹窗 |
|
||||
| `test/config/` | 三语、系统语言和运行时服务器地址 |
|
||||
| `test/core/` | ApiClient、ID 解析、触觉、分享和画中画 |
|
||||
| `test/discover/`、`test/home/` | 首页、轮播、网格和导航 |
|
||||
| `test/download/`、`test/library/`、`test/watch/` | 下载、收藏、观看记录 |
|
||||
| `test/drama_detail/`、`test/player/`、`test/playback/` | 详情、播放器与播放队列 |
|
||||
| `test/notice/` | 通知分页、空态、详情与入口 |
|
||||
| `test/empty_state/`、`test/theme/` | 空态组件与主题 token |
|
||||
| `test/integration/` | 依赖本机后端的联调测试,服务未启动时跳过 |
|
||||
| `integration_test/app_backend_test.dart` | 设备侧后端连通性测试 |
|
||||
| `test/support/` | fake repository、HTTP adapter、播放器和测试数据 |
|
||||
|
||||
## 生成物
|
||||
|
||||
以下内容由工具生成,不要手工修改:
|
||||
|
||||
- `lib/l10n/app_localizations*.dart`
|
||||
- `*.g.dart`
|
||||
- `.dart_tool/`
|
||||
- `build/`
|
||||
- `ios/Flutter/ephemeral/`
|
||||
- `ios/Runner/GeneratedPluginRegistrant.h`
|
||||
- `ios/Runner/GeneratedPluginRegistrant.m`
|
||||
|
||||
`pubspec.lock` 由 Dart 包管理工具维护,应提交但不手工编辑。
|
||||
@@ -0,0 +1,38 @@
|
||||
# 客户端任务清单
|
||||
|
||||
状态按当前 `develop` 中已合入的功能整理。契约章节以
|
||||
`FruitServer/docs/api-phase1.md` 为准;任务过程记录见
|
||||
`FruitServer/docs/plans/PROGRESS.md`。
|
||||
|
||||
## K1-K13
|
||||
|
||||
| 批次 | 范围 | 状态 | 关键提交或契约章节 | 备注 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| K1 | 详情、播放票据、观看进度、续看、收藏 | 已完成并合入 | §1.3-§1.5 | 已有三态和基础页面 |
|
||||
| K2 | 分类、观看记录、收藏列表、下载授权管理 | 已完成并合入 | §1.2、§1.5、§1.6 | 下载只管理授权,不落盘 |
|
||||
| K3 | 评论、回复、点赞、举报、分享 | 已完成并合入 | §1.7 | 分享使用系统分享面板 |
|
||||
| K4 | 账号剩余能力 | 未开始 | §1.1 | Google 登录所需凭据和契约范围需核对 |
|
||||
| K5 | 克莱因蓝主题、印尼语适配 | 已完成并合入 | 无接口变更 | 三语为 en/zh/id |
|
||||
| K6 | 登录页、底部导航、触觉反馈 | 已完成并合入 | 无接口变更 | 触觉通过 `Haptics` 封装 |
|
||||
| K7 | 首页轮播、站内通知 | 已完成并合入 | §1.3、§1.9.2 | 通知无已读态 |
|
||||
| K8 | 登录页视觉重设计 | 已完成并合入 | 无接口变更 | 保留原有登录逻辑和校验 |
|
||||
| K9 | 首页全部剧目双列网格 | 已完成并合入 | 无接口变更 | 数据源为 feed 分类结果 |
|
||||
| K10 | 统一空列表占位 | 已完成并合入 | 无接口变更 | 评论弹窗使用 compact 变体 |
|
||||
| K11 | 首页三列、分类首位“全部” | 已完成并合入 | 无接口变更 | 网格比例保持 2:3 |
|
||||
| K12 | 首页去标题、空态视觉重做 | 已完成并合入 | 无接口变更 | 双层同心圆空态 |
|
||||
| K13 | debug 运行时服务器地址 | 已完成并合入 | 无接口变更 | 保存后重启生效,release 不开放 |
|
||||
|
||||
## 待办
|
||||
|
||||
| 事项 | 状态 | 依赖或说明 |
|
||||
| --- | --- | --- |
|
||||
| K4 账号剩余能力 | 待办 | Google 登录需要客户端凭据、平台配置和后端契约,范围需核对 |
|
||||
| B1 支付与金币 | 待办 | 客户端尚未接入 §1.8 的支付/权益闭环,商品、渠道和验证方式需核对 |
|
||||
| 搜索 | 待办 | 当前没有独立搜索接口,接口契约和数据范围需核对 |
|
||||
| 下载落盘 | 待办 | 需要新增文件下载、进度持久化、续传、离线播放和本地清理设计 |
|
||||
|
||||
## 维护规则
|
||||
|
||||
- 新批次完成后更新本表,不写未经确认的提交号。
|
||||
- 功能状态以当前 `develop` 代码和自动化测试为准。
|
||||
- “需核对”表示产品范围、接口或外部凭据尚未确认,不能按已完成处理。
|
||||
@@ -0,0 +1,74 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:fruitshorts/app.dart';
|
||||
import 'package:fruitshorts/core/config/app_config.dart';
|
||||
import 'package:fruitshorts/core/data/remote/api_client.dart';
|
||||
import 'package:fruitshorts/core/data/remote/catalog_api.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
|
||||
/// 设备侧集成测试:**在手机进程里**真实请求开发机上的 app-api。
|
||||
///
|
||||
/// 跑法(红线第 10 条要求的"设备侧取证"):
|
||||
/// ```
|
||||
/// IP=$(ipconfig getifaddr en0)
|
||||
/// flutter test integration_test -d <device-id> --dart-define=API_BASE_URL=http://$IP:8081
|
||||
/// ```
|
||||
/// 断言失败时会把实际使用的地址一起打出来,便于区分"地址不对"还是"设备连不上"。
|
||||
void main() {
|
||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
final baseUrl = AppConfig.apiBaseUrl;
|
||||
|
||||
testWidgets('should_fetch_home_feed_and_drama_detail_when_device_reaches_backend', (
|
||||
tester,
|
||||
) async {
|
||||
debugPrint('[device] API_BASE_URL=$baseUrl');
|
||||
final client = ApiClient(baseUrl: baseUrl);
|
||||
addTearDown(client.close);
|
||||
final api = CatalogApi(client);
|
||||
|
||||
final feed = await api.homeFeed();
|
||||
expect(
|
||||
feed.dramas,
|
||||
isNotEmpty,
|
||||
reason: '设备侧拿不到首页列表(API_BASE_URL=$baseUrl)',
|
||||
);
|
||||
debugPrint('[device] 首页分区=${feed.sections.length} 剧目=${feed.dramas.length}');
|
||||
|
||||
final card = feed.dramas.first;
|
||||
expect(card.id, isNotEmpty, reason: '设备侧首页卡片 id 为空');
|
||||
|
||||
final detail = await api.dramaDetail(card.id);
|
||||
expect(detail.id, card.id, reason: '详情返回的 id 与卡片不一致');
|
||||
expect(
|
||||
detail.episodes,
|
||||
isNotEmpty,
|
||||
reason: '设备侧拿到的详情没有剧集(dramaId=${card.id})',
|
||||
);
|
||||
debugPrint('[device] 详情 id=${detail.id} 剧集=${detail.episodes.length}');
|
||||
});
|
||||
|
||||
testWidgets('should_render_home_drama_list_when_app_boots_on_device', (
|
||||
tester,
|
||||
) async {
|
||||
// 用真 App(真网络、真目录控制器):首页底部标签栏出现即代表"剧目列表加载成功",
|
||||
// 也就是用户在真机上遇到的那个「剧目列表加载失败」已经消失。
|
||||
await tester.pumpWidget(const LumaDramaApp());
|
||||
|
||||
var loaded = false;
|
||||
for (var attempt = 0; attempt < 60 && !loaded; attempt++) {
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
loaded = find.byKey(const Key('home-tabs-bar')).evaluate().isNotEmpty;
|
||||
}
|
||||
|
||||
expect(
|
||||
loaded,
|
||||
isTrue,
|
||||
reason: '首页 30 秒内没渲染出剧目列表(API_BASE_URL=$baseUrl)',
|
||||
);
|
||||
debugPrint('[device] 首页剧目列表已渲染:API_BASE_URL=$baseUrl');
|
||||
});
|
||||
}
|
||||
@@ -360,7 +360,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -487,7 +487,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -538,7 +538,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
||||
@@ -6,11 +6,27 @@
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<PreActions>
|
||||
<ExecutionAction
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Bootstrap Flutter SPM Package"
|
||||
scriptText = "#!/bin/sh set -e FLUTTER="" if [ -n "${FLUTTER_ROOT:-}" ] && [ -x "$FLUTTER_ROOT/bin/flutter" ]; then FLUTTER="$FLUTTER_ROOT/bin/flutter" elif FLUTTER="$(command -v flutter)"; then : elif [ -x "$HOME/flutter/bin/flutter" ]; then FLUTTER="$HOME/flutter/bin/flutter" elif [ -x "/opt/homebrew/bin/flutter" ]; then FLUTTER="/opt/homebrew/bin/flutter" fi if [ -z "$FLUTTER" ]; then echo "error: Flutter executable not found. Set FLUTTER_ROOT or add Flutter to PATH." >&2 exit 1 fi if [ -z "${SRCROOT:-}" ]; then echo "error: SRCROOT is not set; cannot locate the Flutter project." >&2 exit 1 fi cd "$SRCROOT/.." "$FLUTTER" pub get ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</EnvironmentBuildable>
|
||||
</ActionContent>
|
||||
</ExecutionAction>
|
||||
<ExecutionAction
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Prepare Flutter Framework Script"
|
||||
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||
scriptText = "#!/bin/sh set -e FLUTTER="" if [ -n "${FLUTTER_ROOT:-}" ] && [ -x "$FLUTTER_ROOT/bin/flutter" ]; then FLUTTER="$FLUTTER_ROOT/bin/flutter" elif FLUTTER="$(command -v flutter)"; then : elif [ -x "$HOME/flutter/bin/flutter" ]; then FLUTTER="$HOME/flutter/bin/flutter" elif [ -x "/opt/homebrew/bin/flutter" ]; then FLUTTER="/opt/homebrew/bin/flutter" fi if [ -z "$FLUTTER" ]; then echo "error: Flutter executable not found. Set FLUTTER_ROOT or add Flutter to PATH." >&2 exit 1 fi FLUTTER_ROOT="$(cd "$(dirname "$FLUTTER")/.." && pwd -P)" if [ -z "${SRCROOT:-}" ]; then echo "error: SRCROOT is not set; cannot locate the Flutter project." >&2 exit 1 fi cd "$SRCROOT" "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
|
||||
@@ -10,7 +10,7 @@ final class RunnerFlutterViewController: FlutterViewController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.backgroundColor = .black
|
||||
view.backgroundColor = UIColor(red: 16.0 / 255.0, green: 12.0 / 255.0, blue: 10.0 / 255.0, alpha: 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 340 B After Width: | Height: | Size: 866 B |
|
Before Width: | Height: | Size: 644 B After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1001 B After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 644 B After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 822 B After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "background.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 69 B |
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||