mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-05-17 21:05:56 +08:00
merge
This commit is contained in:
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: Something isn't working as expected
|
||||
---
|
||||
|
||||
## Bug Report
|
||||
|
||||
**仅限中文与英文**, 其他语言的提交将直接被关闭
|
||||
|
||||
请先确认查找了已有的 issue [GitHub issues](https://github.com/apache/incubator-shardingsphere-example/issues).
|
||||
|
||||
为了更好的收录您反馈或者提交的相关pr. 请您关注您提交的问题, 我们可能需要更多的详细信息, 我们会在issue下先您收集相关信息,
|
||||
如果长时间未得到您的回复, 如果我们无法在某些环境上重现该问题, 并且您**超过7天未回复**, 我们可能会关 **闭掉issue**, 谢谢
|
||||
|
||||
|
||||
### 您当前的flutter doctor信息
|
||||
|
||||
### 预期的表现
|
||||
|
||||
### 实际的表现
|
||||
|
||||
### 预期的分析 (给出您能想到, 任何您能想到的)
|
||||
|
||||
### 重现的方式, 例如从 A界面 点击 b, 跳转到B页面, 界面出现溢出乱码等.
|
||||
|
||||
### 用于重现此问题或者可能解决以上问题的示例代码(例如github 链接代码)
|
18
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
18
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
name: "\U0001F680 Feature Request"
|
||||
about: I have a suggestion
|
||||
---
|
||||
|
||||
## Feature Request
|
||||
|
||||
**仅限中文与英文**, 其他语言的提交将直接被关闭
|
||||
|
||||
请先确认查找了已有的 issue [GitHub issues](https://github.com/apache/incubator-shardingsphere-example/issues).
|
||||
|
||||
为了更好的收录您反馈或者提交的相关pr. 请您关注您提交的问题, 我们可能需要更多的详细信息, 我们会在issue下先您收集相关信息,
|
||||
如果长时间未得到您的回复, 如果我们无法在某些环境上重现该问题, 并且您**超过7天未回复**, 我们可能会关 **闭掉issue**, 谢谢
|
||||
|
||||
|
||||
### 您的功能需求是否与哪些问题有关?
|
||||
|
||||
### 描述您想要的功能.
|
14
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: "\U0001F914 Question"
|
||||
about: Usage question that isn't answered in docs or discussion
|
||||
---
|
||||
|
||||
## Question
|
||||
|
||||
**仅限中文与英文**, 其他语言的提交将直接被关闭
|
||||
|
||||
请先确认查找了已有的 issue [GitHub issues](https://github.com/apache/incubator-shardingsphere-example/issues).
|
||||
|
||||
为了更好的收录您反馈或者提交的相关pr. 请您关注您提交的问题, 我们可能需要更多的详细信息, 我们会在issue下先您收集相关信息,
|
||||
如果长时间未得到您的回复, 如果我们无法在某些环境上重现该问题, 并且您**超过7天未回复**, 我们可能会关 **闭掉issue**, 谢谢
|
||||
|
20
.github/ISSUE_TEMPLATE/widget about.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/widget about.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: "📄 Widget About"
|
||||
about: something about widget
|
||||
---
|
||||
|
||||
## Widget About
|
||||
|
||||
**仅限中文与英文**, 其他语言的提交将直接被关闭
|
||||
|
||||
请先确认查找了已有的 issue [GitHub issues](https://github.com/apache/incubator-shardingsphere-example/issues).
|
||||
|
||||
为了更好的收录您反馈或者提交的相关pr. 请您关注您提交的问题, 我们可能需要更多的详细信息, 我们会在issue下先您收集相关信息,
|
||||
如果长时间未得到您的回复, 如果我们无法在某些环境上重现该问题, 并且您**超过7天未回复**, 我们可能会关 **闭掉issue**, 谢谢
|
||||
|
||||
|
||||
## 描述widget 类型
|
||||
|
||||
## widget 简要描述
|
||||
|
||||
##
|
@ -85,4 +85,4 @@ The advantages of Flutter mainly include:
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Powered by [Alibaba Auction Front-end Team](https://github.com/alibaba-paimai-frontend)<img src="https://img.alicdn.com/tfs/TB1foEhAMHqK1RjSZJnXXbNLpXa-166-166.png" width= 20 height=20>
|
||||
Powered by Alibaba Auction Front-end Team<img src="https://img.alicdn.com/tfs/TB1foEhAMHqK1RjSZJnXXbNLpXa-166-166.png" width= 20 height=20>
|
||||
|
@ -1,6 +1,8 @@
|
||||
Language: [English](https://github.com/alibaba/flutter-go/blob/master/README-en.md) | [中文简体](https://github.com/alibaba/flutter-go/blob/master/README.md)
|
||||
## Flutter Go
|
||||
|
||||
# test
|
||||
|
||||

|
||||
|
||||
> 帮助开发者快速上手 Flutter **Flutter Go 1.0 Android版已正式发布**
|
||||
@ -126,3 +128,4 @@ flutter优点主要包括:
|
||||
- 大家的互相信任,尊重与支持,才是开源社区前进的动力和来源.
|
||||
|
||||
Powered by 阿里拍卖前端团队<img src="https://img.alicdn.com/tfs/TB1foEhAMHqK1RjSZJnXXbNLpXa-166-166.png" width=20 height=20>
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 360 KiB |
Binary file not shown.
Before Width: | Height: | Size: 673 KiB |
Binary file not shown.
Before Width: | Height: | Size: 215 KiB |
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 192 KiB |
67
docs/contribute.md
Normal file
67
docs/contribute.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Flutter Go PR 规范说明
|
||||
|
||||
# 贡献指南
|
||||
|
||||
此项目遵循[贡献者行为准则](https://github.com/spring-projects/spring-framework/blob/master/CODE_OF_CONDUCT.adoc)。参与此项目即表示您同意遵守其条款.
|
||||
|
||||
|
||||
如何提PR请先阅读以下文档
|
||||
- [如何提PR](https://github.com/alibaba/flutter-go/blob/master/docs/push-pr.md)
|
||||
- [如何使用go-cli](https://github.com/alibaba/flutter-go/blob/master/docs/go-cli.md);
|
||||
- [dart 代码规范](https://github.com/alibaba/flutter-go/blob/beta/Flutter_Go%20%E4%BB%A3%E7%A0%81%E5%BC%80%E5%8F%91%E8%A7%84%E8%8C%83.md)
|
||||
|
||||
|
||||
# Issue
|
||||
PR的第一步就是提交issue,即提交你发现的BUG 或者 想加入的功能, 选择你issue在类型
|
||||
|
||||

|
||||
|
||||
|
||||
您的 Pull Request 可能包含以下几种
|
||||
|
||||
- 当前项目逻辑代码的问题修复或者优化
|
||||
- widget 示例的完善
|
||||
- widget 文档的完善与更新
|
||||
|
||||
|
||||
# 文档与DEMO的完善
|
||||
一个widget的demo实例与文档说明, 由以下目录构成, 我们以**/lib/widgets/components/Tab/Tab**组件举例, 在此文件目录下构建您的demo运行即可看到效果
|
||||
|
||||
- index.dart
|
||||
- demo.dart
|
||||
|
||||
|
||||
|
||||
# 撰写 Pull Request
|
||||
|
||||
为了更好的将 *flutter* 的各种使用方法分享给大家, 我们欢迎第三方提交个人Pull Request(简称为PR)到开源仓库中. 提交的PR需要满足以下规则:
|
||||
|
||||
- PR 的提交名称, 请使用有意义可以理解的词汇, 否则我们请直接关闭它.
|
||||
- 例如: 增加了XX功能, 优化..., 修复在 XX 状态下对 XX 的异常处理
|
||||
- PR 只能被提交合并到 *develop* 分支, 被提交到master的 PR, 我们将会直接关闭.
|
||||
- PR 的描述区,需要描述本次改动的主要内容, 以及为什么要如此改动.
|
||||
- 避免超大的 PR 提交
|
||||
- 当 PR 的改动 **change** 超过1000行(暂定为1000)时, 请尽量拆分后进行提交.
|
||||
- 规范化的commit信息
|
||||
- commit规范参照[develop规范](https://github.com/alibbaba/flutter-go/blob/master/develop.md#commit-%E6%8F%90%E4%BA%A4%E8%A7%84%E8%8C%83)
|
||||
- commit列表, 请在提交PR之前做好整理, 避免出现一个功能点的多条commit.[如何整理commit](https://help.github.com/en/articles/using-git-rebase-on-the-command-line)
|
||||
|
||||
# 如何提交PR
|
||||
* fork项目到自己仓库
|
||||
* git clone (您的仓库地址)到本地
|
||||
* 建立上游源
|
||||
* git remote add upStream git@github.com:alibaba/flutter-go.git
|
||||
* 创建开发分支(非必须)
|
||||
* git checkout -b develop
|
||||
* 修改提交代码
|
||||
* git status
|
||||
* git add .
|
||||
* git commit -m 'feat: message'
|
||||
* git push origin develop
|
||||
* 同步代码
|
||||
* git fetch upstream
|
||||
* git merge upstream/develop
|
||||
* git push origin develop
|
||||
* 提交PR
|
||||
* 到自己github仓库对应fork的项目下new pull request
|
||||
|
109
docs/go-cli.md
Normal file
109
docs/go-cli.md
Normal file
@ -0,0 +1,109 @@
|
||||
# GoCli 使用方式
|
||||
|
||||
## 安装
|
||||
|
||||
获取最新flutterGo代码分之后. 在源文件下会有 **go-cli** 的文件.
|
||||
|
||||
首先进入该文件夹并安装go-cli所需要的依赖
|
||||
|
||||
```
|
||||
cd go-cli
|
||||
pub get
|
||||
```
|
||||
|
||||
然后使用pub global命令将文件包注册到全局
|
||||
|
||||
```
|
||||
pub global activate --source path /{your flutter go absolute path}/fluttergo/go-cli
|
||||
|
||||
```
|
||||
|
||||
使用pub global list命令查看全局包列表 如果看到有 **goCli 1.0.0**则证明安装成功
|
||||
|
||||
```
|
||||
goCli 1.0.0 at path "/{youpath}/flutter-go/go-cli"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 使用方式
|
||||
|
||||
现在支持以下几种命令
|
||||
|
||||
- createDemo 新增flutter go demo.
|
||||
- createPage 新增flutter go page.
|
||||
- watch 动态生成文档与demo相关
|
||||
|
||||
### createDemo
|
||||
|
||||
动态生成widget demo, 可以创建demo.以便详情页中使用
|
||||
|
||||
|
||||
在flutter go 根文件下通过命令行输入以上命令可以进行以下操作
|
||||
|
||||
[✓] 请输入新增加的demo名称? demoName
|
||||
|
||||
[✓] 请输入您的姓名(使用英文) yourName
|
||||
|
||||
[✓] 请输入您的github的email地址 yourEmail
|
||||
|
||||
[✓] 请输入您demo的描述 这是一个测试的标准demo
|
||||
|
||||
|
||||
在完成以上操作后, 可以得到这样的输出:
|
||||
|
||||
|
||||
```
|
||||
------------------
|
||||
您新增的组件信息如下
|
||||
==================
|
||||
{
|
||||
name : demoName
|
||||
author : yourName
|
||||
email : yourEmail
|
||||
desc : 这是一个测试的标准demo
|
||||
}
|
||||
==================
|
||||
[✓] Is this the config you want ? (Y/n) y
|
||||
{
|
||||
新建的demo文件位于 : /flutter go/lib/page_demo_package/demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
demoId为 : 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
markdown中调用方式 : [demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
}
|
||||
|
||||
```
|
||||
您可以在任意详情页中, 通过以下方式调用
|
||||
|
||||
```
|
||||
[demo: 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
```
|
||||
|
||||
|
||||
|
||||
### createPage
|
||||
|
||||
使用方式同上. 通过该命令可以创建标准的详情页.您可以通过修改index.md进行动态的更新您所创建的详情页.
|
||||
|
||||
目录结构为
|
||||
|
||||
```
|
||||
standard_pages/
|
||||
├── index.dart (不可人为修改)
|
||||
└── standard_sanfan_ee4feb8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
├── .page.json (不可人为修改)
|
||||
├── index.dart (不可人为修改)
|
||||
└── index.md (可修改)
|
||||
```
|
||||
|
||||
### watch
|
||||
|
||||
监听并编译standard_pages与page_demo_package下的的文件改动. 动态处理demo目录与文件markdown转化等.
|
||||
|
||||
## 注意
|
||||
|
||||
- 在修改page_demo_package或者standard_pages目录下的文件操作时. 建议在flutterGo目录执行goCLi watch 开启文件动态编译
|
||||
- name, author 字段必须使用英文开头, 不允许使用特殊符号. 正常的示范 name ='name_test' author = 'abcdefg';
|
||||
- 暂时阶段demo与page,一经过创建不允许修改名称作者等信息. 凡是被收录进主分支的不允许被删除
|
||||
|
||||
|
BIN
docs/jiegou.png
BIN
docs/jiegou.png
Binary file not shown.
Before Width: | Height: | Size: 106 KiB |
35
docs/push-pr.md
Normal file
35
docs/push-pr.md
Normal file
@ -0,0 +1,35 @@
|
||||
# 如何为一个项目提PR
|
||||
|
||||
|
||||
## PR 的含义
|
||||
|
||||
PR的全称是 **pull request**, 可以理解成. 让开源项目拉取合并他方的请求.
|
||||
|
||||
|
||||
## pull request
|
||||
|
||||
1. 将 开源flutter go项目 fork到我们自己的仓库.
|
||||
|
||||

|
||||
|
||||
2. 将Fork的仓库 clone 到本地,进行本地修改.
|
||||
|
||||
3. 将改动push到自己的仓库中
|
||||
|
||||
|
||||
```
|
||||
git add {some change file}
|
||||
git commit ...
|
||||
git push origin {your branch}
|
||||
|
||||
```
|
||||
|
||||
|
||||
4. 登陆github, 从**自己的仓库**向**开源项目仓库** 发起 **pull request** (合并申请);
|
||||
|
||||
过程参考:
|
||||
|
||||

|
||||
|
||||
|
||||
5. 开源项目维护者会review您的 **pull request**,展开讨论或者修改, 一旦通过审核,开源项目维护者合并该分支到正式仓库然后并关闭合并申请。
|
109
go-cli/Readme.md
Normal file
109
go-cli/Readme.md
Normal file
@ -0,0 +1,109 @@
|
||||
# GoCli 使用方式
|
||||
|
||||
## 安装
|
||||
|
||||
获取最新flutterGo代码分之后. 在源文件下会有 **go-cli** 的文件.
|
||||
|
||||
首先进入该文件夹并安装go-cli所需要的依赖
|
||||
|
||||
```
|
||||
cd go-cli
|
||||
pub get
|
||||
```
|
||||
|
||||
然后使用pub global命令将文件包注册到全局
|
||||
|
||||
```
|
||||
pub global activate --source path /{your flutter go absolute path}/fluttergo/go-cli
|
||||
|
||||
```
|
||||
|
||||
使用pub global list命令查看全局包列表 如果看到有 **goCli 1.0.0**则证明安装成功
|
||||
|
||||
```
|
||||
goCli 1.0.0 at path "/{youpath}/flutter-go/go-cli"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 使用方式
|
||||
|
||||
现在支持以下几种命令
|
||||
|
||||
- createDemo 新增flutter go demo.
|
||||
- createPage 新增flutter go page.
|
||||
- watch 动态生成文档与demo相关
|
||||
|
||||
### createDemo
|
||||
|
||||
动态生成widget demo, 可以创建demo.以便详情页中使用
|
||||
|
||||
|
||||
在flutter go 根文件下通过命令行输入以上命令可以进行以下操作
|
||||
|
||||
[✓] 请输入新增加的demo名称? demoName
|
||||
|
||||
[✓] 请输入您的姓名(使用英文) yourName
|
||||
|
||||
[✓] 请输入您的github的email地址 yourEmail
|
||||
|
||||
[✓] 请输入您demo的描述 这是一个测试的标准demo
|
||||
|
||||
|
||||
在完成以上操作后, 可以得到这样的输出:
|
||||
|
||||
|
||||
```
|
||||
------------------
|
||||
您新增的组件信息如下
|
||||
==================
|
||||
{
|
||||
name : demoName
|
||||
author : yourName
|
||||
email : yourEmail
|
||||
desc : 这是一个测试的标准demo
|
||||
}
|
||||
==================
|
||||
[✓] Is this the config you want ? (Y/n) y
|
||||
{
|
||||
新建的demo文件位于 : /flutter go/lib/page_demo_package/demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
demoId为 : 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
markdown中调用方式 : [demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
}
|
||||
|
||||
```
|
||||
您可以在任意详情页中, 通过以下方式调用
|
||||
|
||||
```
|
||||
[demo: 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
```
|
||||
|
||||
|
||||
|
||||
### createPage
|
||||
|
||||
使用方式同上. 通过该命令可以创建标准的详情页.您可以通过修改index.md进行动态的更新您所创建的详情页.
|
||||
|
||||
目录结构为
|
||||
|
||||
```
|
||||
standard_pages/
|
||||
├── index.dart (不可人为修改)
|
||||
└── standard_sanfan_ee4feb8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
├── .page.json (不可人为修改)
|
||||
├── index.dart (不可人为修改)
|
||||
└── index.md (可修改)
|
||||
```
|
||||
|
||||
### watch
|
||||
|
||||
监听并编译standard_pages与page_demo_package下的的文件改动. 动态处理demo目录与文件markdown转化等.
|
||||
|
||||
## 注意
|
||||
|
||||
- 在修改page_demo_package或者standard_pages目录下的文件操作时. 建议在flutterGo目录执行goCLi watch 开启文件动态编译
|
||||
- name, author 字段必须使用英文开头, 不允许使用特殊符号. 正常的示范 name ='name_test' author = 'abcdefg';
|
||||
- 暂时阶段demo与page,一经过创建不允许修改名称作者等信息. 凡是被收录进主分支的不允许被删除
|
||||
|
||||
|
17
go-cli/bin/goCli.dart
Normal file
17
go-cli/bin/goCli.dart
Normal file
@ -0,0 +1,17 @@
|
||||
import 'package:args/args.dart'; // 使用其中两个类ArgParser和ArgResults
|
||||
import 'package:args/command_runner.dart';
|
||||
import '../src/cli_command_runder.dart';
|
||||
ArgResults argResults; // 声明ArgResults类型的顶级变量,保存解析的参数结果
|
||||
|
||||
// 同时,argResults也是ArgResults的实例
|
||||
void main(List<String> args) async {
|
||||
// createDemo();
|
||||
try {
|
||||
await run(args);
|
||||
} on UsageException catch (e) {
|
||||
|
||||
print(' ');
|
||||
print(e.usage);
|
||||
|
||||
}
|
||||
}
|
3
go-cli/config.json
Normal file
3
go-cli/config.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "sanfan"
|
||||
}
|
23
go-cli/pubspec.yaml
Normal file
23
go-cli/pubspec.yaml
Normal file
@ -0,0 +1,23 @@
|
||||
name: goCli
|
||||
description: bin_go
|
||||
|
||||
# The following defines the version and build number for your application.
|
||||
# A version number is three numbers separated by dots, like 1.2.43
|
||||
# followed by an optional build number separated by a +.
|
||||
# Both the version and the builder number may be overridden in flutter
|
||||
# build by specifying --build-name and --build-number, respectively.
|
||||
# Read more about versioning at semver.org.
|
||||
version: 1.0.0
|
||||
executables:
|
||||
goCli:
|
||||
environment:
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: '^1.5.1'
|
||||
dart_inquirer: '^1.0.0'
|
||||
watcher: ^0.9.7+10
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
|
95
go-cli/src/build/build_demo_list.dart
Normal file
95
go-cli/src/build/build_demo_list.dart
Normal file
@ -0,0 +1,95 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import '../../utils/util.dart';
|
||||
import '../config.dart';
|
||||
import '../exception/demo.dart';
|
||||
|
||||
|
||||
Future<List> buildDemoListJson() async {
|
||||
List<FileSystemEntity> childList = await readeDirChildren(TARGET_DEMO_DIC, false);
|
||||
List<String> demoPathList = [];
|
||||
List<Map<String, dynamic>> detailList = []; // 存放所有demo的详情的列表
|
||||
for(FileSystemEntity entity in childList) {
|
||||
//文件、目录和链接都继承自FileSystemEntity
|
||||
//FileSystemEntity.type静态函数返回值为FileSystemEntityType
|
||||
//FileSystemEntityType有三个常量:
|
||||
//Directory、FILE、LINK、NOT_FOUND
|
||||
//FileSystemEntity.isFile .isLink .isDerectory可用于判断类型
|
||||
Uri url = entity.uri;
|
||||
if (await FileSystemEntity.isDirectory(entity.path)) {
|
||||
try {
|
||||
await checkDemo(entity.path);
|
||||
demoPathList.add(entity.path);
|
||||
} on InvalidDemo catch (e) {
|
||||
print("不存在 $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String dicPath in demoPathList) {
|
||||
String target = '$dicPath/.demo.json';
|
||||
String jsonString = await readeFile(target);
|
||||
try {
|
||||
Map<String, dynamic> item = json.decode(jsonString);
|
||||
detailList.add(item);
|
||||
} catch (err) {
|
||||
print("err $err");
|
||||
throw new Exception('$dicPath');
|
||||
}
|
||||
}
|
||||
print("本次编译: 获取${detailList.length}条demo数据");
|
||||
|
||||
String demoTplString = renderDemosDart(detailList);
|
||||
|
||||
// 生成 page_demo_package/index.dart
|
||||
writeContent2Path(TARGET_DEMO_DIC, 'index.dart', demoTplString.replaceAll(new RegExp('-'), '_'));
|
||||
// 生成 page_demo_package/.demo.dart
|
||||
writeContent2Path(TARGET_DEMO_DIC, '.demo.json', json.encode(detailList));
|
||||
return Future(() => childList);
|
||||
// return ;
|
||||
}
|
||||
|
||||
String renderDemosDart(List<Map<String, dynamic>> data) {
|
||||
// 自定义前缀 避免出现数字非法字符等
|
||||
String pre = "StandardDemo";
|
||||
String head = '';
|
||||
String foot = 'var demoObjects = { \r\n';
|
||||
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
Map<String, dynamic> item = data[i];
|
||||
String demoImportName = '${item['name']}_${item['id']}';
|
||||
head += "import '${item['name']}_${item['author']}_${item['id']}/index.dart' as StandardDemo_$demoImportName;\r\n";
|
||||
|
||||
foot += " '${item['id']}': ${pre}_${demoImportName}.demoWidgets";
|
||||
|
||||
if (i != data.length - 1) {
|
||||
foot += ',\r\n';
|
||||
}
|
||||
|
||||
}
|
||||
foot += "\r\n};";
|
||||
|
||||
return head + foot;
|
||||
}
|
||||
Future<bool> checkDemo(String path) async {
|
||||
List files = [
|
||||
'index.dart',
|
||||
'.demo.json',
|
||||
'src/'
|
||||
];
|
||||
bool success = true;
|
||||
for (String name in files) {
|
||||
bool isDic = name.indexOf('/') != -1;
|
||||
bool isExist ;
|
||||
String detailPath = '$path/$name';
|
||||
if (isDic) {
|
||||
isExist = await Directory(detailPath).exists();
|
||||
} else {
|
||||
isExist = await File(detailPath).exists();
|
||||
}
|
||||
if (!isExist) {
|
||||
throw new InvalidDemo('$path$name not exit');
|
||||
}
|
||||
}
|
||||
return Future(() => true);
|
||||
}
|
165
go-cli/src/build/build_page_list.dart
Normal file
165
go-cli/src/build/build_page_list.dart
Normal file
@ -0,0 +1,165 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:path/path.dart' as p;
|
||||
import '../../utils/util.dart';
|
||||
import '../config.dart';
|
||||
import '../exception/demo.dart';
|
||||
|
||||
|
||||
Future<List> buildPageListJson() async {
|
||||
List<FileSystemEntity> childList = await readeDirChildren(TARGET_PAGE_DIC, false);
|
||||
List<String> pagePathList = [];
|
||||
List<Map<String, dynamic>> detailList = []; // 存放所有demo的详情的列表
|
||||
int errCount = 0;
|
||||
int pageCount = 0;
|
||||
for(FileSystemEntity entity in childList) {
|
||||
//文件、目录和链接都继承自FileSystemEntity
|
||||
//FileSystemEntity.type静态函数返回值为FileSystemEntityType
|
||||
//FileSystemEntityType有三个常量:
|
||||
//Directory、FILE、LINK、NOT_FOUND
|
||||
//FileSystemEntity.isFile .isLink .isDerectory可用于判断类型
|
||||
if (await FileSystemEntity.isDirectory(entity.path)) {
|
||||
pageCount++;
|
||||
try {
|
||||
await checkPage(entity.path);
|
||||
pagePathList.add(entity.path);
|
||||
} on InvalidDemo catch (e) {
|
||||
errCount++;
|
||||
print("不存在 $e");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (String dicPath in pagePathList) {
|
||||
String target = '$dicPath/.page.json';
|
||||
String jsonString = await readeFile(target);
|
||||
try {
|
||||
Map<String, dynamic> item = json.decode(jsonString);
|
||||
detailList.add(item);
|
||||
} catch (err) {
|
||||
print("err $err");
|
||||
|
||||
throw new Exception('$dicPath');
|
||||
}
|
||||
}
|
||||
print("本次编译: 总${pageCount}个界面, 成功${detailList.length}条, 失败${errCount}条");
|
||||
|
||||
String demoTplString = renderPagesDart(detailList);
|
||||
//
|
||||
// // 生成 page_demo_package/index.dart
|
||||
writeContent2Path(TARGET_PAGE_DIC, 'index.dart', demoTplString.replaceAll(new RegExp('-'), '_'));
|
||||
// // 生成 page_demo_package/.demo.dart
|
||||
writeContent2Path(TARGET_PAGE_DIC, '.pages.json', json.encode(detailList));
|
||||
return Future(() => childList);
|
||||
// return ;
|
||||
}
|
||||
|
||||
String renderPagesDart(List<Map<String, dynamic>> data) {
|
||||
// 自定义前缀 避免出现数字非法字符等
|
||||
String pre = "StandardPage";
|
||||
String head = '';
|
||||
String foot = """
|
||||
class StandardPages {
|
||||
Map<String, String> standardPages;
|
||||
Map<String, String> getPages() {
|
||||
return {
|
||||
""";
|
||||
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
Map<String, dynamic> item = data[i];
|
||||
String demoImportName = '${item['name']}_${item['id']}';
|
||||
head += "import '${item['name']}_${item['author']}_${item['id']}/index.dart' as ${pre}_$demoImportName;\r\n";
|
||||
|
||||
foot += "\t\t\t'${item['id']}': ${pre}_${demoImportName}.getMd()";
|
||||
|
||||
if (i != data.length - 1) {
|
||||
foot += ',\r\n';
|
||||
}
|
||||
|
||||
}
|
||||
foot += """\r
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
""";
|
||||
|
||||
return head + foot;
|
||||
}
|
||||
Future<bool> checkPage(String path) async {
|
||||
List files = [
|
||||
'index.dart',
|
||||
'index.md',
|
||||
'.page.json'
|
||||
];
|
||||
for (String name in files) {
|
||||
bool isDic = name.indexOf('/') != -1;
|
||||
bool isExist ;
|
||||
String detailPath = '$path/$name';
|
||||
if (isDic) {
|
||||
isExist = await Directory(detailPath).exists();
|
||||
} else {
|
||||
isExist = await File(detailPath).exists();
|
||||
}
|
||||
if (!isExist) {
|
||||
throw new InvalidDemo('$path$name not exit');
|
||||
}
|
||||
}
|
||||
return Future(() => true);
|
||||
}
|
||||
|
||||
|
||||
Future<void> transformMd2Dart(String path) async{
|
||||
print("pathLL: $path");
|
||||
String mdContent = await readeFile(p.absolute(path,'index.md'));
|
||||
|
||||
|
||||
String result = """
|
||||
String getMd() {
|
||||
return \"\"\"
|
||||
${mdContent}\"\"\";
|
||||
|
||||
|
||||
}
|
||||
""";
|
||||
writeContent2Path(p.absolute(path), 'index.dart', result);
|
||||
return '';
|
||||
}
|
||||
//main() {
|
||||
// buildPageListJson();
|
||||
//}
|
||||
|
||||
|
||||
////
|
||||
//// Created with Android Studio.
|
||||
//// User: 三帆
|
||||
//// Date: 25/05/2019
|
||||
//// Time: 21:23
|
||||
//// email: sanfan.hx@alibaba-inc.com
|
||||
//// target: 该文件用在打包后的代码中.日常开发的时候, 获取markdown不走该目录
|
||||
////
|
||||
//import 'package:flutter/material.dart';
|
||||
//import 'page1_hanxu_172ba42f_0520_401e_b568_ba7f7f6835e4/index.dart' as page1_hanxu_172ba42f_0520_401e_b568_ba7f7f6835e4;
|
||||
//
|
||||
//
|
||||
//class StandardPages {
|
||||
// Map<String, String> standardPages;
|
||||
// Map<String, String> getPages() {
|
||||
// return {
|
||||
// 'page1_hanxu_172ba42f_0520_401e_b568_ba7f7f6835e4': page1_hanxu_172ba42f_0520_401e_b568_ba7f7f6835e4.stringMd
|
||||
// };
|
||||
// }
|
||||
//}
|
||||
|
||||
//var stringMd = """# page
|
||||
//
|
||||
//this is page markdown
|
||||
//
|
||||
//you can load demo like this
|
||||
//
|
||||
//```
|
||||
//[demo: xxxid]
|
||||
//```
|
||||
//
|
||||
//""";
|
||||
//
|
33
go-cli/src/cli_command_runder.dart
Normal file
33
go-cli/src/cli_command_runder.dart
Normal file
@ -0,0 +1,33 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:args/command_runner.dart';
|
||||
import './version.dart';
|
||||
import './command/create_demo.dart';
|
||||
import './command/create_page.dart';
|
||||
import './command/watch_md.dart';
|
||||
|
||||
|
||||
|
||||
Future<int> run(List<String> args) => _CommandRunner().run(args);
|
||||
|
||||
class _CommandRunner extends CommandRunner<int> {
|
||||
_CommandRunner() : super('goCli', 'A tool to develop flutter go projects.') {
|
||||
argParser.addFlag('version',
|
||||
negatable: false, help: 'Prints the version of goCi.');
|
||||
addCommand(CreateDemoCommand());
|
||||
addCommand(CreatePageCommand());
|
||||
addCommand(WatchCommand());
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> runCommand(ArgResults topLevelResults) async {
|
||||
if (topLevelResults['version'] as bool) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// In the case of `help`, `null` is returned. Treat that as success.
|
||||
return await super.runCommand(topLevelResults) ?? 0;
|
||||
}
|
||||
}
|
137
go-cli/src/command/create_demo.dart
Normal file
137
go-cli/src/command/create_demo.dart
Normal file
@ -0,0 +1,137 @@
|
||||
import 'dart:io';
|
||||
import 'package:args/args.dart'; // 使用其中两个类ArgParser和ArgResults
|
||||
import 'package:dart_inquirer/dart_inquirer.dart';
|
||||
import 'package:console/console.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:args/command_runner.dart';
|
||||
import '../build/build_demo_list.dart';
|
||||
|
||||
import '../config.dart';
|
||||
import '../../utils/util.dart';
|
||||
|
||||
|
||||
|
||||
ArgResults argResults; // 声明ArgResults类型的顶级变量,保存解析的参数结果
|
||||
|
||||
class DemoDetail {
|
||||
String name;
|
||||
String author;
|
||||
String email;
|
||||
String desc;
|
||||
String id;
|
||||
DemoDetail.fromJson(Map<dynamic, dynamic> json) {
|
||||
name = json['name'].trim();
|
||||
author = json['author'].trim();
|
||||
email = json['email'].trim();
|
||||
desc = json['desc'].trim();
|
||||
id = json['id'] ?? generateId();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
// 同时,argResults也是ArgResults的实例
|
||||
void createDemo() async {
|
||||
Map environmentVars = Platform.environment;
|
||||
List<Question> questions = [
|
||||
InputQuestion('name', '请输入新增加的demo名称?'),
|
||||
InputQuestion('author', '请输入您的姓名(使用英文)'),
|
||||
InputQuestion('email', '请输入您的github的email地址'),
|
||||
InputQuestion('desc', '请输入您demo的描述'),
|
||||
];
|
||||
|
||||
Map<dynamic, dynamic> answers = {};
|
||||
// 获取初次信息
|
||||
Prompt prompt = Prompt(questions);
|
||||
DemoDetail demoDetail;
|
||||
answers = await prompt.execute();
|
||||
|
||||
print(Seperator());
|
||||
print('您新增的组件信息如下');
|
||||
print(Seperator('='));
|
||||
prettyPrintJson(answers);
|
||||
print(Seperator('='));
|
||||
|
||||
questions =[ConfirmQuestion('confirm', 'Is this the config you want ?')];
|
||||
prompt = Prompt(questions);
|
||||
Map confirmAnswers = await prompt.execute();
|
||||
if (confirmAnswers['confirm'] != true) {
|
||||
return createDemo();
|
||||
}
|
||||
demoDetail = DemoDetail.fromJson(answers);
|
||||
|
||||
var demoPath = '$TARGET_DEMO_DIC/${demoDetail.name}_${demoDetail.author}_${demoDetail.id}';
|
||||
|
||||
// 创建root文件
|
||||
await createFile(demoPath);
|
||||
await createFile('$demoPath/src');
|
||||
// print("demoPath>>>> ${environmentVars['PWD']}/${demoPath}");
|
||||
writeContent2Path('$demoPath/src/', 'index.dart', """
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Demo extends StatefulWidget {
|
||||
@override
|
||||
_State createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<Demo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Text("this is flutter go init demo"),
|
||||
);
|
||||
}
|
||||
}
|
||||
""");
|
||||
|
||||
writeContent2Path('$demoPath/', '.demo.json', """
|
||||
{
|
||||
"name": "${demoDetail.name}",
|
||||
"screenShot": "",
|
||||
"author":"${demoDetail.author}",
|
||||
"email": "${demoDetail.email}",
|
||||
"desc": "${demoDetail.desc}",
|
||||
"id": "${demoDetail.id}"
|
||||
}
|
||||
""");
|
||||
|
||||
writeContent2Path('$demoPath/', 'index.dart', """
|
||||
//
|
||||
// Created with flutter go cli
|
||||
// User: ${demoDetail.author}
|
||||
// Time: ${new DateTime.now()}
|
||||
// email: ${demoDetail.email}
|
||||
// desc: ${demoDetail.desc}
|
||||
//
|
||||
|
||||
import 'src/index.dart';
|
||||
|
||||
var demoWidgets = [
|
||||
new Demo()
|
||||
];
|
||||
|
||||
""");
|
||||
// format('{color.red}Invalid demo happends: $details {color.normal}');
|
||||
prettyPrintJson({
|
||||
'新建的demo文件位于': p.absolute((demoPath)),
|
||||
'demoId为': demoDetail.id,
|
||||
'markdown中调用方式': '[demo:${demoDetail.id}]'
|
||||
});
|
||||
buildDemoListJson();
|
||||
}
|
||||
|
||||
|
||||
class CreateDemoCommand extends Command<int> {
|
||||
@override
|
||||
final name = 'createDemo';
|
||||
@override
|
||||
final description = '新增flutter go demo.';
|
||||
|
||||
CreateDemoCommand() {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
createDemo();
|
||||
return 0;
|
||||
}
|
||||
}
|
124
go-cli/src/command/create_page.dart
Normal file
124
go-cli/src/command/create_page.dart
Normal file
@ -0,0 +1,124 @@
|
||||
import 'dart:io';
|
||||
import 'package:args/args.dart'; // 使用其中两个类ArgParser和ArgResults
|
||||
import 'package:dart_inquirer/dart_inquirer.dart';
|
||||
import 'package:args/command_runner.dart';
|
||||
|
||||
import '../build/build_page_list.dart';
|
||||
import '../config.dart';
|
||||
import '../../utils/util.dart';
|
||||
|
||||
var pageMarkdown = """
|
||||
# page
|
||||
|
||||
this is page markdown
|
||||
|
||||
you can load demo like this
|
||||
|
||||
```
|
||||
[demo: xxxid]
|
||||
```
|
||||
|
||||
""";
|
||||
|
||||
|
||||
ArgResults argResults; // 声明ArgResults类型的顶级变量,保存解析的参数结果
|
||||
|
||||
class PageDetail {
|
||||
String name;
|
||||
String author;
|
||||
String title;
|
||||
String email;
|
||||
String desc;
|
||||
String id;
|
||||
PageDetail.fromJson(Map<dynamic, dynamic> json) {
|
||||
name = json['name'];
|
||||
author = json['author'];
|
||||
title = json['title'];
|
||||
email = json['email'];
|
||||
desc = json['desc'];
|
||||
id = json['id'] ?? generateId();
|
||||
}
|
||||
}
|
||||
// 同时,argResults也是ArgResults的实例
|
||||
void createPage() async {
|
||||
Map environmentVars = Platform.environment;
|
||||
List<Question> questions = [
|
||||
InputQuestion('name', '请输入文件名称?'),
|
||||
InputQuestion('title', '请输入界面名称?'),
|
||||
InputQuestion('author', '请输入您的姓名(使用英文)'),
|
||||
InputQuestion('email', '请输入您的email地址'),
|
||||
InputQuestion('desc', '请输入您界面的简要'),
|
||||
];
|
||||
|
||||
Map<dynamic, dynamic> answers = {};
|
||||
// 获取初次信息
|
||||
Prompt prompt = Prompt(questions);
|
||||
PageDetail pageDetail;
|
||||
answers = await prompt.execute();
|
||||
print(Seperator());
|
||||
print('您新增的界面信息如下');
|
||||
print(Seperator('='));
|
||||
prettyPrintJson(answers);
|
||||
print(Seperator('='));
|
||||
|
||||
questions =[ConfirmQuestion('confirm', 'Is this the config you want ?')];
|
||||
prompt = Prompt(questions);
|
||||
Map confirmAnswers = await prompt.execute();
|
||||
if (confirmAnswers['confirm'] != true) {
|
||||
return createPage();
|
||||
}
|
||||
pageDetail = PageDetail.fromJson(answers);
|
||||
|
||||
var demoPath = '$TARGET_PAGE_DIC/${pageDetail.name}_${pageDetail.author}_${pageDetail.id}';
|
||||
|
||||
// 创建root文件
|
||||
await createFile(demoPath);
|
||||
|
||||
pageMarkdown = await readeFile("${environmentVars['PWD']}/go-cli/utils/tpl.md");
|
||||
|
||||
writeContent2Path('$demoPath/', 'index.dart', """
|
||||
String getMd() {
|
||||
return \"\"\"
|
||||
${pageMarkdown}\"\"\";
|
||||
|
||||
}
|
||||
""");
|
||||
|
||||
writeContent2Path('$demoPath/', '.page.json', """
|
||||
{
|
||||
"name": "${pageDetail.name}",
|
||||
"screenShot": "",
|
||||
"author":"${pageDetail.author}",
|
||||
"title":"${pageDetail.title}",
|
||||
"email": "${pageDetail.email}",
|
||||
"desc": "${pageDetail.desc}",
|
||||
"id": "${pageDetail.id}"
|
||||
}
|
||||
""");
|
||||
|
||||
writeContent2Path('$demoPath/', 'index.md', pageMarkdown);
|
||||
buildPageListJson();
|
||||
prettyPrintJson({
|
||||
'界面位于': demoPath,
|
||||
'Id': pageDetail.id,
|
||||
'文件夹名称': '${pageDetail.name}_${pageDetail.author}_${pageDetail.id}'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class CreatePageCommand extends Command<int> {
|
||||
@override
|
||||
final name = 'createPage';
|
||||
@override
|
||||
final description = '新增flutter go page.';
|
||||
|
||||
CreateDemoCommand() {
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
createPage();
|
||||
return 0;
|
||||
}
|
||||
}
|
102
go-cli/src/command/watch_md.dart
Normal file
102
go-cli/src/command/watch_md.dart
Normal file
@ -0,0 +1,102 @@
|
||||
//
|
||||
// Created with Android Studio.
|
||||
// User: 三帆
|
||||
// Date: 08/06/2019
|
||||
// Time: 16:34
|
||||
// email: sanfan.hx@alibaba-inc.com
|
||||
// target: 监听demo与md
|
||||
//
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:args/command_runner.dart';
|
||||
import '../build/build_demo_list.dart';
|
||||
import '../build/build_page_list.dart';
|
||||
|
||||
import 'package:watcher/watcher.dart';
|
||||
import '../config.dart';
|
||||
import 'dart:async';
|
||||
|
||||
void watch() {
|
||||
Timer _changeTimer;
|
||||
List<Map<String, String>> config = [
|
||||
{
|
||||
"type": "demo",
|
||||
"path": '$TARGET_DEMO_DIC'
|
||||
}
|
||||
];
|
||||
List<String> demoIgnore = [
|
||||
'.demo.json',
|
||||
'index.dart',
|
||||
'info.json',
|
||||
'readme.md',
|
||||
];
|
||||
var watcherDemo = DirectoryWatcher(p.absolute('$TARGET_DEMO_DIC'));
|
||||
watcherDemo.events.listen((event) {
|
||||
|
||||
if (isIgnore(demoIgnore, TARGET_DEMO_DIC, event.path)) {
|
||||
return ;
|
||||
}
|
||||
if (event.type == ChangeType.ADD || event.type == ChangeType.REMOVE) {
|
||||
if (_changeTimer != null && _changeTimer.isActive) {
|
||||
_changeTimer.cancel();
|
||||
}
|
||||
_changeTimer = new Timer(Duration(milliseconds: 1000), () {
|
||||
buildDemoListJson();
|
||||
});
|
||||
}
|
||||
|
||||
}, onError: (error) {
|
||||
print('watch 发生错误: $error');
|
||||
});
|
||||
|
||||
List<String> pageIgnore = [
|
||||
'index.dart',
|
||||
'.pages.json'
|
||||
];
|
||||
var watcherPage = DirectoryWatcher(p.absolute('$TARGET_PAGE_DIC'));
|
||||
watcherPage.events.listen((event) {
|
||||
if (isIgnore(pageIgnore, TARGET_PAGE_DIC, event.path)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
if (event.type == ChangeType.ADD || event.type == ChangeType.REMOVE) {
|
||||
print("buildPageListJson:::");
|
||||
buildPageListJson();
|
||||
return ;
|
||||
}
|
||||
|
||||
if (event.type == ChangeType.MODIFY) {
|
||||
if (event.path.contains('index.md')) {
|
||||
transformMd2Dart(event.path.replaceAll('/index.md', ''));
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
print(event);
|
||||
});
|
||||
}
|
||||
bool isIgnore (List<String> ignorePath, parentPath, currentPath) {
|
||||
for (String ignore in ignorePath) {
|
||||
String path = p.absolute(parentPath, ignore);
|
||||
if (currentPath.contains(path)) {
|
||||
// print("修改的文件, 是忽略列表中的文件, 跳过编译!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
class WatchCommand extends Command<int> {
|
||||
@override
|
||||
final name = 'watch';
|
||||
@override
|
||||
final description = '动态生成文档与demo相关';
|
||||
|
||||
CreateDemoCommand() {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
watch();
|
||||
return 0;
|
||||
}
|
||||
}
|
4
go-cli/src/config.dart
Normal file
4
go-cli/src/config.dart
Normal file
@ -0,0 +1,4 @@
|
||||
// 生成Demo的目录位置
|
||||
const TARGET_PAGE_DIC = 'lib/standard_pages';
|
||||
const TARGET_DEMO_DIC = 'lib/page_demo_package';
|
||||
|
21
go-cli/src/exception/demo.dart
Normal file
21
go-cli/src/exception/demo.dart
Normal file
@ -0,0 +1,21 @@
|
||||
//
|
||||
// Created with Android Studio.
|
||||
// User: 三帆
|
||||
// Date: 25/05/2019
|
||||
// Time: 21:20
|
||||
// email: sanfan.hx@alibaba-inc.com
|
||||
// target: xxx
|
||||
//
|
||||
|
||||
|
||||
import 'package:console/console.dart';
|
||||
|
||||
class InvalidDemo implements Exception {
|
||||
final String details;
|
||||
InvalidDemo(this.details);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return format('{color.red}Invalid demo happends: $details {color.normal}');
|
||||
}
|
||||
}
|
1
go-cli/src/version.dart
Normal file
1
go-cli/src/version.dart
Normal file
@ -0,0 +1 @@
|
||||
const packageVersion = '1.0.0';
|
48
go-cli/utils/tpl.md
Normal file
48
go-cli/utils/tpl.md
Normal file
@ -0,0 +1,48 @@
|
||||
# 标准的详情页
|
||||
|
||||
您可以在这个界面中, 编写大多数的markdown文案, 他会在 **goCli watch** 下同步被编译成 **dart** 文件
|
||||
|
||||
您可以通过goCli创建详情页所需要的demo
|
||||
|
||||
```
|
||||
goCLi createDemo
|
||||
```
|
||||
|
||||
在flutter go 根文件下通过命令行输入以上命令可以进行以下操作
|
||||
|
||||
[✓] 请输入新增加的demo名称? demoName
|
||||
|
||||
[✓] 请输入您的姓名(使用英文) yourName
|
||||
|
||||
[✓] 请输入您的github的email地址 yourEmail
|
||||
|
||||
[✓] 请输入您demo的描述 这是一个测试的标准demo
|
||||
|
||||
|
||||
在完成以上操作后, 可以得到这样的输出:
|
||||
|
||||
|
||||
```
|
||||
------------------
|
||||
您新增的组件信息如下
|
||||
==================
|
||||
{
|
||||
name : demoName
|
||||
author : yourName
|
||||
email : yourEmail
|
||||
desc : 这是一个测试的标准demo
|
||||
}
|
||||
==================
|
||||
[✓] Is this the config you want ? (Y/n) y
|
||||
{
|
||||
新建的demo文件位于 : /flutter go/lib/page_demo_package/demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
demoId为 : 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
markdown中调用方式 : [demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
}
|
||||
|
||||
```
|
||||
您可以在任意详情页中, 通过以下方式调用
|
||||
|
||||
```
|
||||
[demo: 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
```
|
64
go-cli/utils/util.dart
Normal file
64
go-cli/utils/util.dart
Normal file
@ -0,0 +1,64 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
Future<bool> createFile(String path) async {
|
||||
final tempDic = new Directory(path);
|
||||
var exits = await tempDic.exists();
|
||||
|
||||
if (exits) {
|
||||
print("文件当前已存在");
|
||||
return Future(() => false);
|
||||
}
|
||||
|
||||
await tempDic.createSync(recursive: true);
|
||||
return Future(() => true);
|
||||
}
|
||||
Future<String> readeFile(String path) async {
|
||||
String content = await new File(path).readAsString();
|
||||
return Future(() => content);
|
||||
}
|
||||
|
||||
// 该文件调用的时候. 必须存在父级文件夹
|
||||
Future<void> writeContent2Path(String path,String fileName, String content) async {
|
||||
var file = File('$path/$fileName');
|
||||
var sink = file.openWrite();
|
||||
sink.write(content);
|
||||
await sink.flush();
|
||||
await sink.close();
|
||||
return Future.value();
|
||||
}
|
||||
String generateId() {
|
||||
int d = DateTime.now().millisecondsSinceEpoch;
|
||||
var random = new Random(1);
|
||||
var template = 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx';
|
||||
var id = template.replaceAllMapped(new RegExp(r"[x|y]"), (c) {
|
||||
var r = ((d + random.nextDouble() * 16) % 16).toInt();
|
||||
d = d ~/ 16;
|
||||
var t = c.group(0) == 'x' ? r : (1 & 0x3 | 0x8);
|
||||
return t.toRadixString(16);
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
/// 该文件调用的时候. 必须存在父级文件夹
|
||||
/// @param path 目录地址
|
||||
/// @param recursive 是否显示子目录或者子文件
|
||||
Future<List<FileSystemEntity>> readeDirChildren(String path, [bool recursive = false]) async {
|
||||
try {
|
||||
var dirParent = Directory(path);
|
||||
Stream<FileSystemEntity> entityList = dirParent.list(recursive: false, followLinks: false);
|
||||
List<FileSystemEntity> fileChildren = [];
|
||||
|
||||
await for(FileSystemEntity entity in entityList) {
|
||||
fileChildren.add(entity);
|
||||
}
|
||||
|
||||
return Future(() => fileChildren);
|
||||
} catch (e) {
|
||||
print('读取文件失败 ${e.toString()}');
|
||||
return Future(() => []);
|
||||
}
|
||||
}
|
||||
|
||||
//void main() {
|
||||
// readeFile('/Users/ontwo/Documents/ali/flutter/flutter-common-widgets-app/LICENSE');
|
||||
//}
|
@ -1,2 +1,3 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
#include "../Pods/Target\ Support\ Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
|
@ -1,2 +1,3 @@
|
||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
#include "../Pods/Target\ Support\ Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
|
@ -32,6 +32,16 @@
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
FA240D7922F2857D003025F3 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0115F22F1B9DF0016E673 /* Flutter.framework */; };
|
||||
FA240D7A22F2857D003025F3 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0115F22F1B9DF0016E673 /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FA240D7B22F28581003025F3 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0116122F1B9DF0016E673 /* App.framework */; };
|
||||
FA240D7C22F28581003025F3 /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0116122F1B9DF0016E673 /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
FAD0116422F1B9DF0016E673 /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FAD0115E22F1B9DF0016E673 /* Debug.xcconfig */; };
|
||||
FAD0116522F1B9DF0016E673 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0115F22F1B9DF0016E673 /* Flutter.framework */; };
|
||||
FAD0116622F1B9DF0016E673 /* Release.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FAD0116022F1B9DF0016E673 /* Release.xcconfig */; };
|
||||
FAD0116722F1B9DF0016E673 /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAD0116122F1B9DF0016E673 /* App.framework */; };
|
||||
FAD0116822F1B9DF0016E673 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = FAD0116222F1B9DF0016E673 /* AppFrameworkInfo.plist */; };
|
||||
FAD0116922F1B9DF0016E673 /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = FAD0116322F1B9DF0016E673 /* Generated.xcconfig */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -41,6 +51,8 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
FA240D7C22F28581003025F3 /* App.framework in Embed Frameworks */,
|
||||
FA240D7A22F2857D003025F3 /* Flutter.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -80,6 +92,12 @@
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A4868A865F318D337B7500AF /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B7B77D3AD1E975E5BE03D770 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
FAD0115E22F1B9DF0016E673 /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
FAD0115F22F1B9DF0016E673 /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Flutter.framework; sourceTree = "<group>"; };
|
||||
FAD0116022F1B9DF0016E673 /* Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||
FAD0116122F1B9DF0016E673 /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = App.framework; sourceTree = "<group>"; };
|
||||
FAD0116222F1B9DF0016E673 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
FAD0116322F1B9DF0016E673 /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Generated.xcconfig; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -88,6 +106,10 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17DB4C25EDB98B3648015B9E /* libPods-Runner.a in Frameworks */,
|
||||
FAD0116722F1B9DF0016E673 /* App.framework in Frameworks */,
|
||||
FAD0116522F1B9DF0016E673 /* Flutter.framework in Frameworks */,
|
||||
FA240D7922F2857D003025F3 /* Flutter.framework in Frameworks */,
|
||||
FA240D7B22F28581003025F3 /* App.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -127,6 +149,7 @@
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FAD0115D22F1B9DF0016E673 /* Flutter */,
|
||||
0828E485220692A700A59437 /* launch */,
|
||||
084A20872202E4FD00428FF5 /* flutter go.png */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
@ -180,6 +203,19 @@
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FAD0115D22F1B9DF0016E673 /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FAD0115E22F1B9DF0016E673 /* Debug.xcconfig */,
|
||||
FAD0115F22F1B9DF0016E673 /* Flutter.framework */,
|
||||
FAD0116022F1B9DF0016E673 /* Release.xcconfig */,
|
||||
FAD0116122F1B9DF0016E673 /* App.framework */,
|
||||
FAD0116222F1B9DF0016E673 /* AppFrameworkInfo.plist */,
|
||||
FAD0116322F1B9DF0016E673 /* Generated.xcconfig */,
|
||||
);
|
||||
path = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -250,6 +286,7 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
FAD0116622F1B9DF0016E673 /* Release.xcconfig in Resources */,
|
||||
0828E4A0220692B500A59437 /* iPad Landscape.png in Resources */,
|
||||
0828E4A1220692B500A59437 /* iPhone XR Portrait.png in Resources */,
|
||||
0828E49F220692B500A59437 /* iPhone XS Max Landscape.png in Resources */,
|
||||
@ -260,14 +297,17 @@
|
||||
0828E49E220692B500A59437 /* iPad Portrait@2x.png in Resources */,
|
||||
0828E49D220692B500A59437 /* iPhone Portrait@2x.png in Resources */,
|
||||
0828E499220692B500A59437 /* iPhone Portrait-Retina HD 4.7.png in Resources */,
|
||||
FAD0116822F1B9DF0016E673 /* AppFrameworkInfo.plist in Resources */,
|
||||
084A20882202E4FD00428FF5 /* flutter go.png in Resources */,
|
||||
0828E497220692B500A59437 /* iPhone X_XS Landscape.png in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
0828E4A52206936100A59437 /* Images.xcassets in Resources */,
|
||||
FAD0116922F1B9DF0016E673 /* Generated.xcconfig in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
0828E49B220692B500A59437 /* iPad Landscape@2x.png in Resources */,
|
||||
0828E495220692B500A59437 /* iPhone Portrait-Retina 4.png in Resources */,
|
||||
0828E498220692B500A59437 /* iPhone XS Max Portrait.png in Resources */,
|
||||
FAD0116422F1B9DF0016E673 /* Debug.xcconfig in Resources */,
|
||||
94722E5C22511D3600F63900 /* GoogleService-Info.plist in Resources */,
|
||||
0828E496220692B500A59437 /* iPad Portrait.png in Resources */,
|
||||
0828E49C220692B500A59437 /* iPhone Landscape-Retina HD 5.5.png in Resources */,
|
||||
@ -289,11 +329,11 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
|
||||
shellScript = "/bin/sh \"/Users/nealyang/development/flutter/packages/flutter_tools/bin/xcode_backend.sh\" thin\n";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
buildActionMask = 12;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
@ -303,7 +343,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
|
||||
};
|
||||
B34D03FFEA3831330E64E5C7 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
@ -506,7 +546,7 @@
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = A4868A865F318D337B7500AF /* Pods-Runner.debug.xcconfig */;
|
||||
baseConfigurationReference = FAD0115E22F1B9DF0016E673 /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = Launch2;
|
||||
@ -537,7 +577,7 @@
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B7B77D3AD1E975E5BE03D770 /* Pods-Runner.release.xcconfig */;
|
||||
baseConfigurationReference = FAD0116022F1B9DF0016E673 /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = Launch2;
|
||||
|
@ -1,5 +1,5 @@
|
||||
class Api{
|
||||
// static const String BASE_URL = 'http://flutter-go.alibaba.net/';
|
||||
// static const String BASE_URL = 'http://flutter-go.alibaba.net/';
|
||||
static const String BASE_URL = 'https://flutter-go.pub/api/';
|
||||
|
||||
static const String DO_LOGIN = BASE_URL+'doLogin';//登陆
|
||||
@ -15,7 +15,7 @@ class Api{
|
||||
|
||||
static const String FEEDBACK = BASE_URL+'auth/feedback';//建议反馈
|
||||
|
||||
static const String LOTOUT = BASE_URL+'logout';//退出登陆
|
||||
// static const String LOTOUT = BASE_URL+'logout';//退出登陆
|
||||
|
||||
static const String GET_ALL_COLLECTION = BASE_URL+'auth/getAllUserCollection';//获取全部收藏
|
||||
|
||||
@ -23,9 +23,14 @@ class Api{
|
||||
|
||||
static const String ADD_COLLECTION = BASE_URL+'auth/addCollection';//添加收藏
|
||||
|
||||
static const String CHECK_COLLECTED = BASE_URL+'auth/checkCollected';//校验收藏
|
||||
static const String CHECK_COLLECTED = BASE_URL+'checkCollected';//校验收藏
|
||||
|
||||
static const String SET_THEMECOLOR = BASE_URL+'auth/setThemeColor';//设置主题颜色
|
||||
|
||||
static const String GET_THEMECOLOR = BASE_URL +'/getThemeColor';//获取主题颜色
|
||||
}
|
||||
|
||||
static const String GET_WIDGET_TREE = 'http://flutter-go.alibaba.net/' + 'getCateList';//获取widget列表树
|
||||
|
||||
static const String SEARCH_WIDGET = BASE_URL+'searchWidget';//搜索组件
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../model/cat.dart';
|
||||
import '../resources/widget_name_to_icon.dart';
|
||||
import '../components/widget_item_container.dart';
|
||||
import '../model/widget.dart';
|
||||
|
||||
class CateCard extends StatefulWidget {
|
||||
final Cat category;
|
||||
final CategoryComponent category;
|
||||
CateCard({@required this.category});
|
||||
@override
|
||||
_CateCardState createState() => _CateCardState();
|
||||
@ -13,28 +13,15 @@ class CateCard extends StatefulWidget {
|
||||
|
||||
class _CateCardState extends State<CateCard> {
|
||||
// 一级菜单目录下的二级Cat集合
|
||||
List<Cat> _firstChildList = new List();
|
||||
CatControlModel catControl = new CatControlModel();
|
||||
List<CommonItem> _firstChildList;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getFirstChildCategoriesByParentId();
|
||||
_firstChildList = widget.category.children;
|
||||
}
|
||||
|
||||
// 获取一层目录下的二级内容
|
||||
getFirstChildCategoriesByParentId() async {
|
||||
int parentId = widget.category.id;
|
||||
// 构建查询条件
|
||||
Cat childCateCondition = new Cat(parentId: parentId);
|
||||
|
||||
List<Cat> list = await catControl.getList(childCateCondition);
|
||||
if (list.isNotEmpty&&list.length>=1 && this.mounted) {
|
||||
setState(() {
|
||||
_firstChildList = list;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -43,7 +30,6 @@ class _CateCardState extends State<CateCard> {
|
||||
//首字母转为大写
|
||||
widget.category.name.substring(0, 1),
|
||||
widget.category.name.substring(0, 1).toUpperCase());
|
||||
|
||||
return Container(
|
||||
width: screenWidth,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
|
||||
@ -119,9 +105,8 @@ class _CateCardState extends State<CateCard> {
|
||||
),
|
||||
),
|
||||
child: WidgetItemContainer(
|
||||
categories: this._firstChildList,
|
||||
columnCount: 3,
|
||||
isWidgetPoint:false
|
||||
commonItems: this._firstChildList,
|
||||
columnCount: 3
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -8,11 +8,12 @@ import '../model/widget.dart';
|
||||
import '../widgets/index.dart';
|
||||
import '../components/widget_item_container.dart';
|
||||
|
||||
enum CateOrWigdet { Cat, WidgetDemo }
|
||||
|
||||
|
||||
class CategoryHome extends StatefulWidget {
|
||||
CategoryHome(this.name);
|
||||
final String name;
|
||||
CategoryHome(this.token);
|
||||
final String token;
|
||||
|
||||
|
||||
@override
|
||||
_CategoryHome createState() => new _CategoryHome();
|
||||
@ -21,12 +22,11 @@ class CategoryHome extends StatefulWidget {
|
||||
class _CategoryHome extends State<CategoryHome> {
|
||||
String title = '';
|
||||
// 显示列表 cat or widget;
|
||||
List<Cat> categories = [];
|
||||
List<WidgetPoint> widgetPoints = [];
|
||||
List<Cat> catHistory = new List();
|
||||
List<CommonItem> items = [];
|
||||
List<Object> widgetPoints = [];
|
||||
List<CommonItem> catHistory = new List();
|
||||
|
||||
|
||||
CatControlModel catControl = new CatControlModel();
|
||||
WidgetControlModel widgetControl = new WidgetControlModel();
|
||||
// 所有的可用demos;
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
|
||||
@ -34,80 +34,60 @@ class _CategoryHome extends State<CategoryHome> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始化加入顶级的name
|
||||
this.getCatByName(widget.name).then((Cat cat) {
|
||||
catHistory.add(cat);
|
||||
searchCatOrWigdet();
|
||||
print("这是新界面的id:>>> ${widget.token}");
|
||||
|
||||
CommonItem targetGroup = Application.widgetTree.find(widget.token) ?? [];
|
||||
print("targetGroup::: $targetGroup");
|
||||
|
||||
catHistory.add(
|
||||
targetGroup
|
||||
);
|
||||
this.setState(() {
|
||||
items = targetGroup.children;
|
||||
});
|
||||
searchCatOrWidget();
|
||||
}
|
||||
|
||||
Future<Cat> getCatByName(String name) async {
|
||||
return await catControl.getCatByName(name);
|
||||
}
|
||||
|
||||
|
||||
Future<bool> back() {
|
||||
if (catHistory.length == 1) {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
catHistory.removeLast();
|
||||
searchCatOrWigdet();
|
||||
return Future<bool>.value(false);
|
||||
// if (catHistory.length == 1) {
|
||||
// return Future<bool>.value(true);
|
||||
// }
|
||||
// catHistory.removeLast();
|
||||
// searchCatOrWidget();
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
|
||||
void go(Cat cat) {
|
||||
void go(CommonItem cat) {
|
||||
catHistory.add(cat);
|
||||
searchCatOrWigdet();
|
||||
searchCatOrWidget();
|
||||
}
|
||||
|
||||
void searchCatOrWigdet() async {
|
||||
// 假设进入这个界面的parent一定存在
|
||||
Cat parentCat = catHistory.last;
|
||||
void searchCatOrWidget() async {
|
||||
CommonItem widgetTree = Application.widgetTree;
|
||||
// 假设进入这个界面的parent一定存在
|
||||
CommonItem targetGroup = catHistory.last;
|
||||
|
||||
|
||||
// 继续搜索显示下一级depth: depth + 1, parentId: parentCat.id
|
||||
List<Cat> _categories =
|
||||
await catControl.getList(new Cat(parentId: parentCat.id));
|
||||
List<WidgetPoint> _widgetPoints = new List();
|
||||
if (_categories.isEmpty) {
|
||||
_widgetPoints =
|
||||
await widgetControl.getList(new WidgetPoint(catId: parentCat.id));
|
||||
}
|
||||
|
||||
this.setState(() {
|
||||
categories = _categories;
|
||||
title = parentCat.name;
|
||||
widgetPoints = _widgetPoints;
|
||||
title = targetGroup.name;
|
||||
});
|
||||
}
|
||||
|
||||
void onCatgoryTap(Cat cat) {
|
||||
void onCatgoryTap(CommonItem cat) {
|
||||
go(cat);
|
||||
}
|
||||
|
||||
void onWidgetTap(WidgetPoint widgetPoint) {
|
||||
String targetName = widgetPoint.name;
|
||||
String targetRouter = '/category/error/404';
|
||||
widgetDemosList.forEach((item) {
|
||||
// print("targetRouter = item.routerName> ${[item.name,targetName]}");
|
||||
if (item.name == targetName) {
|
||||
targetRouter = item.routerName;
|
||||
}
|
||||
});
|
||||
Application.router.navigateTo(context, "$targetRouter");
|
||||
}
|
||||
|
||||
|
||||
Widget _buildContent() {
|
||||
WidgetItemContainer wiContaienr = WidgetItemContainer(
|
||||
columnCount: 3,
|
||||
categories: categories,
|
||||
isWidgetPoint:false
|
||||
commonItems: items
|
||||
);
|
||||
if (widgetPoints.length > 0) {
|
||||
wiContaienr = WidgetItemContainer(
|
||||
categories: widgetPoints,
|
||||
columnCount: 3,
|
||||
isWidgetPoint:true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(bottom: 10.0, top: 5.0),
|
||||
decoration: BoxDecoration(
|
||||
@ -122,14 +102,18 @@ class _CategoryHome extends State<CategoryHome> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(title),
|
||||
title: Text("$title"),
|
||||
),
|
||||
body: WillPopScope(
|
||||
|
||||
onWillPop: () {
|
||||
return back();
|
||||
},
|
||||
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
_buildContent(),
|
||||
|
27
lib/components/flutter_markdown/LICENSE
Normal file
27
lib/components/flutter_markdown/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2017 Google, Inc. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
39
lib/components/flutter_markdown/README.md
Normal file
39
lib/components/flutter_markdown/README.md
Normal file
@ -0,0 +1,39 @@
|
||||
# Flutter Markdown
|
||||
[](https://pub.dartlang.org/packages/flutter_markdown)
|
||||
[](https://travis-ci.org/flutter/flutter_markdown)
|
||||
|
||||
|
||||
A markdown renderer for Flutter. It supports the
|
||||
[original format](https://daringfireball.net/projects/markdown/), but no inline
|
||||
html.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Using the Markdown widget is simple, just pass in the source markdown as a
|
||||
string:
|
||||
|
||||
new Markdown(data: markdownSource);
|
||||
|
||||
If you do not want the padding or scrolling behavior, use the MarkdownBody
|
||||
instead:
|
||||
|
||||
new MarkdownBody(data: markdownSource);
|
||||
|
||||
By default, Markdown uses the formatting from the current material design theme,
|
||||
but it's possible to create your own custom styling. Use the MarkdownStyle class
|
||||
to pass in your own style. If you don't want to use Markdown outside of material
|
||||
design, use the MarkdownRaw class.
|
||||
|
||||
## Image support
|
||||
|
||||
The `Img` tag only supports the following image locations:
|
||||
|
||||
* From the network: Use a URL prefixed by either `http://` or `https://`.
|
||||
|
||||
* From local files on the device: Use an absolute path to the file, for example by
|
||||
concatenating the file name with the path returned by a known storage location,
|
||||
such as those provided by the [`path_provider`](https://pub.dartlang.org/packages/path_provider)
|
||||
plugin.
|
||||
|
||||
* From image locations referring to bundled assets: Use an asset name prefixed by `resource:`.
|
||||
like `resource:assets/image.png`.
|
10
lib/components/flutter_markdown/lib/flutter_markdown.dart
Normal file
10
lib/components/flutter_markdown/lib/flutter_markdown.dart
Normal file
@ -0,0 +1,10 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// A library to render markdown formatted text.
|
||||
library flutter_markdown;
|
||||
|
||||
export 'src/builder.dart';
|
||||
export 'src/style_sheet.dart';
|
||||
export 'src/widget.dart';
|
376
lib/components/flutter_markdown/lib/src/builder.dart
Normal file
376
lib/components/flutter_markdown/lib/src/builder.dart
Normal file
@ -0,0 +1,376 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:markdown/markdown.dart' as md;
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'style_sheet.dart';
|
||||
|
||||
typedef Widget DemoBuilder(Map<String, dynamic> attrs);
|
||||
|
||||
final Set<String> _kBlockTags = new Set<String>.from(<String>[
|
||||
'p',
|
||||
'h1',
|
||||
'h2',
|
||||
'h3',
|
||||
'h4',
|
||||
'h5',
|
||||
'h6',
|
||||
'li',
|
||||
'blockquote',
|
||||
'pre',
|
||||
'ol',
|
||||
'ul',
|
||||
'hr',
|
||||
]);
|
||||
|
||||
const List<String> _kListTags = const <String>['ul', 'ol'];
|
||||
|
||||
bool _isBlockTag(String tag) => _kBlockTags.contains(tag);
|
||||
bool _isListTag(String tag) => _kListTags.contains(tag);
|
||||
|
||||
class _BlockElement {
|
||||
_BlockElement(this.tag);
|
||||
|
||||
final String tag;
|
||||
final List<Widget> children = <Widget>[];
|
||||
|
||||
int nextListIndex = 0;
|
||||
}
|
||||
|
||||
/// A collection of widgets that should be placed adjacent to (inline with)
|
||||
/// other inline elements in the same parent block.
|
||||
///
|
||||
/// Inline elements can be textual (a/em/strong) represented by [RichText]
|
||||
/// widgets or images (img) represented by [Image.network] widgets.
|
||||
///
|
||||
/// Inline elements can be nested within other inline elements, inheriting their
|
||||
/// parent's style along with the style of the block they are in.
|
||||
///
|
||||
/// When laying out inline widgets, first, any adjacent RichText widgets are
|
||||
/// merged, then, all inline widgets are enclosed in a parent [Wrap] widget.
|
||||
class _InlineElement {
|
||||
_InlineElement(this.tag, {this.style});
|
||||
|
||||
final String tag;
|
||||
|
||||
/// Created by merging the style defined for this element's [tag] in the
|
||||
/// delegate's [MarkdownStyleSheet] with the style of its parent.
|
||||
final TextStyle style;
|
||||
|
||||
final List<Widget> children = <Widget>[];
|
||||
}
|
||||
|
||||
/// A delegate used by [MarkdownBuilder] to control the widgets it creates.
|
||||
abstract class MarkdownBuilderDelegate {
|
||||
/// Returns a gesture recognizer to use for an `a` element with the given
|
||||
/// `href` attribute.
|
||||
GestureRecognizer createLink(String href);
|
||||
|
||||
/// Returns formatted text to use to display the given contents of a `pre`
|
||||
/// element.
|
||||
///
|
||||
/// The `styleSheet` is the value of [MarkdownBuilder.styleSheet].
|
||||
TextSpan formatText(MarkdownStyleSheet styleSheet, String code);
|
||||
}
|
||||
|
||||
/// Builds a [Widget] tree from parsed Markdown.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Markdown], which is a widget that parses and displays Markdown.
|
||||
class MarkdownBuilder implements md.NodeVisitor {
|
||||
/// Creates an object that builds a [Widget] tree from parsed Markdown.
|
||||
MarkdownBuilder({
|
||||
this.delegate,
|
||||
this.styleSheet,
|
||||
this.imageDirectory,
|
||||
this.demoParser
|
||||
});
|
||||
|
||||
/// A delegate that controls how link and `pre` elements behave.
|
||||
final MarkdownBuilderDelegate delegate;
|
||||
|
||||
/// Defines which [TextStyle] objects to use for each type of element.
|
||||
final MarkdownStyleSheet styleSheet;
|
||||
|
||||
final DemoBuilder demoParser;
|
||||
/// The base directory holding images referenced by Img tags with local file paths.
|
||||
final Directory imageDirectory;
|
||||
|
||||
final List<String> _listIndents = <String>[];
|
||||
final List<_BlockElement> _blocks = <_BlockElement>[];
|
||||
final List<_InlineElement> _inlines = <_InlineElement>[];
|
||||
final List<GestureRecognizer> _linkHandlers = <GestureRecognizer>[];
|
||||
|
||||
|
||||
/// Returns widgets that display the given Markdown nodes.
|
||||
///
|
||||
/// The returned widgets are typically used as children in a [ListView].
|
||||
List<Widget> build(List<md.Node> nodes) {
|
||||
_listIndents.clear();
|
||||
_blocks.clear();
|
||||
_inlines.clear();
|
||||
_linkHandlers.clear();
|
||||
|
||||
_blocks.add(new _BlockElement(null));
|
||||
|
||||
for (md.Node node in nodes) {
|
||||
assert(_blocks.length == 1);
|
||||
node.accept(this);
|
||||
}
|
||||
|
||||
assert(_inlines.isEmpty);
|
||||
return _blocks.single.children;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitText(md.Text text) {
|
||||
if (_blocks.last.tag == null) // Don't allow text directly under the root.
|
||||
return;
|
||||
|
||||
_addParentInlineIfNeeded(_blocks.last.tag);
|
||||
|
||||
final TextSpan span = _blocks.last.tag == 'pre'
|
||||
? delegate.formatText(styleSheet, text.text)
|
||||
: new TextSpan(
|
||||
style: _inlines.last.style,
|
||||
text: text.text,
|
||||
recognizer: _linkHandlers.isNotEmpty ? _linkHandlers.last : null,
|
||||
);
|
||||
|
||||
_inlines.last.children.add(new RichText(
|
||||
textScaleFactor: styleSheet.textScaleFactor,
|
||||
text: span,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
bool visitElementBefore(md.Element element) {
|
||||
// print("visitElementBefore ${element.tag}");
|
||||
final String tag = element.tag;
|
||||
if (_isBlockTag(tag)) {
|
||||
_addAnonymousBlockIfNeeded(styleSheet.styles[tag]);
|
||||
if (_isListTag(tag))
|
||||
_listIndents.add(tag);
|
||||
_blocks.add(new _BlockElement(tag));
|
||||
} else {
|
||||
_addParentInlineIfNeeded(_blocks.last.tag);
|
||||
|
||||
TextStyle parentStyle = _inlines.last.style;
|
||||
_inlines.add(new _InlineElement(
|
||||
tag,
|
||||
style: parentStyle.merge(styleSheet.styles[tag]),
|
||||
));
|
||||
}
|
||||
|
||||
if (tag == 'a') {
|
||||
_linkHandlers.add(delegate.createLink(element.attributes['href']));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
void visitElementAfter(md.Element element) {
|
||||
final String tag = element.tag;
|
||||
if (_isBlockTag(tag)) {
|
||||
_addAnonymousBlockIfNeeded(styleSheet.styles[tag]);
|
||||
|
||||
final _BlockElement current = _blocks.removeLast();
|
||||
Widget child;
|
||||
|
||||
if (current.children.isNotEmpty) {
|
||||
child = new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: current.children,
|
||||
);
|
||||
} else {
|
||||
child = const SizedBox();
|
||||
}
|
||||
|
||||
if (_isListTag(tag)) {
|
||||
assert(_listIndents.isNotEmpty);
|
||||
_listIndents.removeLast();
|
||||
} else if (tag == 'li') {
|
||||
if (_listIndents.isNotEmpty) {
|
||||
child = new Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
new SizedBox(
|
||||
width: styleSheet.listIndent,
|
||||
child: _buildBullet(_listIndents.last),
|
||||
),
|
||||
new Expanded(child: child)
|
||||
],
|
||||
);
|
||||
}
|
||||
} else if (tag == 'blockquote') {
|
||||
child = new DecoratedBox(
|
||||
decoration: styleSheet.blockquoteDecoration,
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.all(styleSheet.blockquotePadding),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
} else if (tag == 'pre') {
|
||||
child = new DecoratedBox(
|
||||
decoration: styleSheet.codeblockDecoration,
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.all(styleSheet.codeblockPadding),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
} else if (tag == 'hr') {
|
||||
child = new DecoratedBox(
|
||||
decoration: styleSheet.horizontalRuleDecoration,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
_addBlockChild(child);
|
||||
} else {
|
||||
|
||||
final _InlineElement current = _inlines.removeLast();
|
||||
final _InlineElement parent = _inlines.last;
|
||||
|
||||
if (tag == 'img') {
|
||||
// create an image widget for this image
|
||||
current.children.add(_buildImage(element.attributes['src']));
|
||||
} else if (tag == 'a') {
|
||||
_linkHandlers.removeLast();
|
||||
} else if (tag == 'demo') {
|
||||
current.children.add(_buildGoDemos(element.attributes));
|
||||
}
|
||||
|
||||
|
||||
if (current.children.isNotEmpty) {
|
||||
parent.children.addAll(current.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
Widget _buildGoDemos(Map<String, dynamic> attrs) {
|
||||
Widget targetGoDemos;
|
||||
|
||||
if (demoParser != null) {
|
||||
targetGoDemos = demoParser(attrs);
|
||||
}
|
||||
|
||||
return targetGoDemos ?? new Text('demo not exits');
|
||||
}
|
||||
|
||||
Widget _buildImage(String src) {
|
||||
final List<String> parts = src.split('#');
|
||||
if (parts.isEmpty)
|
||||
return const SizedBox();
|
||||
|
||||
final String path = parts.first;
|
||||
double width;
|
||||
double height;
|
||||
if (parts.length == 2) {
|
||||
final List<String> dimensions = parts.last.split('x');
|
||||
if (dimensions.length == 2) {
|
||||
width = double.parse(dimensions[0]);
|
||||
height = double.parse(dimensions[1]);
|
||||
}
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(path);
|
||||
Widget child;
|
||||
if (uri.scheme == 'http' || uri.scheme == 'https') {
|
||||
child = new Image.network(uri.toString(), width: width, height: height);
|
||||
} else if (uri.scheme == 'data') {
|
||||
child = _handleDataSchemeUri(uri, width, height);
|
||||
} else if (uri.scheme == "resource") {
|
||||
child = new Image.asset(path.substring(9), width: width, height: height);
|
||||
} else {
|
||||
String filePath = (imageDirectory == null
|
||||
? uri.toFilePath()
|
||||
: p.join(imageDirectory.path, uri.toFilePath()));
|
||||
child = new Image.file(new File(filePath), width: width, height: height);
|
||||
}
|
||||
|
||||
if (_linkHandlers.isNotEmpty) {
|
||||
TapGestureRecognizer recognizer = _linkHandlers.last;
|
||||
return new GestureDetector(child: child, onTap: recognizer.onTap);
|
||||
} else {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
Widget _handleDataSchemeUri(Uri uri, final double width, final double height) {
|
||||
final String mimeType = uri.data.mimeType;
|
||||
if (mimeType.startsWith('image/')) {
|
||||
return new Image.memory(uri.data.contentAsBytes(), width: width, height: height);
|
||||
} else if (mimeType.startsWith('text/')) {
|
||||
return new Text(uri.data.contentAsString());
|
||||
}
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
Widget _buildBullet(String listTag) {
|
||||
if (listTag == 'ul')
|
||||
return new Text('•', textAlign: TextAlign.center, style: styleSheet.styles['li']);
|
||||
|
||||
final int index = _blocks.last.nextListIndex;
|
||||
return new Padding(
|
||||
padding: const EdgeInsets.only(right: 5.0),
|
||||
child: new Text('${index + 1}.', textAlign: TextAlign.right, style: styleSheet.styles['li']),
|
||||
);
|
||||
}
|
||||
|
||||
void _addParentInlineIfNeeded(String tag) {
|
||||
if (_inlines.isEmpty) {
|
||||
_inlines.add(new _InlineElement(
|
||||
tag,
|
||||
style: styleSheet.styles[tag],
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
void _addBlockChild(Widget child) {
|
||||
final _BlockElement parent = _blocks.last;
|
||||
if (parent.children.isNotEmpty)
|
||||
parent.children.add(new SizedBox(height: styleSheet.blockSpacing));
|
||||
parent.children.add(child);
|
||||
parent.nextListIndex += 1;
|
||||
}
|
||||
|
||||
void _addAnonymousBlockIfNeeded(TextStyle style) {
|
||||
if (_inlines.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final _InlineElement inline = _inlines.single;
|
||||
if (inline.children.isNotEmpty) {
|
||||
List<Widget> mergedInlines = _mergeInlineChildren(inline);
|
||||
final Wrap wrap = new Wrap(children: mergedInlines);
|
||||
_addBlockChild(wrap);
|
||||
_inlines.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Merges adjacent [TextSpan] children of the given [_InlineElement]
|
||||
List<Widget> _mergeInlineChildren(_InlineElement inline) {
|
||||
List<Widget> mergedTexts = <Widget>[];
|
||||
for (Widget child in inline.children) {
|
||||
if (mergedTexts.isNotEmpty && mergedTexts.last is RichText && child is RichText) {
|
||||
RichText previous = mergedTexts.removeLast();
|
||||
List<TextSpan> children = previous.text.children != null
|
||||
? new List.from(previous.text.children)
|
||||
: [previous.text];
|
||||
children.add(child.text);
|
||||
TextSpan mergedSpan = new TextSpan(children: children);
|
||||
mergedTexts.add(new RichText(
|
||||
textScaleFactor: styleSheet.textScaleFactor,
|
||||
text: mergedSpan,
|
||||
));
|
||||
} else {
|
||||
mergedTexts.add(child);
|
||||
}
|
||||
}
|
||||
return mergedTexts;
|
||||
}
|
||||
}
|
307
lib/components/flutter_markdown/lib/src/style_sheet.dart
Normal file
307
lib/components/flutter_markdown/lib/src/style_sheet.dart
Normal file
@ -0,0 +1,307 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Defines which [TextStyle] objects to use for which Markdown elements.
|
||||
class MarkdownStyleSheet {
|
||||
/// Creates an explicit mapping of [TextStyle] objects to Markdown elements.
|
||||
MarkdownStyleSheet({
|
||||
this.a,
|
||||
this.p,
|
||||
this.code,
|
||||
this.h1,
|
||||
this.h2,
|
||||
this.h3,
|
||||
this.h4,
|
||||
this.h5,
|
||||
this.h6,
|
||||
this.em,
|
||||
this.strong,
|
||||
this.blockquote,
|
||||
this.img,
|
||||
this.blockSpacing,
|
||||
this.listIndent,
|
||||
this.blockquotePadding,
|
||||
this.blockquoteDecoration,
|
||||
this.codeblockPadding,
|
||||
this.codeblockDecoration,
|
||||
this.horizontalRuleDecoration,
|
||||
this.textScaleFactor = 1.0
|
||||
}) : _styles = <String, TextStyle>{
|
||||
'a': a,
|
||||
'p': p,
|
||||
'li': p,
|
||||
'code': code,
|
||||
'pre': p,
|
||||
'h1': h1,
|
||||
'h2': h2,
|
||||
'h3': h3,
|
||||
'h4': h4,
|
||||
'h5': h5,
|
||||
'h6': h6,
|
||||
'em': em,
|
||||
'strong': strong,
|
||||
'blockquote': blockquote,
|
||||
'img': img,
|
||||
};
|
||||
|
||||
/// Creates a [MarkdownStyleSheet] from the [TextStyle]s in the provided [ThemeData].
|
||||
factory MarkdownStyleSheet.fromTheme(ThemeData theme) {
|
||||
assert(theme?.textTheme?.body1?.fontSize != null);
|
||||
return new MarkdownStyleSheet(
|
||||
a: const TextStyle(color: Colors.blue),
|
||||
p: theme.textTheme.body1,
|
||||
code: new TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
fontFamily: "monospace",
|
||||
fontSize: theme.textTheme.body1.fontSize * 0.85
|
||||
),
|
||||
h1: theme.textTheme.headline,
|
||||
h2: theme.textTheme.title,
|
||||
h3: theme.textTheme.subhead,
|
||||
h4: theme.textTheme.body2,
|
||||
h5: theme.textTheme.body2,
|
||||
h6: theme.textTheme.body2,
|
||||
em: const TextStyle(fontStyle: FontStyle.italic),
|
||||
strong: const TextStyle(fontWeight: FontWeight.bold),
|
||||
blockquote: theme.textTheme.body1,
|
||||
img: theme.textTheme.body1,
|
||||
blockSpacing: 8.0,
|
||||
listIndent: 32.0,
|
||||
blockquotePadding: 8.0,
|
||||
blockquoteDecoration: new BoxDecoration(
|
||||
color: Colors.blue.shade100,
|
||||
borderRadius: new BorderRadius.circular(2.0)
|
||||
),
|
||||
codeblockPadding: 8.0,
|
||||
codeblockDecoration: new BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: new BorderRadius.circular(2.0)
|
||||
),
|
||||
horizontalRuleDecoration: new BoxDecoration(
|
||||
border: new Border(
|
||||
top: new BorderSide(width: 5.0, color: Colors.grey.shade300)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a [MarkdownStyle] from the [TextStyle]s in the provided [ThemeData].
|
||||
///
|
||||
/// This constructor uses larger fonts for the headings than in
|
||||
/// [MarkdownStyle.fromTheme].
|
||||
factory MarkdownStyleSheet.largeFromTheme(ThemeData theme) {
|
||||
return new MarkdownStyleSheet(
|
||||
a: const TextStyle(color: Colors.blue),
|
||||
p: theme.textTheme.body1,
|
||||
code: new TextStyle(
|
||||
color: Colors.grey.shade700,
|
||||
fontFamily: "monospace",
|
||||
fontSize: theme.textTheme.body1.fontSize * 0.85
|
||||
),
|
||||
h1: theme.textTheme.display3,
|
||||
h2: theme.textTheme.display2,
|
||||
h3: theme.textTheme.display1,
|
||||
h4: theme.textTheme.headline,
|
||||
h5: theme.textTheme.title,
|
||||
h6: theme.textTheme.subhead,
|
||||
em: const TextStyle(fontStyle: FontStyle.italic),
|
||||
strong: const TextStyle(fontWeight: FontWeight.bold),
|
||||
blockquote: theme.textTheme.body1,
|
||||
img: theme.textTheme.body1,
|
||||
blockSpacing: 8.0,
|
||||
listIndent: 32.0,
|
||||
blockquotePadding: 8.0,
|
||||
blockquoteDecoration: new BoxDecoration(
|
||||
color: Colors.blue.shade100,
|
||||
borderRadius: new BorderRadius.circular(2.0)
|
||||
),
|
||||
codeblockPadding: 8.0,
|
||||
codeblockDecoration: new BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: new BorderRadius.circular(2.0)
|
||||
),
|
||||
horizontalRuleDecoration: new BoxDecoration(
|
||||
border: new Border(
|
||||
top: new BorderSide(width: 5.0, color: Colors.grey.shade300)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates a new [MarkdownStyleSheet] based on the current style, with the
|
||||
/// provided parameters overridden.
|
||||
MarkdownStyleSheet copyWith({
|
||||
TextStyle a,
|
||||
TextStyle p,
|
||||
TextStyle code,
|
||||
TextStyle h1,
|
||||
TextStyle h2,
|
||||
TextStyle h3,
|
||||
TextStyle h4,
|
||||
TextStyle h5,
|
||||
TextStyle h6,
|
||||
TextStyle em,
|
||||
TextStyle strong,
|
||||
TextStyle blockquote,
|
||||
TextStyle img,
|
||||
double blockSpacing,
|
||||
double listIndent,
|
||||
double blockquotePadding,
|
||||
Decoration blockquoteDecoration,
|
||||
double codeblockPadding,
|
||||
Decoration codeblockDecoration,
|
||||
Decoration horizontalRuleDecoration,
|
||||
double textScaleFactor,
|
||||
}) {
|
||||
return new MarkdownStyleSheet(
|
||||
a: a ?? this.a,
|
||||
p: p ?? this.p,
|
||||
code: code ?? this.code,
|
||||
h1: h1 ?? this.h1,
|
||||
h2: h2 ?? this.h2,
|
||||
h3: h3 ?? this.h3,
|
||||
h4: h4 ?? this.h4,
|
||||
h5: h5 ?? this.h5,
|
||||
h6: h6 ?? this.h6,
|
||||
em: em ?? this.em,
|
||||
strong: strong ?? this.strong,
|
||||
blockquote: blockquote ?? this.blockquote,
|
||||
img: img ?? this.img,
|
||||
blockSpacing: blockSpacing ?? this.blockSpacing,
|
||||
listIndent: listIndent ?? this.listIndent,
|
||||
blockquotePadding: blockquotePadding ?? this.blockquotePadding,
|
||||
blockquoteDecoration: blockquoteDecoration ?? this.blockquoteDecoration,
|
||||
codeblockPadding: codeblockPadding ?? this.codeblockPadding,
|
||||
codeblockDecoration: codeblockDecoration ?? this.codeblockDecoration,
|
||||
horizontalRuleDecoration: horizontalRuleDecoration ?? this.horizontalRuleDecoration,
|
||||
textScaleFactor : textScaleFactor ?? this.textScaleFactor,
|
||||
);
|
||||
}
|
||||
|
||||
/// The [TextStyle] to use for `a` elements.
|
||||
final TextStyle a;
|
||||
|
||||
/// The [TextStyle] to use for `p` elements.
|
||||
final TextStyle p;
|
||||
|
||||
/// The [TextStyle] to use for `code` elements.
|
||||
final TextStyle code;
|
||||
|
||||
/// The [TextStyle] to use for `h1` elements.
|
||||
final TextStyle h1;
|
||||
|
||||
/// The [TextStyle] to use for `h2` elements.
|
||||
final TextStyle h2;
|
||||
|
||||
/// The [TextStyle] to use for `h3` elements.
|
||||
final TextStyle h3;
|
||||
|
||||
/// The [TextStyle] to use for `h4` elements.
|
||||
final TextStyle h4;
|
||||
|
||||
/// The [TextStyle] to use for `h5` elements.
|
||||
final TextStyle h5;
|
||||
|
||||
/// The [TextStyle] to use for `h6` elements.
|
||||
final TextStyle h6;
|
||||
|
||||
/// The [TextStyle] to use for `em` elements.
|
||||
final TextStyle em;
|
||||
|
||||
/// The [TextStyle] to use for `strong` elements.
|
||||
final TextStyle strong;
|
||||
|
||||
/// The [TextStyle] to use for `blockquote` elements.
|
||||
final TextStyle blockquote;
|
||||
|
||||
/// The [TextStyle] to use for `img` elements.
|
||||
final TextStyle img;
|
||||
|
||||
/// The amount of vertical space to use between block-level elements.
|
||||
final double blockSpacing;
|
||||
|
||||
/// The amount of horizontal space to indent list items.
|
||||
final double listIndent;
|
||||
|
||||
/// The padding to use for `blockquote` elements.
|
||||
final double blockquotePadding;
|
||||
|
||||
/// The decoration to use behind `blockquote` elements.
|
||||
final Decoration blockquoteDecoration;
|
||||
|
||||
/// The padding to use for `pre` elements.
|
||||
final double codeblockPadding;
|
||||
|
||||
/// The decoration to use behind for `pre` elements.
|
||||
final Decoration codeblockDecoration;
|
||||
|
||||
/// The decoration to use for `hr` elements.
|
||||
final Decoration horizontalRuleDecoration;
|
||||
|
||||
// The text scale factor to use in textual elements
|
||||
final double textScaleFactor;
|
||||
|
||||
/// A [Map] from element name to the corresponding [TextStyle] object.
|
||||
Map<String, TextStyle> get styles => _styles;
|
||||
Map<String, TextStyle> _styles;
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
if (identical(this, other))
|
||||
return true;
|
||||
if (other.runtimeType != MarkdownStyleSheet)
|
||||
return false;
|
||||
final MarkdownStyleSheet typedOther = other;
|
||||
return typedOther.a == a
|
||||
&& typedOther.p == p
|
||||
&& typedOther.code == code
|
||||
&& typedOther.h1 == h1
|
||||
&& typedOther.h2 == h2
|
||||
&& typedOther.h3 == h3
|
||||
&& typedOther.h4 == h4
|
||||
&& typedOther.h5 == h5
|
||||
&& typedOther.h6 == h6
|
||||
&& typedOther.em == em
|
||||
&& typedOther.strong == strong
|
||||
&& typedOther.blockquote == blockquote
|
||||
&& typedOther.img == img
|
||||
&& typedOther.blockSpacing == blockSpacing
|
||||
&& typedOther.listIndent == listIndent
|
||||
&& typedOther.blockquotePadding == blockquotePadding
|
||||
&& typedOther.blockquoteDecoration == blockquoteDecoration
|
||||
&& typedOther.codeblockPadding == codeblockPadding
|
||||
&& typedOther.codeblockDecoration == codeblockDecoration
|
||||
&& typedOther.horizontalRuleDecoration == horizontalRuleDecoration
|
||||
&& typedOther.textScaleFactor == textScaleFactor;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return hashList([
|
||||
a,
|
||||
p,
|
||||
code,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
em,
|
||||
strong,
|
||||
blockquote,
|
||||
img,
|
||||
blockSpacing,
|
||||
listIndent,
|
||||
blockquotePadding,
|
||||
blockquoteDecoration,
|
||||
codeblockPadding,
|
||||
codeblockDecoration,
|
||||
horizontalRuleDecoration,
|
||||
textScaleFactor,
|
||||
]);
|
||||
}
|
||||
}
|
247
lib/components/flutter_markdown/lib/src/widget.dart
Normal file
247
lib/components/flutter_markdown/lib/src/widget.dart
Normal file
@ -0,0 +1,247 @@
|
||||
// Copyright 2016 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:markdown/markdown.dart' as md;
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'builder.dart';
|
||||
import 'style_sheet.dart';
|
||||
//
|
||||
typedef Widget ItemDemoBuilder(Map<String, dynamic> attrs);
|
||||
|
||||
/// Signature for callbacks used by [MarkdownWidget] when the user taps a link.
|
||||
///
|
||||
/// Used by [MarkdownWidget.onTapLink].
|
||||
typedef void MarkdownTapLinkCallback(String href);
|
||||
|
||||
/// Creates a format [TextSpan] given a string.
|
||||
///
|
||||
/// Used by [MarkdownWidget] to highlight the contents of `pre` elements.
|
||||
abstract class SyntaxHighlighter { // ignore: one_member_abstracts
|
||||
/// Returns the formated [TextSpan] for the given string.
|
||||
TextSpan format(String source);
|
||||
}
|
||||
|
||||
/// A base class for widgets that parse and display Markdown.
|
||||
///
|
||||
/// Supports all standard Markdown from the original
|
||||
/// [Markdown specification](https://daringfireball.net/projects/markdown/).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Markdown], which is a scrolling container of Markdown.
|
||||
/// * [MarkdownBody], which is a non-scrolling container of Markdown.
|
||||
/// * <https://daringfireball.net/projects/markdown/>
|
||||
abstract class MarkdownWidget extends StatefulWidget {
|
||||
/// Creates a widget that parses and displays Markdown.
|
||||
///
|
||||
/// The [data] argument must not be null.
|
||||
const MarkdownWidget({
|
||||
Key key,
|
||||
@required this.data,
|
||||
this.styleSheet,
|
||||
this.syntaxHighlighter,
|
||||
this.onTapLink,
|
||||
this.imageDirectory,
|
||||
this.demoBuilder,
|
||||
}) : assert(data != null),
|
||||
super(key: key);
|
||||
|
||||
/// The Markdown to display.
|
||||
final String data;
|
||||
|
||||
/// The styles to use when displaying the Markdown.
|
||||
///
|
||||
/// If null, the styles are inferred from the current [Theme].
|
||||
final MarkdownStyleSheet styleSheet;
|
||||
|
||||
/// The syntax highlighter used to color text in `pre` elements.
|
||||
///
|
||||
/// If null, the [MarkdownStyleSheet.code] style is used for `pre` elements.
|
||||
final SyntaxHighlighter syntaxHighlighter;
|
||||
|
||||
/// Called when the user taps a link.
|
||||
final MarkdownTapLinkCallback onTapLink;
|
||||
|
||||
/// The base directory holding images referenced by Img tags with local file paths.
|
||||
final Directory imageDirectory;
|
||||
|
||||
final ItemDemoBuilder demoBuilder;
|
||||
/// Subclasses should override this function to display the given children,
|
||||
/// which are the parsed representation of [data].
|
||||
@protected
|
||||
Widget build(BuildContext context, List<Widget> children);
|
||||
|
||||
@override
|
||||
_MarkdownWidgetState createState() => new _MarkdownWidgetState();
|
||||
}
|
||||
|
||||
class DemosSyntax extends md.InlineSyntax {
|
||||
DemosSyntax() : super('\\[demo:([a-z0-9_+-]+)\\]');
|
||||
bool onMatch(parser, match) {
|
||||
var anchor = new md.Element.empty('demo');
|
||||
anchor.attributes['id'] = match[1];
|
||||
parser.addNode(anchor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class _MarkdownWidgetState extends State<MarkdownWidget> implements MarkdownBuilderDelegate {
|
||||
List<Widget> _children;
|
||||
final List<GestureRecognizer> _recognizers = <GestureRecognizer>[];
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_parseMarkdown();
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(MarkdownWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.data != oldWidget.data
|
||||
|| widget.styleSheet != oldWidget.styleSheet)
|
||||
_parseMarkdown();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposeRecognizers();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _parseMarkdown() {
|
||||
final MarkdownStyleSheet styleSheet = widget.styleSheet ?? new MarkdownStyleSheet.fromTheme(Theme.of(context));
|
||||
|
||||
_disposeRecognizers();
|
||||
|
||||
// TODO: This can be optimized by doing the split and removing \r at the same time
|
||||
final List<String> lines = widget.data.replaceAll('\r\n', '\n').split('\n');
|
||||
final md.ExtensionSet extens = new md.ExtensionSet([
|
||||
md.FencedCodeBlockSyntax()
|
||||
], [
|
||||
new DemosSyntax(),
|
||||
new md.InlineHtmlSyntax(),
|
||||
]);
|
||||
final md.Document document = new md.Document(encodeHtml: false, extensionSet: extens);
|
||||
final MarkdownBuilder builder = new MarkdownBuilder(
|
||||
delegate: this,
|
||||
styleSheet: styleSheet,
|
||||
imageDirectory: widget.imageDirectory,
|
||||
demoParser: widget.demoBuilder
|
||||
);
|
||||
_children = builder.build(document.parseLines(lines));
|
||||
}
|
||||
|
||||
void _disposeRecognizers() {
|
||||
if (_recognizers.isEmpty)
|
||||
return;
|
||||
final List<GestureRecognizer> localRecognizers = new List<GestureRecognizer>.from(_recognizers);
|
||||
_recognizers.clear();
|
||||
for (GestureRecognizer recognizer in localRecognizers)
|
||||
recognizer.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
GestureRecognizer createLink(String href) {
|
||||
final TapGestureRecognizer recognizer = new TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
if (widget.onTapLink != null)
|
||||
widget.onTapLink(href);
|
||||
};
|
||||
_recognizers.add(recognizer);
|
||||
return recognizer;
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan formatText(MarkdownStyleSheet styleSheet, String code) {
|
||||
if (widget.syntaxHighlighter != null)
|
||||
return widget.syntaxHighlighter.format(code);
|
||||
return new TextSpan(style: styleSheet.code, text: code);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => widget.build(context, _children);
|
||||
}
|
||||
|
||||
/// A non-scrolling widget that parses and displays Markdown.
|
||||
///
|
||||
/// Supports all standard Markdown from the original
|
||||
/// [Markdown specification](https://daringfireball.net/projects/markdown/).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Markdown], which is a scrolling container of Markdown.
|
||||
/// * <https://daringfireball.net/projects/markdown/>
|
||||
class MarkdownBody extends MarkdownWidget {
|
||||
/// Creates a non-scrolling widget that parses and displays Markdown.
|
||||
const MarkdownBody({
|
||||
Key key,
|
||||
String data,
|
||||
MarkdownStyleSheet styleSheet,
|
||||
SyntaxHighlighter syntaxHighlighter,
|
||||
MarkdownTapLinkCallback onTapLink,
|
||||
Directory imageDirectory,
|
||||
ItemDemoBuilder demoBuilder,
|
||||
}) : super(
|
||||
key: key,
|
||||
data: data,
|
||||
styleSheet: styleSheet,
|
||||
syntaxHighlighter: syntaxHighlighter,
|
||||
onTapLink: onTapLink,
|
||||
imageDirectory: imageDirectory,
|
||||
demoBuilder: demoBuilder
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, List<Widget> children) {
|
||||
if (children.length == 1)
|
||||
return children.single;
|
||||
return new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: children,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// A scrolling widget that parses and displays Markdown.
|
||||
///
|
||||
/// Supports all standard Markdown from the original
|
||||
/// [Markdown specification](https://daringfireball.net/projects/markdown/).
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MarkdownBody], which is a non-scrolling container of Markdown.
|
||||
/// * <https://daringfireball.net/projects/markdown/>
|
||||
class Markdown extends MarkdownWidget {
|
||||
/// Creates a scrolling widget that parses and displays Markdown.
|
||||
const Markdown({
|
||||
Key key,
|
||||
String data,
|
||||
MarkdownStyleSheet styleSheet,
|
||||
SyntaxHighlighter syntaxHighlighter,
|
||||
MarkdownTapLinkCallback onTapLink,
|
||||
Directory imageDirectory,
|
||||
this.padding: const EdgeInsets.all(16.0),
|
||||
}) : super(
|
||||
key: key,
|
||||
data: data,
|
||||
styleSheet: styleSheet,
|
||||
syntaxHighlighter: syntaxHighlighter,
|
||||
onTapLink: onTapLink,
|
||||
imageDirectory: imageDirectory,
|
||||
);
|
||||
|
||||
/// The amount of space by which to inset the children.
|
||||
final EdgeInsets padding;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, List<Widget> children) {
|
||||
return new ListView(padding: padding, children: children);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import 'package:flutter_markdown/flutter_markdown.dart' as md;
|
||||
import '../components/flutter_markdown/lib/flutter_markdown.dart' as md;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_go/utils/high_light_code.dart';
|
||||
|
@ -4,6 +4,7 @@
|
||||
import 'dart:core';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_go/utils/data_utils.dart';
|
||||
|
||||
import '../routers/application.dart';
|
||||
import '../routers/routers.dart';
|
||||
@ -37,7 +38,7 @@ class _WidgetDemoState extends State<WidgetDemo> {
|
||||
CollectionControlModel _collectionControl = new CollectionControlModel();
|
||||
var _collectionIcons;
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
String _router = '';
|
||||
String widgetType = 'old';
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
List<Widget> _buildContent() {
|
||||
@ -64,57 +65,67 @@ class _WidgetDemoState extends State<WidgetDemo> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_collectionControl.getRouterByName(widget.title).then((list) {
|
||||
widgetDemosList.forEach((item) {
|
||||
if (item.name == widget.title) {
|
||||
_router = item.routerName;
|
||||
// 这里不能直接 使用 ` ModalRoute.of(context)` 会产生报错
|
||||
Future.delayed(Duration.zero, () {
|
||||
String currentPath = ModalRoute.of(context).settings.name;
|
||||
if (currentPath.indexOf('/standard-page') == 0) {
|
||||
widgetType = 'standard';
|
||||
}
|
||||
Map<String, String> params = {
|
||||
'type': widgetType,
|
||||
"url": currentPath,
|
||||
"name": widget.title
|
||||
};
|
||||
DataUtils.checkCollected(params).then((result) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = result;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = list.length > 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 点击收藏按钮
|
||||
_getCollection() {
|
||||
String currentRouterPath = ModalRoute.of(context).settings.name;
|
||||
Map<String, String> params = {
|
||||
"type": widgetType,
|
||||
"url": currentRouterPath,
|
||||
"name": widget.title
|
||||
};
|
||||
if (_hasCollected) {
|
||||
// 删除操作
|
||||
_collectionControl.deleteByName(widget.title).then((result) {
|
||||
if (result > 0 && this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = false;
|
||||
});
|
||||
DataUtils.removeCollected(params, context).then((result) {
|
||||
if (result) {
|
||||
_scaffoldKey.currentState
|
||||
.showSnackBar(SnackBar(content: Text('已取消收藏')));
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, true));
|
||||
.fire(CollectionEvent(widget.title, currentRouterPath, true));
|
||||
}
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = false;
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
print('删除错误');
|
||||
});
|
||||
} else {
|
||||
// 插入操作
|
||||
_collectionControl
|
||||
.insert(Collection(name: widget.title, router: _router))
|
||||
.then((result) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = true;
|
||||
});
|
||||
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, false));
|
||||
DataUtils.addCollected(params, context).then((result) {
|
||||
if (result) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = true;
|
||||
});
|
||||
}
|
||||
|
||||
_scaffoldKey.currentState
|
||||
.showSnackBar(SnackBar(content: Text('收藏成功')));
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, currentRouterPath, false));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -158,28 +169,28 @@ class _WidgetDemoState extends State<WidgetDemo> {
|
||||
PopupMenuButton<String>(
|
||||
onSelected: _selectValue,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
const PopupMenuItem<String>(
|
||||
value: 'doc',
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
Icons.library_books,
|
||||
size: 22.0,
|
||||
),
|
||||
title: Text('查看文档'),
|
||||
),
|
||||
const PopupMenuItem<String>(
|
||||
value: 'doc',
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
Icons.library_books,
|
||||
size: 22.0,
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
const PopupMenuItem<String>(
|
||||
value: 'code',
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
Icons.code,
|
||||
size: 22.0,
|
||||
),
|
||||
title: Text('查看Demo'),
|
||||
),
|
||||
title: Text('查看文档'),
|
||||
),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
const PopupMenuItem<String>(
|
||||
value: 'code',
|
||||
child: ListTile(
|
||||
leading: Icon(
|
||||
Icons.code,
|
||||
size: 22.0,
|
||||
),
|
||||
],
|
||||
title: Text('查看Demo'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -3,56 +3,89 @@ import 'package:fluro/fluro.dart';
|
||||
import './widget_item.dart';
|
||||
import '../routers/application.dart';
|
||||
import '../widgets/index.dart';
|
||||
import '../model/widget.dart';
|
||||
|
||||
class WidgetItemContainer extends StatelessWidget {
|
||||
final int columnCount; //一行几个
|
||||
final List<dynamic> categories;
|
||||
final bool isWidgetPoint;
|
||||
final List<CommonItem> commonItems;
|
||||
// final bool isWidgetPoint;
|
||||
|
||||
// 所有的可用demos;
|
||||
final List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
|
||||
WidgetItemContainer(
|
||||
{Key key,
|
||||
@required this.categories,
|
||||
@required this.commonItems,
|
||||
@required this.columnCount,
|
||||
@required this.isWidgetPoint})
|
||||
// @required this.isWidgetPoint
|
||||
})
|
||||
: super(key: key);
|
||||
|
||||
/// 跳转goup
|
||||
void tapToGroup(CategoryComponent cate, BuildContext context) {
|
||||
Application.router
|
||||
.navigateTo(context, "/category/${cate.token}", transition: TransitionType.inFromRight);
|
||||
}
|
||||
|
||||
/// 跳转到老的widget界面
|
||||
void tapToOldWidget(WidgetLeaf leaf, BuildContext context) {
|
||||
|
||||
String targetName = leaf.name;
|
||||
String targetRouter = '/category/error/404';
|
||||
widgetDemosList.forEach((item) {
|
||||
if (item.name == targetName) {
|
||||
targetRouter = item.routerName;
|
||||
}
|
||||
});
|
||||
Application.router.navigateTo(context, targetRouter, transition: TransitionType.inFromRight);
|
||||
}
|
||||
|
||||
/// 跳转到新的标准页
|
||||
void tapToStandardPage(WidgetLeaf leaf, BuildContext context) {
|
||||
String targetRouter = '/standard-page/${leaf.pageId}';
|
||||
Application.router.navigateTo(context, targetRouter, transition: TransitionType.inFromRight);
|
||||
}
|
||||
|
||||
List<Widget> _buildColumns(context) {
|
||||
List<Widget> _listWidget = [];
|
||||
List<Widget> _listRows = [];
|
||||
int addI;
|
||||
for (int i = 0, length = categories.length; i < length; i += columnCount) {
|
||||
for (int i = 0, length = commonItems.length; i < length; i += columnCount) {
|
||||
_listRows = [];
|
||||
for (int innerI = 0; innerI < columnCount; innerI++) {
|
||||
addI = innerI + i;
|
||||
if (addI < length) {
|
||||
dynamic item = categories[addI];
|
||||
CommonItem item = commonItems[addI];
|
||||
|
||||
|
||||
_listRows.add(
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: WidgetItem(
|
||||
title: item.name,
|
||||
onTap: () {
|
||||
if (isWidgetPoint) {
|
||||
String targetName = item.name;
|
||||
String targetRouter = '/category/error/404';
|
||||
widgetDemosList.forEach((item) {
|
||||
if (item.name == targetName) {
|
||||
targetRouter = item.routerName;
|
||||
}
|
||||
});
|
||||
Application.router.navigateTo(context, "$targetRouter", transition: TransitionType.inFromRight);
|
||||
} else {
|
||||
Application.router
|
||||
.navigateTo(context, "/category/${item.name}", transition: TransitionType.inFromRight);
|
||||
String type = item.type;
|
||||
|
||||
if (type == "category") {
|
||||
return tapToGroup(item as CategoryComponent, context);
|
||||
}
|
||||
if (type == "widget") {
|
||||
WidgetLeaf leaf = item as WidgetLeaf;
|
||||
|
||||
if (leaf.display == "standard") {
|
||||
return tapToStandardPage(leaf, context);
|
||||
} else {
|
||||
return tapToOldWidget(leaf, context);
|
||||
}
|
||||
}
|
||||
|
||||
Application.router
|
||||
.navigateTo(context, "/category/error/404", transition: TransitionType.inFromRight);
|
||||
},
|
||||
index: addI,
|
||||
totalCount: length,
|
||||
rowLength: columnCount,
|
||||
textSize: isWidgetPoint ? 'middle' : 'small',
|
||||
textSize: true ? 'middle' : 'small',
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -81,3 +114,4 @@ class WidgetItemContainer extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import 'package:flutter_jpush/flutter_jpush.dart';
|
||||
import 'package:flutter_go/event/event_bus.dart';
|
||||
import 'package:flutter_go/event/event_model.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:flutter_go/model/widget.dart';
|
||||
|
||||
//import 'views/welcome_page/index.dart';
|
||||
|
||||
@ -25,9 +26,9 @@ var db;
|
||||
class MyApp extends StatefulWidget {
|
||||
MyApp() {
|
||||
final router = new Router();
|
||||
|
||||
Routes.configureRoutes(router);
|
||||
|
||||
// 这里设置项目环境
|
||||
Application.env = ENV.PRODUCTION;
|
||||
Application.router = router;
|
||||
}
|
||||
|
||||
@ -128,7 +129,6 @@ class _MyAppState extends State<MyApp> {
|
||||
});
|
||||
print('身份信息验证失败:$onError');
|
||||
});
|
||||
|
||||
ApplicationEvent.event.on<UserSettingThemeColorEvent>().listen((event) {
|
||||
print('接收到的 event $event');
|
||||
});
|
||||
@ -154,8 +154,9 @@ class _MyAppState extends State<MyApp> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// WidgetTree.getCommonItemByPath([15, 17], Application.widgetTree);
|
||||
return new MaterialApp(
|
||||
title: 'title',
|
||||
title: 'titles',
|
||||
theme: new ThemeData(
|
||||
primaryColor: Color(this.themeColor),
|
||||
backgroundColor: Color(0xFFEFEFEF),
|
||||
@ -188,6 +189,10 @@ void main() async {
|
||||
await provider.init(true);
|
||||
sp = await SpUtil.getInstance();
|
||||
new SearchHistoryList(sp);
|
||||
await DataUtils.getWidgetTreeList().then((List json) {
|
||||
if (json == null) return;
|
||||
Application.widgetTree = WidgetTree.buildWidgetTree(json);
|
||||
});
|
||||
db = Provider.db;
|
||||
runApp(new MyApp());
|
||||
}
|
||||
|
@ -49,15 +49,21 @@ class CollectionControlModel {
|
||||
List list = await sql.getByCondition();
|
||||
List<Collection> resultList = [];
|
||||
list.forEach((item){
|
||||
print(item);
|
||||
print('collection item =>> $item');
|
||||
resultList.add(Collection.fromJSON(item));
|
||||
});
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 通过收藏名获取router
|
||||
Future getRouterByName(String name) async {
|
||||
List list = await sql.getByCondition(conditions: {'name': name});
|
||||
/// 通过收藏名获取router
|
||||
/// 因为名称很容易重复. 所以这里使用path router做唯一判断
|
||||
// Future getRouterByName(String name) async {
|
||||
// List list = await sql.getByCondition(conditions: {'name': name});
|
||||
// return list;
|
||||
// }
|
||||
|
||||
Future getRouterByUrl(String path) async {
|
||||
List list = await sql.getByCondition(conditions: {'router': path});
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -65,4 +71,8 @@ class CollectionControlModel {
|
||||
Future deleteByName(String name) async{
|
||||
return await sql.delete(name,'name');
|
||||
}
|
||||
// 通过path删除
|
||||
Future deleteByPath(String path) async{
|
||||
return await sql.delete(path,'router');
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,13 @@ import "package:flutter/material.dart";
|
||||
|
||||
import 'package:flutter_go/utils/sql.dart';
|
||||
|
||||
enum treeNode {
|
||||
CategoryComponent,
|
||||
WidgetLeaf
|
||||
}
|
||||
|
||||
//typedef aaa
|
||||
|
||||
abstract class WidgetInterface {
|
||||
int get id;
|
||||
|
||||
@ -142,3 +149,182 @@ class WidgetControlModel {
|
||||
return widgets;
|
||||
}
|
||||
}
|
||||
// 抽象类
|
||||
abstract class CommonItem<T> {
|
||||
int id;
|
||||
String name;
|
||||
int parentId;
|
||||
String type;
|
||||
List<CommonItem> children;
|
||||
String token;
|
||||
|
||||
/// 父级节点, 存放整个CommonItem对象node = ! null
|
||||
///
|
||||
CommonItem parent;
|
||||
String toString() {
|
||||
return "CommonItem {name: $name, type: $type, parentId: $parentId, token: $token, children长度 ${children}";
|
||||
}
|
||||
|
||||
T getChild(String token);
|
||||
T addChildren(Object item);
|
||||
// 从children树中. 查找任意子节点
|
||||
T find(String token, [CommonItem node]);
|
||||
}
|
||||
|
||||
// tree的group树干
|
||||
class CategoryComponent extends CommonItem {
|
||||
int id;
|
||||
String name;
|
||||
int parentId;
|
||||
CommonItem parent;
|
||||
String token;
|
||||
|
||||
|
||||
List<CommonItem> children = [];
|
||||
|
||||
String type = 'category';
|
||||
|
||||
CategoryComponent({
|
||||
@required this.id,
|
||||
@required this.name,
|
||||
@required this.parentId,
|
||||
this.children,
|
||||
this.parent
|
||||
});
|
||||
CategoryComponent.fromJson(Map json) {
|
||||
this.id = int.parse(json['id']);
|
||||
this.name = json['name'];
|
||||
this.parentId = json['parentId'];
|
||||
this.token = json['id'] + json['type'];
|
||||
}
|
||||
void addChildren(Object item) {
|
||||
if (item is CategoryComponent) {
|
||||
CategoryComponent cate = item;
|
||||
cate.parent = this;
|
||||
this.children.add(
|
||||
cate
|
||||
);
|
||||
}
|
||||
if (item is WidgetLeaf) {
|
||||
WidgetLeaf widget = item;
|
||||
widget.parent = this;
|
||||
this.children.add(
|
||||
widget
|
||||
);
|
||||
}
|
||||
}
|
||||
@override
|
||||
CommonItem getChild(String token) {
|
||||
return children.firstWhere((CommonItem item) => item.token == token, orElse: () => null);
|
||||
}
|
||||
|
||||
@override
|
||||
CommonItem find(String token, [CommonItem node]) {
|
||||
CommonItem ret;
|
||||
if (node !=null) {
|
||||
if (node.token == token) {
|
||||
return node;
|
||||
} else {
|
||||
// 循环到叶子节点, 返回 空
|
||||
if (node.children == null) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < node.children.length; i++) {
|
||||
CommonItem temp = this.find(token, node.children[i]);
|
||||
if (temp != null) {
|
||||
ret = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = find(token, this);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// 叶子节点
|
||||
class WidgetLeaf extends CommonItem {
|
||||
int id;
|
||||
String name;
|
||||
int parentId;
|
||||
String display; // 展示类型, 区分老的widget文件下的详情
|
||||
String author; // 文档负责人
|
||||
String path; // 路由地址
|
||||
String pageId; // 界面ID
|
||||
CommonItem parent;
|
||||
|
||||
String type = 'widget';
|
||||
WidgetLeaf({
|
||||
@required this.id,
|
||||
@required this.name,
|
||||
@required this.display,
|
||||
this.author,
|
||||
this.path,
|
||||
this.pageId
|
||||
});
|
||||
|
||||
WidgetLeaf.fromJson(Map json) {
|
||||
this.id = int.parse(json['id']);
|
||||
this.name = json['name'];
|
||||
this.display = json['display'];
|
||||
this.author = json['author'] ?? null;
|
||||
this.path = json['path'] ?? null;
|
||||
this.pageId = json['pageId'] ?? null;
|
||||
this.token = json['id'] + json['type'];
|
||||
}
|
||||
@override
|
||||
CommonItem getChild(String token) {
|
||||
return null;
|
||||
}
|
||||
@override
|
||||
addChildren(Object item) {
|
||||
// TODO: implement addChildren
|
||||
return null;
|
||||
}
|
||||
|
||||
CommonItem find(String token, [CommonItem node]){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class WidgetTree {
|
||||
static CategoryComponent buildWidgetTree(List json, [parent]){
|
||||
CategoryComponent current;
|
||||
if (parent != null) {
|
||||
current = parent;
|
||||
} else {
|
||||
current = CategoryComponent(id: 0, name: 'root', parentId: null, children: []);
|
||||
}
|
||||
json.forEach((item) {
|
||||
|
||||
// 归属分类级别
|
||||
if (['root', 'category'].indexOf(item['type']) != -1) {
|
||||
CategoryComponent cate = CategoryComponent.fromJson(item);
|
||||
if (cate.children != null) {
|
||||
buildWidgetTree(item['children'], cate);
|
||||
}
|
||||
current.addChildren(cate);
|
||||
} else {
|
||||
// 归属最后一层叶子节点
|
||||
WidgetLeaf cate = WidgetLeaf.fromJson(item);
|
||||
current.addChildren(cate);
|
||||
}
|
||||
});
|
||||
return current;
|
||||
}
|
||||
static CategoryComponent getCommonItemById(List<int> path, CategoryComponent root) {
|
||||
print("getCommonItemByPath $path");
|
||||
print("root $root");
|
||||
CommonItem childLeaf;
|
||||
int first = path.first;
|
||||
path = path.sublist(1);
|
||||
print("path:::: $path");
|
||||
if (path.length >= 0) {
|
||||
// childLeaf = root.getChild(path.first);
|
||||
}
|
||||
|
||||
|
||||
return childLeaf;
|
||||
}
|
||||
}
|
1
lib/page_demo_package/.demo.json
Normal file
1
lib/page_demo_package/.demo.json
Normal file
@ -0,0 +1 @@
|
||||
[{"name":"demoName","screenShot":"","author":"yourName","email":"yourEmail","desc":"这是一个测试的标准demo","id":"1a29aa8e_32ae_4241_9c8a_5c9e1f92b096"}]
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "demoName",
|
||||
"screenShot": "",
|
||||
"author":"yourName",
|
||||
"email": "yourEmail",
|
||||
"desc": "这是一个测试的标准demo",
|
||||
"id": "1a29aa8e_32ae_4241_9c8a_5c9e1f92b096"
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Created with flutter go cli
|
||||
// User: yourName
|
||||
// Time: 2019-06-10 20:37:27.289097
|
||||
// email: yourEmail
|
||||
// desc: 这是一个测试的标准demo
|
||||
//
|
||||
|
||||
import 'src/index.dart';
|
||||
|
||||
var demoWidgets = [
|
||||
new Demo()
|
||||
];
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Demo extends StatefulWidget {
|
||||
@override
|
||||
_State createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<Demo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: RaisedButton(onPressed: () {}, child: Text('以下方式引入的demo'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
4
lib/page_demo_package/index.dart
Normal file
4
lib/page_demo_package/index.dart
Normal file
@ -0,0 +1,4 @@
|
||||
import 'demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096/index.dart' as StandardDemo_demoName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096;
|
||||
var demoObjects = {
|
||||
'1a29aa8e_32ae_4241_9c8a_5c9e1f92b096': StandardDemo_demoName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096.demoWidgets
|
||||
};
|
17
lib/page_demo_package/info.json
Normal file
17
lib/page_demo_package/info.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"70c429df-c27d-4843-8e28-1e6885c9276b": {
|
||||
"name": "button-red",
|
||||
"screenShot": "",
|
||||
"author": "sanfan",
|
||||
"email": "sanfan.hx@alibaba-inc.com",
|
||||
"desc": "desc",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
20
lib/page_demo_package/readme.md
Normal file
20
lib/page_demo_package/readme.md
Normal file
@ -0,0 +1,20 @@
|
||||
# 目录说明
|
||||
|
||||
本目录文件结构与文件命名, 使用cli进行更新
|
||||
|
||||
|
||||
# demos 目录文件结构
|
||||
|
||||
```
|
||||
demos
|
||||
├── ${demoName}-${author}-${32位demoID}
|
||||
│ ├── index.dart
|
||||
│ └── src
|
||||
│ ├── .demo.json
|
||||
│ └── ${demoName}.dart
|
||||
├── ...${demoName}-${author}-${32位demoID}
|
||||
├── index.dart
|
||||
├── info.json
|
||||
└── readme.md
|
||||
```
|
||||
|
@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
class WidgetName2Icon {
|
||||
static Map<String,dynamic> icons = {
|
||||
"Developer": Icons.developer_mode,
|
||||
"Standard": Icons.pages ,
|
||||
"Element":Icons.explicit,
|
||||
"Components":Icons.extension,
|
||||
"Themes":Icons.filter_b_and_w,
|
||||
"Theme":Icons.filter_b_and_w,
|
||||
"Form":Icons.table_chart,
|
||||
"Frame":Icons.aspect_ratio,
|
||||
"Media":Icons.subscriptions,
|
||||
|
@ -1,12 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluro/fluro.dart';
|
||||
|
||||
import 'package:flutter_go/utils/shared_preferences.dart';
|
||||
|
||||
import '../model/widget.dart';
|
||||
enum ENV {
|
||||
PRODUCTION,
|
||||
DEV,
|
||||
}
|
||||
class Application {
|
||||
/// 通过Application设计环境变量
|
||||
static ENV env = ENV.PRODUCTION;
|
||||
|
||||
static Router router;
|
||||
static TabController controller;
|
||||
static SpUtil sharePeferences;
|
||||
static SpUtil sharePeference;
|
||||
static CategoryComponent widgetTree;
|
||||
|
||||
static Map<String, String> github = {
|
||||
'widgetsURL':'https://github.com/alibaba/flutter-go/blob/develop/lib/widgets/',
|
||||
@ -14,4 +22,15 @@ class Application {
|
||||
//'master':'https://github.com/alibaba-paimai-frontend/flutter-common-widgets-app/tree/master/lib/widgets/'
|
||||
};
|
||||
|
||||
/// 所有获取配置的唯一入口
|
||||
Map<String, String> get config {
|
||||
if (Application.env == ENV.PRODUCTION) {
|
||||
return {};
|
||||
}
|
||||
if (Application.env == ENV.DEV) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import 'package:flutter_go/views/login_page/login_page.dart';
|
||||
import 'package:flutter_go/model/user_info.dart';
|
||||
import 'package:flutter_go/views/collection_page/collection_page.dart';
|
||||
import 'package:flutter_go/views/collection_page/collection_full_page.dart';
|
||||
|
||||
import 'package:flutter_go/views/standard_demo_page/index.dart';
|
||||
|
||||
// app的首页
|
||||
var homeHandler = new Handler(
|
||||
@ -35,9 +35,9 @@ var collectionHandler = new Handler(
|
||||
|
||||
var categoryHandler = new Handler(
|
||||
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
String name = params["type"]?.first;
|
||||
String ids = params["ids"]?.first;
|
||||
|
||||
return new CategoryHome(name);
|
||||
return new CategoryHome(ids);
|
||||
},
|
||||
);
|
||||
|
||||
@ -60,12 +60,15 @@ var fullScreenCodeDialog = new Handler(
|
||||
|
||||
var webViewPageHand = new Handler(
|
||||
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
String title = params['title']?.first;
|
||||
String url = params['url']?.first;
|
||||
return new WebViewPage(url, title);
|
||||
});
|
||||
String title = params['title']?.first;
|
||||
String url = params['url']?.first;
|
||||
return new WebViewPage(url, title);
|
||||
});
|
||||
|
||||
// var issuesMessageHandler = new Handler(
|
||||
// handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
// return issuesMessagePage();
|
||||
// });
|
||||
|
||||
var standardPageHandler = new Handler(
|
||||
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
|
||||
String id = params['id']?.first;
|
||||
return StandardView(id: id);
|
||||
}
|
||||
);
|
||||
|
@ -2,10 +2,9 @@
|
||||
import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_go/utils/analytics.dart' show analytics;
|
||||
|
||||
import '../widgets/index.dart';
|
||||
import './router_handler.dart';
|
||||
|
||||
import '../standard_pages/index.dart';
|
||||
class Routes {
|
||||
static String root = "/";
|
||||
static String home = "/home";
|
||||
@ -16,6 +15,7 @@ class Routes {
|
||||
static String issuesMessage='/issuesMessage';
|
||||
static String collectionPage = '/collection-page';
|
||||
static String collectionFullPage = '/collection-full-page';
|
||||
static String standardPage = '/standard-page/:id';
|
||||
|
||||
static void configureRoutes(Router router) {
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
@ -25,7 +25,7 @@ class Routes {
|
||||
router.define(home, handler: homeHandler);
|
||||
router.define(collectionPage,handler:collectionHandler);
|
||||
router.define(collectionFullPage,handler:collectionFullHandler);
|
||||
router.define('/category/:type', handler: categoryHandler);
|
||||
router.define('/category/:ids', handler: categoryHandler);
|
||||
router.define('/category/error/404', handler: widgetNotFoundHandler);
|
||||
router.define(loginPage, handler: loginPageHandler);
|
||||
router.define(codeView,handler:fullScreenCodeDialog);
|
||||
@ -41,5 +41,10 @@ class Routes {
|
||||
});
|
||||
router.define('${demo.routerName}', handler: handler);
|
||||
});
|
||||
router.define(standardPage,handler:standardPageHandler);
|
||||
// router.define(webViewPage,handler:webViewPageHand);
|
||||
// standardPages.forEach((String id, String md) => {
|
||||
//
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
11
lib/standard_pages/.pages.json
Normal file
11
lib/standard_pages/.pages.json
Normal file
@ -0,0 +1,11 @@
|
||||
[
|
||||
{
|
||||
"name": "standard",
|
||||
"screenShot": "",
|
||||
"author": "sanfan",
|
||||
"title": "介绍页",
|
||||
"email": "hanxu317@qq.com",
|
||||
"desc": "desc",
|
||||
"id": "ee4feb8e_32ae_4241_9c8a_5c9e1f92b096"
|
||||
}
|
||||
]
|
11
lib/standard_pages/index.dart
Normal file
11
lib/standard_pages/index.dart
Normal file
@ -0,0 +1,11 @@
|
||||
import 'standard_sanfan_ee4feb8e_32ae_4241_9c8a_5c9e1f92b096/index.dart' as StandardPage_standard_ee4feb8e_32ae_4241_9c8a_5c9e1f92b096;
|
||||
class StandardPages {
|
||||
Map<String, String> standardPages;
|
||||
Map<String, String> getPages() {
|
||||
return {
|
||||
'ee4feb8e_32ae_4241_9c8a_5c9e1f92b096': StandardPage_standard_ee4feb8e_32ae_4241_9c8a_5c9e1f92b096.getMd()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "standard",
|
||||
"screenShot": "",
|
||||
"author":"sanfan",
|
||||
"title":"介绍页",
|
||||
"email": "hanxu317@qq.com",
|
||||
"desc": "desc",
|
||||
"id": "ee4feb8e_32ae_4241_9c8a_5c9e1f92b096"
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
String getMd() {
|
||||
return """
|
||||
# 标准的详情页
|
||||
|
||||
您可以在这个界面中, 编写大多数的markdown文案, 他会在 **goCli watch** 下同步被编译成 **dart** 文件
|
||||
|
||||
您可以通过goCli创建详情页所需要的demo
|
||||
[demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
|
||||
|
||||
```
|
||||
goCLi createDemo
|
||||
```
|
||||
|
||||
在flutter go 根文件下通过命令行输入以上命令可以进行以下操作
|
||||
|
||||
[✓] 请输入新增加的demo名称? demoName
|
||||
|
||||
[✓] 请输入您的姓名(使用英文) yourName
|
||||
|
||||
[✓] 请输入您的github的email地址 yourEmail
|
||||
|
||||
[✓] 请输入您demo的描述 这是一个测试的标准demo
|
||||
|
||||
|
||||
在完成以上操作后, 可以得到这样的输出:
|
||||
|
||||
|
||||
```
|
||||
------------------
|
||||
您新增的组件信息如下
|
||||
==================
|
||||
{
|
||||
name : demoName
|
||||
author : yourName
|
||||
email : yourEmail
|
||||
desc : 这是一个测试的标准demo
|
||||
}
|
||||
==================
|
||||
[✓] Is this the config you want ? (Y/n) y
|
||||
{
|
||||
新建的demo文件位于 : /flutter go/lib/page_demo_package/demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
demoId为 : 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
markdown中调用方式 : [demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
}
|
||||
|
||||
```
|
||||
您可以在任意详情页中, 通过以下方式调用
|
||||
|
||||
```
|
||||
[demo: 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
```""";
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
# 标准的详情页
|
||||
|
||||
您可以在这个界面中, 编写大多数的markdown文案, 他会在 **goCli watch** 下同步被编译成 **dart** 文件
|
||||
|
||||
您可以通过goCli创建详情页所需要的demo
|
||||
[demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
|
||||
|
||||
```
|
||||
goCLi createDemo
|
||||
```
|
||||
|
||||
在flutter go 根文件下通过命令行输入以上命令可以进行以下操作
|
||||
|
||||
[✓] 请输入新增加的demo名称? demoName
|
||||
|
||||
[✓] 请输入您的姓名(使用英文) yourName
|
||||
|
||||
[✓] 请输入您的github的email地址 yourEmail
|
||||
|
||||
[✓] 请输入您demo的描述 这是一个测试的标准demo
|
||||
|
||||
|
||||
在完成以上操作后, 可以得到这样的输出:
|
||||
|
||||
|
||||
```
|
||||
------------------
|
||||
您新增的组件信息如下
|
||||
==================
|
||||
{
|
||||
name : demoName
|
||||
author : yourName
|
||||
email : yourEmail
|
||||
desc : 这是一个测试的标准demo
|
||||
}
|
||||
==================
|
||||
[✓] Is this the config you want ? (Y/n) y
|
||||
{
|
||||
新建的demo文件位于 : /flutter go/lib/page_demo_package/demoName_yourName_1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
demoId为 : 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096
|
||||
markdown中调用方式 : [demo:1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
}
|
||||
|
||||
```
|
||||
您可以在任意详情页中, 通过以下方式调用
|
||||
|
||||
```
|
||||
[demo: 1a29aa8e_32ae_4241_9c8a_5c9e1f92b096]
|
||||
```
|
@ -1,7 +1,9 @@
|
||||
import 'dart:async' show Future;
|
||||
|
||||
import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter_go/model/collection.dart';
|
||||
import 'package:flutter_go/model/version.dart';
|
||||
import 'package:flutter_go/model/widget.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
import 'package:flutter_go/model/responseData.dart';
|
||||
|
||||
@ -39,7 +41,6 @@ class DataUtils {
|
||||
var response = await NetUtils.get(Api.CHECK_LOGIN);
|
||||
print('response: $response');
|
||||
try {
|
||||
print('1111');
|
||||
if (response['success']) {
|
||||
print('${response['success']} ${response['data']} response[succes]');
|
||||
UserInformation userInfo = UserInformation.fromJson(response['data']);
|
||||
@ -104,4 +105,97 @@ class DataUtils {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取widget列表处的树型数据
|
||||
static Future<List> getWidgetTreeList() async {
|
||||
try {
|
||||
var response = await NetUtils.get(Api.GET_WIDGET_TREE);
|
||||
print('组件树:$response');
|
||||
if (response != null && response['success']) {
|
||||
return response['data'];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (error) {
|
||||
print('获取组件树 error $error');
|
||||
}
|
||||
}
|
||||
|
||||
// 校验是否收藏
|
||||
static Future<bool> checkCollected(Map<String, String> params) async {
|
||||
print('url 地址:${Api.CHECK_COLLECTED} $params');
|
||||
try {
|
||||
var response = await NetUtils.post(Api.CHECK_COLLECTED, params);
|
||||
return response != null && response['hasCollected'];
|
||||
} catch (error) {
|
||||
print('校验收藏 error $error');
|
||||
}
|
||||
}
|
||||
|
||||
// 添加收藏
|
||||
static Future addCollected(Map<String, String> params, context) async {
|
||||
var response = await NetUtils.post(Api.ADD_COLLECTION, params);
|
||||
if (response['status'] == 401 && response['message'] == '请先登录') {
|
||||
Application.router.navigateTo(context, '${Routes.loginPage}',
|
||||
transition: TransitionType.nativeModal);
|
||||
}
|
||||
return response != null && response['success'];
|
||||
}
|
||||
|
||||
// 移出收藏
|
||||
static Future removeCollected(Map<String, String> params, context) async {
|
||||
var response = await NetUtils.post(Api.REMOVE_COLLECTION, params);
|
||||
if (response['status'] == 401 && response['message'] == '请先登录') {
|
||||
Application.router.navigateTo(context, '${Routes.loginPage}',
|
||||
transition: TransitionType.nativeModal);
|
||||
}
|
||||
return response != null && response['success'];
|
||||
}
|
||||
|
||||
// 获取全部收藏
|
||||
static Future getAllCollections(context) async {
|
||||
var response = await NetUtils.get(Api.GET_ALL_COLLECTION);
|
||||
List<Collection> responseList = [];
|
||||
if (response['status'] == 401 && response['message'] == '请先登录') {
|
||||
Application.router.navigateTo(context, '${Routes.loginPage}',
|
||||
transition: TransitionType.nativeModal);
|
||||
}
|
||||
if (response != null && response['success'] == true) {
|
||||
for (int i = 0; i < response['data'].length; i++) {
|
||||
Map<String, dynamic> tempCo = response['data'][i];
|
||||
responseList.add(Collection.fromJSON(
|
||||
{"name": tempCo['name'], "router": tempCo['url']}));
|
||||
}
|
||||
return responseList;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索组件
|
||||
static Future searchWidget(String name) async {
|
||||
var response = await NetUtils.get(Api.SEARCH_WIDGET, {"name": name});
|
||||
List<WidgetPoint> list = [];
|
||||
if (response != null && response['success'] == true) {
|
||||
for (int i = 0; i < response['data'].length; i++) {
|
||||
var json = response['data'][i];
|
||||
String routerName;
|
||||
if (json['display'] == 'old') {
|
||||
routerName = json['path'];
|
||||
} else {
|
||||
routerName = json['pageId'];
|
||||
}
|
||||
Map<String, dynamic> tempMap = {
|
||||
"name": json['name'],
|
||||
"cnName": json['name'],
|
||||
"routerName": routerName,
|
||||
"catId": int.parse(json['parentId'])
|
||||
};
|
||||
list.add(WidgetPoint.fromJSON(tempMap));
|
||||
}
|
||||
return list;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,13 @@
|
||||
/// @Last Modified time: 2019-06-05 14:01:03
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:event_bus/event_bus.dart';
|
||||
import 'package:fluro/fluro.dart';
|
||||
|
||||
import 'package:flutter_go/model/collection.dart';
|
||||
import 'package:flutter_go/routers/application.dart';
|
||||
import 'package:flutter_go/routers/routers.dart';
|
||||
import 'package:flutter_go/event/event_bus.dart';
|
||||
import 'package:flutter_go/event/event_model.dart';
|
||||
import 'package:flutter_go/utils/data_utils.dart';
|
||||
|
||||
class CollectionFullPage extends StatefulWidget {
|
||||
final bool hasLogined;
|
||||
@ -41,13 +42,10 @@ class _CollectionFullPageState extends State<CollectionFullPage> {
|
||||
|
||||
void _getList() {
|
||||
_collectionList.clear();
|
||||
_collectionControl.getAllCollection().then((resultList) {
|
||||
resultList.forEach((item) {
|
||||
_collectionList.add(item);
|
||||
});
|
||||
DataUtils.getAllCollections(context).then((collectionList) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_collectionList = _collectionList;
|
||||
_collectionList = collectionList;
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -73,7 +71,7 @@ class _CollectionFullPageState extends State<CollectionFullPage> {
|
||||
SizedBox(
|
||||
width: 5.0,
|
||||
),
|
||||
Text('模拟器重新运行会丢失收藏'),
|
||||
Text('常用的组件都可以收藏在这里哦'),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -115,21 +113,24 @@ class _CollectionFullPageState extends State<CollectionFullPage> {
|
||||
trailing:
|
||||
Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0),
|
||||
onTap: () {
|
||||
if (_collectionList[index - 1].router.contains('http')) {
|
||||
// 注意这里title已经转义过了
|
||||
Application.router.navigateTo(context,
|
||||
'${Routes.webViewPage}?title=${_collectionList[index - 1].name}&url=${Uri.encodeComponent(_collectionList[index - 1].router)}');
|
||||
} else {
|
||||
Application.router
|
||||
.navigateTo(context, "${_collectionList[index - 1].router}");
|
||||
}
|
||||
Application.router.navigateTo(
|
||||
context, _collectionList[index - 1].router,
|
||||
transition: TransitionType.inFromRight);
|
||||
|
||||
// if (_collectionList[index - 1].router.contains('http')) {
|
||||
// // 注意这里title已经转义过了
|
||||
// Application.router.navigateTo(context,
|
||||
// '${Routes.webViewPage}?title=${_collectionList[index - 1].name}&url=${Uri.encodeComponent(_collectionList[index - 1].router)}');
|
||||
// } else {
|
||||
// Application.router
|
||||
// .navigateTo(context, "${_collectionList[index - 1].router}");
|
||||
// }
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
ListView buildContent(){
|
||||
ListView buildContent() {
|
||||
if (_collectionList.length == 0) {
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
|
@ -11,6 +11,7 @@ import 'package:flutter_go/routers/application.dart';
|
||||
import 'package:flutter_go/routers/routers.dart';
|
||||
import 'package:flutter_go/event/event_bus.dart';
|
||||
import 'package:flutter_go/event/event_model.dart';
|
||||
import 'package:flutter_go/utils/data_utils.dart';
|
||||
|
||||
class CollectionPage extends StatefulWidget {
|
||||
final bool hasLogined;
|
||||
@ -47,13 +48,10 @@ class _CollectionPageState extends State<CollectionPage> {
|
||||
|
||||
void _getList() {
|
||||
_collectionList.clear();
|
||||
_collectionControl.getAllCollection().then((resultList) {
|
||||
resultList.forEach((item) {
|
||||
_collectionList.add(item);
|
||||
});
|
||||
DataUtils.getAllCollections(context).then((collectionList) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_collectionList = _collectionList;
|
||||
_collectionList = collectionList;
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -108,7 +106,8 @@ class _CollectionPageState extends State<CollectionPage> {
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
title: Text(
|
||||
Uri.decodeComponent(_collectionList[index - 1].name),
|
||||
_collectionList[index - 1].name,
|
||||
// Uri.decodeComponent(_collectionList[index - 1].name),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(fontSize: 17.0),
|
||||
),
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_go/utils/data_utils.dart';
|
||||
import 'package:flutter_go/utils/shared_preferences.dart';
|
||||
import 'package:flutter_go/views/first_page/first_page.dart';
|
||||
import 'package:flutter_go/views/first_page/main_page.dart';
|
||||
import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter_go/views/widget_page/widget_page.dart';
|
||||
import 'package:flutter_go/views/welcome_page/fourth_page.dart';
|
||||
import 'package:flutter_go/views/collection_page/collection_page.dart';
|
||||
@ -69,8 +71,8 @@ class _MyHomePageState extends State<AppPage>
|
||||
_list
|
||||
// ..add(FirstPage())
|
||||
..add(MainPage(userInfo: widget.userInfo))
|
||||
..add(WidgetPage(Provider.db))
|
||||
..add(CollectionPage(hasLogined: widget.userInfo.id != 0))
|
||||
..add(WidgetPage())
|
||||
..add(CollectionPage())
|
||||
..add(FourthPage());
|
||||
}
|
||||
|
||||
@ -87,26 +89,21 @@ class _MyHomePageState extends State<AppPage>
|
||||
}
|
||||
|
||||
void onWidgetTap(WidgetPoint widgetPoint, BuildContext context) {
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
String targetName = widgetPoint.name;
|
||||
String targetRouter = '/category/error/404';
|
||||
widgetDemosList.forEach((item) {
|
||||
if (item.name == targetName) {
|
||||
targetRouter = item.routerName;
|
||||
}
|
||||
});
|
||||
searchHistoryList
|
||||
.add(SearchHistory(name: targetName, targetRouter: targetRouter));
|
||||
.add(SearchHistory(name: targetName, targetRouter: widgetPoint.routerName));
|
||||
print("searchHistoryList1 ${searchHistoryList.toString()}");
|
||||
print("searchHistoryList2 ${targetRouter}");
|
||||
print("searchHistoryList3 ${widgetPoint.name}");
|
||||
Application.router.navigateTo(context, "$targetRouter");
|
||||
Application.router.navigateTo(
|
||||
context, widgetPoint.routerName,
|
||||
transition: TransitionType.inFromRight);
|
||||
}
|
||||
|
||||
Widget buildSearchInput(BuildContext context) {
|
||||
return new SearchInput((value) async {
|
||||
if (value != '') {
|
||||
List<WidgetPoint> list = await widgetControl.search(value);
|
||||
print('value ::: $value');
|
||||
// List<WidgetPoint> list = await widgetControl.search(value);
|
||||
List<WidgetPoint> list = await DataUtils.searchWidget(value);
|
||||
return list
|
||||
.map((item) => new MaterialSearchResult<String>(
|
||||
value: item.name,
|
||||
|
@ -224,15 +224,13 @@ class _LoginPageState extends State<LoginPage> {
|
||||
|
||||
// 登陆操作
|
||||
doLogin() {
|
||||
print("doLogin");
|
||||
_signInFormKey.currentState.save();
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
DataUtils.doLogin({'username': username, 'password': password})
|
||||
.then((userResult) {
|
||||
if (userResult.runtimeType == String) {
|
||||
throw userResult;
|
||||
}
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
|
12
lib/views/standard_demo_page/const.dart
Normal file
12
lib/views/standard_demo_page/const.dart
Normal file
@ -0,0 +1,12 @@
|
||||
const title = 'titie1';
|
||||
Map<String, String> titleObjs = {
|
||||
'title': 'haha33'
|
||||
};
|
||||
class Maps {
|
||||
Map<String, String> list;
|
||||
getList() {
|
||||
return {
|
||||
"title": "1111"
|
||||
};
|
||||
}
|
||||
}
|
128
lib/views/standard_demo_page/index.dart
Normal file
128
lib/views/standard_demo_page/index.dart
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// Created with Android Studio.
|
||||
// User: 三帆
|
||||
// Date: 25/05/2019
|
||||
// Time: 21:46
|
||||
// email: sanfan.hx@alibaba-inc.com
|
||||
// tartget: xxx
|
||||
//
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../components/widget_demo.dart';
|
||||
import 'dart:convert';
|
||||
import '../../components/markdown.dart' as mdCopy;
|
||||
import '../../components/flutter_markdown/lib/flutter_markdown.dart';
|
||||
import '../../standard_pages/index.dart';
|
||||
import '../../page_demo_package/index.dart';
|
||||
import 'package:flutter_go/routers/application.dart';
|
||||
|
||||
// ONLINE || LOCAL
|
||||
ENV env = Application.env;
|
||||
|
||||
class StandardView extends StatefulWidget {
|
||||
final String id;
|
||||
final String detailMd;
|
||||
StandardView({this.id, this.detailMd});
|
||||
@override
|
||||
_StandardView createState() => _StandardView();
|
||||
}
|
||||
|
||||
class _StandardView extends State<StandardView> {
|
||||
String markdownDesc = '# this is header';
|
||||
String pageTitle = "XXX";
|
||||
|
||||
String author = '';
|
||||
String email = '';
|
||||
StandardPages standardPage = new StandardPages();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
this.getDetail();
|
||||
}
|
||||
|
||||
// 本地调用的获取基本信息
|
||||
Future<void> getPagesInfo() async {
|
||||
String jsonString = await DefaultAssetBundle.of(context)
|
||||
.loadString('lib/standard_pages/.pages.json');
|
||||
List jsonList = json.decode(jsonString);
|
||||
Map<String, dynamic> pageDetail =
|
||||
jsonList.firstWhere((item) => item['id'] == widget.id);
|
||||
if (pageDetail != null) {
|
||||
setState(() {
|
||||
pageTitle = pageDetail['title'] ?? '请加入title';
|
||||
author = pageDetail['author'];
|
||||
email = pageDetail['email'];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String _getContentFromLocal() {
|
||||
String pageId = widget.id;
|
||||
Map<String, String> pagesList = standardPage.getPages();
|
||||
return pagesList[pageId];
|
||||
}
|
||||
|
||||
Future<String> _getContentOnline() async {
|
||||
String content = 'online content';
|
||||
|
||||
return Future(() => content);
|
||||
}
|
||||
|
||||
Future<String> getDetail() async {
|
||||
String conent = '';
|
||||
print("env:::: $env");
|
||||
|
||||
if (env == ENV.PRODUCTION) {
|
||||
conent = await _getContentOnline();
|
||||
} else {
|
||||
getPagesInfo();
|
||||
conent = _getContentFromLocal();
|
||||
}
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
markdownDesc = conent;
|
||||
});
|
||||
}
|
||||
return Future(() => conent);
|
||||
// this.rebuild();
|
||||
}
|
||||
|
||||
Widget buildMarkdown() {
|
||||
Map<String, String> contentList = new StandardPages().getPages();
|
||||
|
||||
if (contentList[widget.id] == null) {
|
||||
contentList[widget.id] = '';
|
||||
}
|
||||
|
||||
return MarkdownBody(
|
||||
data: contentList[widget.id],
|
||||
syntaxHighlighter: new mdCopy.HighLight(),
|
||||
demoBuilder: (Map<String, dynamic> attrs) {
|
||||
List<Widget> demo = demoObjects[attrs['id']];
|
||||
if (demo == null) {
|
||||
String errString = "not found ${attrs['id']} in demo packages";
|
||||
debugPrint(errString);
|
||||
demo = [Text(errString)];
|
||||
}
|
||||
|
||||
return Column(children: demo);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new WidgetDemo(
|
||||
title: pageTitle,
|
||||
codeUrl: 'elements/Form/Button/DropdownButton/demo.dart',
|
||||
contentList: [
|
||||
buildMarkdown(),
|
||||
SizedBox(height: 30),
|
||||
'创建者: $author',
|
||||
'创建者: $email',
|
||||
'id: ${widget.id}',
|
||||
],
|
||||
docUrl:
|
||||
'https://docs.flutter.io/flutter/material/DropdownButton-class.html',
|
||||
);
|
||||
}
|
||||
}
|
@ -23,15 +23,12 @@ class WebViewPage extends StatefulWidget {
|
||||
|
||||
class _WebViewPageState extends State<WebViewPage> {
|
||||
final flutterWebviewPlugin = new FlutterWebviewPlugin();
|
||||
bool _hasCollected = false;
|
||||
String _router = '';
|
||||
var _collectionIcons;
|
||||
CollectionControlModel _collectionControl = new CollectionControlModel();
|
||||
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
flutterWebviewPlugin.onUrlChanged.listen((String url) {
|
||||
print('url change:$url');
|
||||
if (url.indexOf('loginSuccess') > -1) {
|
||||
@ -64,87 +61,14 @@ class _WebViewPageState extends State<WebViewPage> {
|
||||
flutterWebviewPlugin.close();
|
||||
}
|
||||
});
|
||||
|
||||
_collectionControl
|
||||
.getRouterByName(Uri.encodeComponent(widget.title.trim()))
|
||||
.then((list) {
|
||||
list.forEach((item) {
|
||||
if (widget.title.trim() == item['name']) {
|
||||
_router = item['router'];
|
||||
}
|
||||
});
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_hasCollected = list.length > 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 点击收藏按钮
|
||||
_getCollection() {
|
||||
if (_hasCollected) {
|
||||
// 删除操作
|
||||
_collectionControl
|
||||
.deleteByName(Uri.encodeComponent(widget.title.trim()))
|
||||
.then((result) {
|
||||
if (result > 0 && this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = false;
|
||||
});
|
||||
_scaffoldKey.currentState
|
||||
.showSnackBar(SnackBar(content: Text('已取消收藏')));
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
print('删除错误');
|
||||
});
|
||||
} else {
|
||||
// 插入操作
|
||||
_collectionControl
|
||||
.insert(Collection(
|
||||
name: Uri.encodeComponent(widget.title.trim()),
|
||||
router: widget.url))
|
||||
.then((result) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = true;
|
||||
});
|
||||
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, false));
|
||||
}
|
||||
_scaffoldKey.currentState
|
||||
.showSnackBar(SnackBar(content: Text('收藏成功')));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_hasCollected) {
|
||||
_collectionIcons = Icons.favorite;
|
||||
} else {
|
||||
_collectionIcons = Icons.favorite_border;
|
||||
}
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
actions: <Widget>[
|
||||
new IconButton(
|
||||
tooltip: 'goBack home',
|
||||
onPressed: _getCollection,
|
||||
icon: Icon(
|
||||
_collectionIcons,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: WebviewScaffold(
|
||||
url: widget.url,
|
||||
|
@ -6,28 +6,28 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter_go/components/cate_card.dart';
|
||||
import 'package:flutter_go/model/cat.dart';
|
||||
|
||||
import 'package:flutter_go/routers/application.dart';
|
||||
|
||||
|
||||
class WidgetPage extends StatefulWidget {
|
||||
final db;
|
||||
final CatControlModel catModel;
|
||||
WidgetPage(this.db)
|
||||
: catModel = new CatControlModel(),
|
||||
super();
|
||||
|
||||
|
||||
|
||||
|
||||
@override
|
||||
SecondPageState createState() => new SecondPageState(catModel);
|
||||
SecondPageState createState() => new SecondPageState();
|
||||
}
|
||||
|
||||
class SecondPageState extends State<WidgetPage> with AutomaticKeepAliveClientMixin{
|
||||
CatControlModel catModel;
|
||||
SecondPageState(this.catModel) : super();
|
||||
|
||||
SecondPageState() : super();
|
||||
|
||||
TextEditingController controller;
|
||||
String active = 'test';
|
||||
String data = '无';
|
||||
|
||||
List<Cat> categories = [];
|
||||
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => true;
|
||||
@ -35,25 +35,16 @@ class SecondPageState extends State<WidgetPage> with AutomaticKeepAliveClientMix
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
renderCats();
|
||||
}
|
||||
|
||||
void renderCats() {
|
||||
catModel.getList().then((List data) {
|
||||
if (data.isNotEmpty) {
|
||||
setState(() {
|
||||
categories = data;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Widget buildGrid() {
|
||||
// 存放最后的widget
|
||||
List<Widget> tiles = [];
|
||||
for (Cat item in categories) {
|
||||
Application.widgetTree.children.forEach((dynamic item) {
|
||||
tiles.add(new CateCard(category: item));
|
||||
}
|
||||
});
|
||||
return new ListView(
|
||||
children: tiles,
|
||||
);
|
||||
@ -62,11 +53,7 @@ class SecondPageState extends State<WidgetPage> with AutomaticKeepAliveClientMix
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
if (categories.length == 0) {
|
||||
return ListView(
|
||||
children: <Widget>[new Container()],
|
||||
);
|
||||
}
|
||||
print("build in widget page");
|
||||
return Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: this.buildGrid(),
|
||||
|
@ -15,7 +15,7 @@ class _CheckedPopupMenuItemDemoState extends State<CheckedPopupMenuItemDemo> {
|
||||
|
||||
final String _checkedValue1 = 'One';
|
||||
final String _checkedValue2 = 'Two';
|
||||
final String _checkedValue3 = 'Free';
|
||||
final String _checkedValue3 = 'Three';
|
||||
final String _checkedValue4 = 'Four';
|
||||
|
||||
@override
|
||||
|
@ -11,7 +11,7 @@ class DropdownMenuItemDemo extends StatefulWidget {
|
||||
|
||||
class _DropdownMenuItemDemoState extends State<DropdownMenuItemDemo> {
|
||||
|
||||
String dropdown1Value = 'Free';
|
||||
String dropdown1Value = 'Three';
|
||||
String dropdown2Value;
|
||||
String dropdown3Value = 'Four';
|
||||
|
||||
@ -32,7 +32,7 @@ class _DropdownMenuItemDemoState extends State<DropdownMenuItemDemo> {
|
||||
dropdown1Value = newValue;
|
||||
});
|
||||
},
|
||||
items: <String>['One', 'Two', 'Free', 'Four'].map<DropdownMenuItem<String>>((String value) {
|
||||
items: <String>['One', 'Two', 'Three', 'Four'].map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
@ -53,7 +53,7 @@ class _DropdownMenuItemDemoState extends State<DropdownMenuItemDemo> {
|
||||
dropdown2Value = newValue;
|
||||
});
|
||||
},
|
||||
items: <String>['One', 'Two', 'Free', 'Four'].map<DropdownMenuItem<String>>((String value) {
|
||||
items: <String>['One', 'Two', 'Three', 'Four'].map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value),
|
||||
@ -74,7 +74,7 @@ class _DropdownMenuItemDemoState extends State<DropdownMenuItemDemo> {
|
||||
});
|
||||
},
|
||||
items: <String>[
|
||||
'One', 'Two', 'Free', 'Four', 'Can', 'I', 'Have', 'A', 'Little',
|
||||
'One', 'Two', 'Three', 'Four', 'Can', 'I', 'Have', 'A', 'Little',
|
||||
'Bit', 'More', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten'
|
||||
]
|
||||
.map<DropdownMenuItem<String>>((String value) {
|
||||
|
@ -21,7 +21,7 @@ const String content1 = '''
|
||||
''';
|
||||
|
||||
class Demo extends StatefulWidget {
|
||||
static const String routeName = '/themes/Material/MaterialColor';
|
||||
static const String routeName = '/Themes/Material/MaterialColor';
|
||||
|
||||
_DemoState createState() => _DemoState();
|
||||
}
|
||||
|
31
pubspec.lock
31
pubspec.lock
@ -105,7 +105,7 @@ packages:
|
||||
name: fluro
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
version: "1.5.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -124,7 +124,7 @@ packages:
|
||||
name: flutter_downloader
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.7"
|
||||
version: "1.1.9"
|
||||
flutter_jpush:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -132,13 +132,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4"
|
||||
flutter_markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_markdown
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
flutter_spinkit:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -194,7 +187,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.0.7"
|
||||
markdown:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: markdown
|
||||
url: "https://pub.dartlang.org"
|
||||
@ -208,7 +201,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.12.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.dartlang.org"
|
||||
@ -234,9 +227,9 @@ packages:
|
||||
name: package_info
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.0+4"
|
||||
version: "0.4.0+6"
|
||||
path:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
@ -248,7 +241,7 @@ packages:
|
||||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.2.0"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -297,7 +290,7 @@ packages:
|
||||
name: share
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.2"
|
||||
version: "0.6.2+1"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -323,7 +316,7 @@ packages:
|
||||
name: sqflite
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.6+1"
|
||||
version: "1.1.6+3"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -339,7 +332,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: string_scanner
|
||||
url: "https://pub.dartlang.org"
|
||||
@ -379,7 +372,7 @@ packages:
|
||||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.5"
|
||||
version: "5.1.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -396,4 +389,4 @@ packages:
|
||||
version: "0.0.1"
|
||||
sdks:
|
||||
dart: ">=2.2.2 <3.0.0"
|
||||
flutter: ">=1.5.0 <2.0.0"
|
||||
flutter: ">=1.6.0 <2.0.0"
|
||||
|
10
pubspec.yaml
10
pubspec.yaml
@ -10,7 +10,7 @@ description: flutter_go
|
||||
version: 1.0.6
|
||||
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev.68.0 <3.0.0"
|
||||
sdk: ">=2.1.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
@ -23,7 +23,6 @@ dependencies:
|
||||
fluro: ^1.3.4
|
||||
image_picker: ^0.5.0
|
||||
sqflite: ^1.1.5
|
||||
flutter_markdown: ^0.2.0
|
||||
url_launcher: ^5.0.2
|
||||
# 本地存储、收藏功能
|
||||
shared_preferences: ^0.4.3
|
||||
@ -42,6 +41,10 @@ dependencies:
|
||||
flutter_bloc: ^0.11.1
|
||||
bloc: ^0.12.0
|
||||
html: ^0.14.0+2
|
||||
markdown: ^2.0.0
|
||||
meta: ^1.0.5
|
||||
string_scanner: ^1.0.0
|
||||
path: ^1.5.1
|
||||
flutter_downloader: ^1.1.7
|
||||
path_provider: ^1.1.0
|
||||
permission_handler: ^3.0.0
|
||||
@ -58,7 +61,6 @@ dev_dependencies:
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://www.dartlang.org/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
|
||||
@ -209,6 +211,8 @@ flutter:
|
||||
- lib/widgets/themes/Cupertino/CupertinoTabScaffold/demo.dart
|
||||
- lib/widgets/themes/Cupertino/CupertinoTabView/demo.dart
|
||||
- lib/widgets/themes/Cupertino/CupertinoTimerPicker/demo.dart
|
||||
- lib/page_demo_package/.demo.json
|
||||
- lib/standard_pages/.pages.json
|
||||
- assets/app.db
|
||||
- assets/images/
|
||||
- assets/fonts/
|
||||
|
Reference in New Issue
Block a user