diff --git a/analysis_options.yaml b/analysis_options.yaml
index 5eacbca..077bb34 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -1,3 +1,3 @@
-analyzer:
- errors:
- mixin_inherits_from_not_object: ignore
\ No newline at end of file
+# analyzer:
+# errors:
+# mixin_inherits_from_not_object: ignore
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 2ab784b..4448699 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
- compileSdkVersion 27
+ compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
@@ -42,10 +42,10 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.flutter.beer"
minSdkVersion 16
- targetSdkVersion 27
+ targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
@@ -79,10 +79,14 @@ flutter {
dependencies {
testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+ androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
//firebase
- implementation 'com.google.firebase:firebase-core:16.0.7'
+ implementation 'com.google.firebase:firebase-core:16.0.8'
+ //Crashlytics SDK
+ implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
}
//firebase
-apply plugin: 'com.google.gms.google-services'
\ No newline at end of file
+apply plugin: 'com.google.gms.google-services'
+//Crashlytics SDK
+apply plugin: 'io.fabric'
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2e9846d..53ae800 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
+ package="com.flutter.beer"
+ android:installLocation="preferExternal">
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
index 131b586..eb44602 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -2,12 +2,18 @@ buildscript {
repositories {
google()
jcenter()
+ //Crashlytics SDK
+ maven {
+ url 'https://maven.fabric.io/public'
+ }
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:3.3.2'
//firebase
classpath 'com.google.gms:google-services:4.2.0'
+ //Crashlytics SDK
+ classpath 'io.fabric.tools:gradle:1.26.1'
}
}
@@ -15,6 +21,10 @@ allprojects {
repositories {
google()
jcenter()
+ //Crashlytics SDK
+ maven {
+ url 'https://maven.google.com/'
+ }
}
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 8bd86f6..4d3226a 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
\ No newline at end of file
diff --git a/assets/imgs/cool.jpg b/assets/imgs/cool.jpg
new file mode 100644
index 0000000..2ed7854
Binary files /dev/null and b/assets/imgs/cool.jpg differ
diff --git a/assets/imgs/github.png b/assets/imgs/github.png
new file mode 100644
index 0000000..b1ba9a7
Binary files /dev/null and b/assets/imgs/github.png differ
diff --git a/assets/imgs/github_1.png b/assets/imgs/github_1.png
new file mode 100644
index 0000000..62fcb4e
Binary files /dev/null and b/assets/imgs/github_1.png differ
diff --git a/assets/imgs/github_2.png b/assets/imgs/github_2.png
new file mode 100644
index 0000000..d6649ed
Binary files /dev/null and b/assets/imgs/github_2.png differ
diff --git a/docs/widget/common/assetbundle/index.md b/docs/widget/common/assetbundle/index.md
index 83532f6..eab9b0d 100644
--- a/docs/widget/common/assetbundle/index.md
+++ b/docs/widget/common/assetbundle/index.md
@@ -1 +1,13 @@
-## **文档完善中**
\ No newline at end of file
+## **AssetBundle**
+> 抽象类,资源读取
+
+#### 使用
+```
+import 'package:flutter/services.dart' show rootBundle;
+
+getText() async {
+ String text = await rootBundle.loadString('locale/zh.json');
+ print('text $text');
+}
+
+```
\ No newline at end of file
diff --git a/docs/widget/common/chip/index.md b/docs/widget/common/chip/index.md
index 83532f6..95e49c0 100644
--- a/docs/widget/common/chip/index.md
+++ b/docs/widget/common/chip/index.md
@@ -1 +1,46 @@
-## **文档完善中**
\ No newline at end of file
+## **Chip**
+
+>
+一般用于显示标签的控件
+
+### 构造方法
+``` dart
+Chip({
+ Key key,
+ this.avatar,
+ @required this.label,
+ this.labelStyle,
+ this.labelPadding,
+ this.deleteIcon,
+ this.onDeleted,
+ this.deleteIconColor,
+ this.deleteButtonTooltipMessage,
+ this.shape,
+ this.clipBehavior = Clip.none,
+ this.backgroundColor,
+ this.padding,
+ this.materialTapTargetSize,
+ this.elevation,
+ })
+```
+
+### 属性介绍
+
+* avatar:标签左侧widget,一般为小图标
+* label:标签内容
+* labelStyle:标签样式
+* labelPadding:标签周围填充
+* deleteIcon:删除图标
+* onDeleted:删除回调,为空时不显示删除图标
+* deleteIconColor:删除图标颜色
+* deleteButtonTooltipMessage:删除图标的tip提示文字
+* shape:形状
+* backgroundColor:背景颜色
+* padding:标签内容和外形之间的填充
+* materialTapTargetSize:配置点击目标的最小尺寸
+* elevation:标签阴影
+
+### 延生
+* ActionChip
+* FilterChip
+* ChoiceChip
diff --git a/docs/widget/common/iconbutton/index.md b/docs/widget/common/iconbutton/index.md
index 83532f6..3b6be3d 100644
--- a/docs/widget/common/iconbutton/index.md
+++ b/docs/widget/common/iconbutton/index.md
@@ -1 +1,32 @@
-## **文档完善中**
\ No newline at end of file
+## **IconButton**
+>
+图标按钮,通过填充颜色(墨水)对触摸做出反应
+
+### 构造方法
+``` dart
+IconButton({
+ Key key,
+ this.iconSize = 24.0,
+ this.padding = const EdgeInsets.all(8.0),
+ this.alignment = Alignment.center,
+ @required this.icon,
+ this.color,
+ this.highlightColor,
+ this.splashColor,
+ this.disabledColor,
+ @required this.onPressed,
+ this.tooltip
+ })
+```
+
+### 属性介绍
+* iconSize = 24.0:图标大小
+* padding = const EdgeInsets.all(8.0):按钮图标周围的填充
+* alignment = Alignment.center:图标对齐方式
+* icon:图标
+* color:图标颜色
+* highlightColor:按钮处于按下时按钮的辅助颜色
+* splashColor:按钮处于按下状态时按钮颜色
+* disabledColor:图标被禁用时按钮内图标的颜色
+* onPressed:点击回调
+* tooltip:长按文本提示
\ No newline at end of file
diff --git a/docs/widget/common/image/index.md b/docs/widget/common/image/index.md
index 83532f6..9299e5e 100644
--- a/docs/widget/common/image/index.md
+++ b/docs/widget/common/image/index.md
@@ -1 +1,51 @@
-## **文档完善中**
\ No newline at end of file
+## **Image**
+
+>
+用于展示图片的控件,支持本地图片,资源图片,网络图片等加载方式
+
+### 构造方法
+``` dart
+Image({
+ Key key,
+ @required this.image,
+ this.semanticLabel,
+ this.excludeFromSemantics = false,
+ this.width,
+ this.height,
+ this.color,
+ this.colorBlendMode,
+ this.fit,
+ this.alignment = Alignment.center,
+ this.repeat = ImageRepeat.noRepeat,
+ this.centerSlice,
+ this.matchTextDirection = false,
+ this.gaplessPlayback = false,
+ this.filterQuality = FilterQuality.low,
+ })
+```
+
+### 属性介绍
+* image:
+ * Image(): 通用方法,使用ImageProvider(包括:AssetImage, NetworkImage, FileImage, MemoryImage)实现,如下方法本质上也是使用这个方法
+ * Image.asset: 加载资源图片
+ * Image.file: 加载本地图片文件夹
+ * Image.network: 加载网络图片
+ * Image.memory: 加载Uint8List资源图片
+* width:图片容器宽度
+* height:图片容器高度
+* color:color一般和colorBlendMod配合使用
+* colorBlendMode:和color配合使用,添加滤镜效果
+* fit:如何将图像分配到布局空间中
+ * BoxFit.fill : 全图显示,显示尽可能拉伸,充满
+ * BoxFit.contain : 全图显示,显示原比例,不需充满
+ * BoxFit.cover : 显示可能拉伸,可能裁剪,充满
+ * BoxFit.fitWidth : 显示尽可能拉伸,可能裁剪,宽度充满
+ * BoxFit.fitHeight 显示尽可能拉伸,可能裁剪,高度充满:
+ * BoxFit.none 无fit:
+ * BoxFit.scaleDown 效果和contain差不多,但此属性不允许显示超过原图片大小,可小不可大:
+* alignment = Alignment.center:控制图片的显示位置
+* repeat = ImageRepeat.noRepeat:图片是否重复
+* centerSlice:九个补丁图像的中心切片
+* matchTextDirection = false:若值为turn,与Directionality配合使用,图片显示方向
+* gaplessPlayback = false:当ImageProvider发生变化后,重新加载图片的过程中,原图片的展示是否保留。若值为true,保留,若为false,不保留,直接空白等待下一张图片加载
+* filterQuality = FilterQuality.low:用于设置图像的FilterQuality
\ No newline at end of file
diff --git a/docs/widget/common/listtile/index.md b/docs/widget/common/listtile/index.md
index 83532f6..d93dcd6 100644
--- a/docs/widget/common/listtile/index.md
+++ b/docs/widget/common/listtile/index.md
@@ -1 +1,35 @@
-## **文档完善中**
\ No newline at end of file
+## **ListTile**
+>
+单个固定高度的行,通常包含一些文本和前导或者尾随的图标,通常在ListView中使用
+
+### 构造方法
+``` dart
+ListTile({
+ Key key,
+ this.leading,
+ this.title,
+ this.subtitle,
+ this.trailing,
+ this.isThreeLine = false,
+ this.dense,
+ this.contentPadding,
+ this.enabled = true,
+ this.onTap,
+ this.onLongPress,
+ this.selected = false,
+ })
+```
+
+### 属性介绍
+
+* leading:显示左侧的小组件
+* title:标题
+* subtitle:子标题
+* trailing:显示右侧的小组件
+* isThreeLine = false:是否显示三行文本
+* dense:是否垂直密集显示
+* contentPadding:ListTile的内部填充
+* enabled = true:是否是交互式的
+* onTap:点击时的回调
+* onLongPress:长按时的回调
+* selected = false:图标和文本是否以相同颜色呈现
diff --git a/docs/widget/common/raisedbutton/index.md b/docs/widget/common/raisedbutton/index.md
index 83532f6..012b1cd 100644
--- a/docs/widget/common/raisedbutton/index.md
+++ b/docs/widget/common/raisedbutton/index.md
@@ -1 +1,57 @@
-## **文档完善中**
\ No newline at end of file
+## **RaisedButton**
+>
+RaisedButton 凸起按钮
+
+### 构造方法
+``` dart
+RaisedButton({
+ Key key,
+ @required VoidCallback onPressed,
+ ValueChanged onHighlightChanged,
+ ButtonTextTheme textTheme,
+ Color textColor,
+ Color disabledTextColor,
+ Color color,
+ Color disabledColor,
+ Color highlightColor,
+ Color splashColor,
+ Brightness colorBrightness,
+ double elevation,
+ double highlightElevation,
+ double disabledElevation,
+ EdgeInsetsGeometry padding,
+ ShapeBorder shape,
+ Clip clipBehavior = Clip.none,
+ MaterialTapTargetSize materialTapTargetSize,
+ Duration animationDuration,
+ Widget child,
+ })
+```
+
+### 属性介绍
+* onPressed: 点击回调
+* textColor:文本颜色
+* disabledTextColor:禁用文本颜色
+* color:按钮颜色
+* disabledColor: 禁用按钮颜色
+* highlightColor:长按按钮颜色
+* splashColor: 点击按钮水波纹颜色
+* elevation: 按钮下面阴影
+* highlightElevation:阴影大小
+* disabledElevation:禁止阴影
+* padding:按钮填充区域
+* shape:按钮形状
+* child:按钮中的Widget
+
+### 高级用法
+按钮形状
+* BeveledRectangleBorder 带斜角的长方形边框
+* CircleBorder 圆形边框
+* RoundedRectangleBorder 圆角矩形
+* StadiumBorder 两端是半圆的边框
+
+设置按钮形状常用属性
+* side:用来设置边线(颜色、宽度等)
+* borderRadius:用来设置圆角
+
+使用RaisedButton.icon可以创建图标(icon)和标签(label)的widget文本按钮
\ No newline at end of file
diff --git a/docs/widget/common/stepper/index.md b/docs/widget/common/stepper/index.md
index 83532f6..2a8c50a 100644
--- a/docs/widget/common/stepper/index.md
+++ b/docs/widget/common/stepper/index.md
@@ -1 +1,29 @@
-## **文档完善中**
\ No newline at end of file
+## **Stepper**
+
+>
+一个步骤小控件,通过一系列步骤显示进度,对于表单的情况,Stepper特别有用,可以通过控制需要完成多个步骤才能提交的表单
+
+### 构造方法
+``` dart
+Stepper({
+ Key key,
+ @required this.steps,
+ this.physics,
+ this.type = StepperType.vertical,
+ this.currentStep = 0,
+ this.onStepTapped,
+ this.onStepContinue,
+ this.onStepCancel,
+ this.controlsBuilder,
+ })
+```
+
+### 属性介绍
+* steps: Stepper的内容,包含标题,副标题,内容
+* physics: Stepper滚动视图应如何响应用户输入
+* type = StepperType.vertical: 确定Stepper的布局类型
+* currentStep: 当前步骤索引,内容被显示
+* onStepTapped: step被点击时的回调
+* onStepContinue: 点击 继续 按钮时的回调
+* onStepCancel: 点击 取消 按钮时的回调
+* controlsBuilder: 用于创建自定义控件的回调
\ No newline at end of file
diff --git a/docs/widget/gestures/gesturedetector/index.md b/docs/widget/gestures/gesturedetector/index.md
index 83532f6..043bdcd 100644
--- a/docs/widget/gestures/gesturedetector/index.md
+++ b/docs/widget/gestures/gesturedetector/index.md
@@ -1 +1,80 @@
-## **文档完善中**
\ No newline at end of file
+## **GestureDetector**
+> 该组件可监听触摸事件,可包裹需要监听的组件后使用带有的触摸事件。
+
+### 构造函数
+```
+GestureDetector({
+ Key key,
+ this.child,
+ this.onTapDown,
+ this.onTapUp,
+ this.onTap,
+ this.onTapCancel,
+ this.onDoubleTap,
+ this.onLongPress,
+ this.onLongPressUp,
+ this.onLongPressDragStart,
+ this.onLongPressDragUpdate,
+ this.onLongPressDragUp,
+ this.onVerticalDragDown,
+ this.onVerticalDragStart,
+ this.onVerticalDragUpdate,
+ this.onVerticalDragEnd,
+ this.onVerticalDragCancel,
+ this.onHorizontalDragDown,
+ this.onHorizontalDragStart,
+ this.onHorizontalDragUpdate,
+ this.onHorizontalDragEnd,
+ this.onHorizontalDragCancel,
+ this.onForcePressStart,
+ this.onForcePressPeak,
+ this.onForcePressUpdate,
+ this.onForcePressEnd,
+ this.onPanDown,
+ this.onPanStart,
+ this.onPanUpdate,
+ this.onPanEnd,
+ this.onPanCancel,
+ this.onScaleStart,
+ this.onScaleUpdate,
+ this.onScaleEnd,
+ this.behavior,
+ this.excludeFromSemantics = false,
+ this.dragStartBehavior = DragStartBehavior.down,
+})
+```
+
+### 属性介绍
+> 点击事件可用Tap属性,执行顺序如下罗列
+- onTapDown: 触摸时触发
+- onTapUp: 触摸离开时触发
+- onTap: 点击后触发
+- onTapCancel: 触发时取消
+- onDoubleTap: 200毫秒内触摸时触发,但不触发onTap
+> 拖动事件可用Pan属性,执行顺序如下罗列,拖动时返回是手势位移数据
+- onPanDown:
+- onPanStart: (DragStartDetails e) {} 返回相对屏幕位置
+- onPanUpdate: (DragUpdateDetails e) {} 回调函数中返回是手势位移数据
+- onPanEnd: (DragEndDetails e) {} 回调函数中返回Velocity,手势瞬时速度,可结合动画使用
+- onPanCancel: 回调取消
+> 以下也可执行拖动事件,使用后不会触发Tap/Pan事件,执行顺序如下罗列,拖动时返回相对整个屏幕距离数据
+- onForcePressStart: (ForcePressDetails e) {}
+- onForcePressPeak: (ForcePressDetails e) {}
+- onForcePressUpdate: (ForcePressDetails e) {}
+- onForcePressEnd: (ForcePressDetails e) {}
+> 监听垂直或水平方向
+- onVerticalDragDown
+- onVerticalDragStart
+- onVerticalDragUpdate
+- onVerticalDragEnd
+- onVerticalDragCancel
+- onHorizontalDragDown
+- onHorizontalDragStart
+- onHorizontalDragUpdate
+- onHorizontalDragEnd
+- onHorizontalDragCancel
+> 手势放大
+- onScaleStart
+- onScaleUpdate
+- onScaleEnd
+
diff --git a/docs/widget/navigator/bottomnavigationbar/index.md b/docs/widget/navigator/bottomnavigationbar/index.md
index 83532f6..322d3a3 100644
--- a/docs/widget/navigator/bottomnavigationbar/index.md
+++ b/docs/widget/navigator/bottomnavigationbar/index.md
@@ -1 +1,40 @@
-## **文档完善中**
\ No newline at end of file
+## **BottomNavigationBar**
+> Scaffold的属性,增加底部导航栏tab
+
+### 构造函数
+```
+BottomNavigationBar({
+ Key key,
+ @required this.items,
+ this.onTap,
+ this.currentIndex = 0,
+ BottomNavigationBarType type,
+ this.fixedColor,
+ this.iconSize = 24.0,
+})
+```
+
+### 属性介绍
+- items: 数组类型,tab,通过BottomNavigationBarItem实现
+- onTap: 点击后回调函数,返回点击的数组下标,从0开始
+- currentIndex:当前激活的下标值
+- type: BottomNavigationBarType类型,默认fixed(固定位置大小,点击无动画效果),还有shifting(点击时有动画效果)
+ > fixed: 固定大小,无动画效果。
+ > shifting: 带有动画效果,只有激活的标签带有主题颜色,可自行增加默认颜色
+- fixedColor: 图标与字体颜色,当type的值为BottomNavigationBarType.shifting时,级别比较低。
+- iconSize:double类型,图标大小。
+
+### 高级用法
+- 可以定义一个变量,通过setState方法改变currentIndex的值。Scaffold中的body属性可以使用PageView,实现body页面切换带动导航栏切换,可导航栏触发body页面切换。
+- BottomNavigationBarItem:属性items中的组件
+ ```
+ BottomNavigationBarItem({
+ @required this.icon,
+ this.title,
+ Widget activeIcon,
+ this.backgroundColor,
+ })
+ ```
+ > title: 定义标题
+ > icon: 图标
+ > activeIcon: 选中时图标
\ No newline at end of file
diff --git a/docs/widget/navigator/floatingactionbutton/index.md b/docs/widget/navigator/floatingactionbutton/index.md
index 83532f6..cb07549 100644
--- a/docs/widget/navigator/floatingactionbutton/index.md
+++ b/docs/widget/navigator/floatingactionbutton/index.md
@@ -1 +1,35 @@
-## **文档完善中**
\ No newline at end of file
+## **FloatingActionButton**
+> 在Scaffold中属性floatingActionButton实现FloatingActionButton,该组件是个圆形的浮层按钮,一般情况下child可用icon进行绘画。
+
+### 构造函数
+```
+FloatingActionButton({
+ Key key,
+ this.child,
+ this.tooltip,
+ this.foregroundColor,
+ this.backgroundColor,
+ this.heroTag = const _DefaultHeroTag(),
+ this.elevation = 6.0,
+ this.highlightElevation = 12.0,
+ double disabledElevation,
+ @required this.onPressed,
+ this.mini = false,
+ this.shape = const CircleBorder(),
+ this.clipBehavior = Clip.none,
+ this.materialTapTargetSize,
+ this.isExtended = false,
+})
+```
+
+### 属性介绍
+- onPressed: 必填属性,函数调用,点击按钮后回调事件
+- child: 组件子组件内容,可通过Icon简单的增加图标
+- elevation:图标下阴影大小
+- highlightElevation: 点击后阴影扩散范围
+- tooltip:长按提示
+- foregroundColor:前景色,如图标、文字的颜色
+- backgroundColor:背景填充色
+- mini: 默认false,true时为迷你按钮
+
+
diff --git a/docs/widget/navigator/pageview/index.md b/docs/widget/navigator/pageview/index.md
new file mode 100644
index 0000000..bb90c0b
--- /dev/null
+++ b/docs/widget/navigator/pageview/index.md
@@ -0,0 +1,27 @@
+## **PageView**
+> 创建一个整屏滚动的滚动列表,逐页滚动
+
+
+### 构造函数
+```
+PageView({
+ Key key,
+ Axis scrollDirection: Axis.horizontal,
+ bool reverse: false,
+ PageController controller,
+ ScrollPhysics physics,
+ bool pageSnapping: true,
+ ValueChanged onPageChanged,
+ List children: const [],
+ DragStartBehavior dragStartBehavior: DragStartBehavior.down
+})
+```
+
+### 属性介绍
+- children:页面列表,每个子元素对应一个当前页。
+- scrollDirection: Axis.horizontal/Axis.vertical, 默认是水平方向,可选择垂直方向滚动
+- reverse: 滚动方向取反操作
+- controller: 操作页面滚动行为类,可以通过PageController实例后的对象进行指定页面跳转,可携带特效跳转等。PageController.jumpToPage(index)
+- physics: 滚动属性,可参考滚动类别中的gridview等相近属性介绍
+- pageSnapping: 默认true,切换时,自动逐页跳转。当自定义滚动行为时,可设置为false,禁止页面捕获。
+- onPageChanged: 页面切换时,回调函数,返回页面下标值
diff --git a/docs/widget/navigator/popupmenubutton/index.md b/docs/widget/navigator/popupmenubutton/index.md
index 83532f6..7a448e5 100644
--- a/docs/widget/navigator/popupmenubutton/index.md
+++ b/docs/widget/navigator/popupmenubutton/index.md
@@ -1 +1,34 @@
-## **文档完善中**
\ No newline at end of file
+## **PopupMenuButton**
+
+### 构造函数
+```
+PopupMenuButton({
+ Key key,
+ @required PopupMenuItemBuilder itemBuilder,
+ T initialValue,
+ PopupMenuItemSelected onSelected,
+ PopupMenuCanceled onCanceled,
+ String tooltip,
+ double elevation: 8.0,
+ EdgeInsetsGeometry padding: const EdgeInsets.all(8.0),
+ Widget child,
+ Icon icon,
+ Offset offset: Offset.zero
+})
+```
+
+### 属性介绍
+- itemBuilder: (_) => { return [PopupMenuItem(), PopupMenuItem(),]}
+ > PopupMenuItem: 菜单子组件
+ ```
+ PopupMenuItem({
+ Key key,
+ T value,
+ bool enabled: true,
+ double height: _kMenuItemHeight,
+ @required Widget child
+ })
+ ```
+- onSelected: 选中后返回PopupMenuItem中value的值
+- child: 有默认图标,可以修改为其它显示内容。
+
diff --git a/docs/widget/vision/transform/index.md b/docs/widget/vision/transform/index.md
index 83532f6..dc2da45 100644
--- a/docs/widget/vision/transform/index.md
+++ b/docs/widget/vision/transform/index.md
@@ -1 +1,24 @@
-## **文档完善中**
\ No newline at end of file
+## **Transform**
+
+> 在绘制子元素前应用转换的组件
+
+### 构造方法
+```
+Transform({
+ Key key,
+ @required Matrix4 transform,
+ Offset origin,
+ AlignmentGeometry alignment,
+ bool transformHitTests: true,
+ Widget child
+})
+```
+
+### 属性介绍
+origin:坐标系的原点(相对于此渲染对象的左上角)应用矩阵的原点
+alignment:原点的对齐方式
+transform: 在绘制过程中改变子元素的矩阵
+transformHitTests:在测试时是否执行转换
+
+
+### 实例
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 5ba8d87..565be38 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -8,7 +8,6 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
- 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -20,6 +19,8 @@
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 */; };
+ BA61DFEF7B89A2B0064AE279 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D7BE9010C4F7FF033BA299B7 /* libPods-Runner.a */; };
+ BEBBA522223FEA6600583D52 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BEBBA521223FEA6600583D52 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -38,9 +39,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 13BE6F8BF79FED0958E617CA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
- 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
+ 15BE2897D1518D9BDD5AF970 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
@@ -55,6 +57,9 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ BEBBA521223FEA6600583D52 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
+ D7BE9010C4F7FF033BA299B7 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDCB5E5FC17434D1FF8247D2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -64,16 +69,34 @@
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
+ BA61DFEF7B89A2B0064AE279 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 607E308685FBC1196333D679 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ D7BE9010C4F7FF033BA299B7 /* libPods-Runner.a */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 8B5D251E963699100C93BD5E /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ FDCB5E5FC17434D1FF8247D2 /* Pods-Runner.debug.xcconfig */,
+ 13BE6F8BF79FED0958E617CA /* Pods-Runner.release.xcconfig */,
+ 15BE2897D1518D9BDD5AF970 /* Pods-Runner.profile.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "";
+ };
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
- 2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
@@ -90,7 +113,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
- CF3B75C9A7D2FA2A4C99F110 /* Frameworks */,
+ 8B5D251E963699100C93BD5E /* Pods */,
+ 607E308685FBC1196333D679 /* Frameworks */,
);
sourceTree = "";
};
@@ -105,6 +129,7 @@
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
+ BEBBA521223FEA6600583D52 /* GoogleService-Info.plist */,
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
@@ -133,12 +158,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ 9C2B8B9B587696DA01082626 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ EB6D2D2E068567EE260A8427 /* [CP] Embed Pods Frameworks */,
+ CFD61D2B0A4C5DCF2308F823 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -160,6 +188,8 @@
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
+ DevelopmentTeam = 5K9P57YFSL;
+ ProvisioningStyle = Automatic;
};
};
};
@@ -168,6 +198,7 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
+ English,
en,
Base,
);
@@ -190,8 +221,8 @@
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
- 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ BEBBA522223FEA6600583D52 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -226,6 +257,60 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ 9C2B8B9B587696DA01082626 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ CFD61D2B0A4C5DCF2308F823 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
+ "${PODS_CONFIGURATION_BUILD_DIR}/flutter_downloader/FlutterDownloaderDatabase.bundle",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/FlutterDownloaderDatabase.bundle",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ EB6D2D2E068567EE260A8427 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
+ "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -314,8 +399,10 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = S8QB4VV633;
+ DEVELOPMENT_TEAM = 5K9P57YFSL;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -327,8 +414,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.efoxFlutter;
+ PRODUCT_BUNDLE_IDENTIFIER = com.flutterken.ui;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
@@ -440,7 +528,10 @@
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 5K9P57YFSL;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -452,8 +543,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.efoxFlutter;
+ PRODUCT_BUNDLE_IDENTIFIER = com.flutterken.ui;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -463,7 +555,10 @@
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+ DEVELOPMENT_TEAM = 5K9P57YFSL;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -475,8 +570,9 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.efoxFlutter;
+ PRODUCT_BUNDLE_IDENTIFIER = com.flutterken.ui;
PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..949b678
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ BuildSystemType
+ Original
+
+
diff --git a/ios/Runner/AppDelegate.m b/ios/Runner/AppDelegate.m
index 59a72e9..c185aa5 100644
--- a/ios/Runner/AppDelegate.m
+++ b/ios/Runner/AppDelegate.m
@@ -1,10 +1,15 @@
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
+@import Firebase;//增加 firebase 支持
+
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ [FIRApp configure];//增加 firebase 支持
+
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist
new file mode 100644
index 0000000..bf356a4
--- /dev/null
+++ b/ios/Runner/GoogleService-Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ AD_UNIT_ID_FOR_BANNER_TEST
+ ca-app-pub-3940256099942544/2934735716
+ AD_UNIT_ID_FOR_INTERSTITIAL_TEST
+ ca-app-pub-3940256099942544/4411468910
+ CLIENT_ID
+ 27281760426-agmn2b0f4dr988t098rm5259v7i7cbkf.apps.googleusercontent.com
+ REVERSED_CLIENT_ID
+ com.googleusercontent.apps.27281760426-agmn2b0f4dr988t098rm5259v7i7cbkf
+ API_KEY
+ AIzaSyBUOZNJqMvIF_QEJGHXu0ponVCGPo5YarI
+ GCM_SENDER_ID
+ 27281760426
+ PLIST_VERSION
+ 1
+ BUNDLE_ID
+ com.flutter.beer
+ PROJECT_ID
+ efox-flutter
+ STORAGE_BUCKET
+ efox-flutter.appspot.com
+ IS_ADS_ENABLED
+
+ IS_ANALYTICS_ENABLED
+
+ IS_APPINVITE_ENABLED
+
+ IS_GCM_ENABLED
+
+ IS_SIGNIN_ENABLED
+
+ GOOGLE_APP_ID
+ 1:27281760426:ios:51548b1d738060a2
+ DATABASE_URL
+ https://efox-flutter.firebaseio.com
+
+
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 2f03a2f..a5b0ab9 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -4,6 +4,8 @@
CFBundleDevelopmentRegion
en
+ CFBundleDisplayName
+ flutter ui
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
diff --git a/lib/components/baseComp.dart b/lib/components/baseComp.dart
deleted file mode 100644
index 95c55b0..0000000
--- a/lib/components/baseComp.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:efox_flutter/store/index.dart' show Store;
-import 'headerComp.dart' as Header;
-
-class Index extends StatelessWidget {
- final dynamic child;
- final String title;
-
- Index({Key key, this.title, this.child}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return Store.connect(builder: (context, child, model) {
- return Scaffold(
- appBar: AppBar(
- title: Header.Index(this.title),
- ),
- body: ListView(
- children: [this.child(context, child, model)],
- ),
- );
- });
- }
-}
-
-//import 'package:flutter/material.dart';
-//import 'package:efox_flutter/page/Index.dart';
-//
-//class TestDemo extends StatefulWidget {
-// @override
-// _TestDemoState createState() => new _TestDemoState();
-//}
-//
-//class _TestDemoState extends State {
-// @override
-// Widget build(BuildContext context) {
-// return Index(
-// title: 'TestDemo',
-// child: (context, child, model) {
-// return Center(
-// child: Text(
-// 'Test title',
-// style: TextStyle(
-// fontSize: 22.0,
-// ),
-// ),
-// );
-// },
-// );
-// }
-//}
diff --git a/lib/components/exampleComp.dart b/lib/components/exampleComp.dart
deleted file mode 100644
index 37b53f7..0000000
--- a/lib/components/exampleComp.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:efox_flutter/store/models/main_state_model.dart'
- show MainStateModel;
-import 'package:efox_flutter/store/index.dart' show Store;
-import 'package:efox_flutter/config/theme.dart' show AppTheme;
-
-class Index extends StatelessWidget {
- final Widget child;
-
- Index({Key key, this.child}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- Size size = MediaQuery.of(context).size;
- double _dp = 1.5;
- return Store.connect(
- builder: (context, child, MainStateModel model) {
- return Center(
- child: Container(
- width: size.width,
- height: size.height / _dp,
- margin: EdgeInsets.all(30 / _dp),
- decoration: BoxDecoration(
- border: Border.all(color: Color(AppTheme.mainColor), width: 1.0),
- ),
- child: this.child,
- ),
- );
- },
- );
- }
-}
diff --git a/lib/components/example_comp.dart b/lib/components/example_comp.dart
new file mode 100644
index 0000000..baf6d96
--- /dev/null
+++ b/lib/components/example_comp.dart
@@ -0,0 +1,25 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/config/theme.dart' show AppTheme;
+
+class Index extends StatelessWidget {
+ final Widget child;
+
+ Index({Key key, this.child}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ Size size = MediaQuery.of(context).size;
+ return Center(
+ child: Container(
+ margin: EdgeInsets.all(10),
+ decoration: BoxDecoration(
+ border: Border.all(color: Color(AppTheme.mainColor), width: 1.0),
+ ),
+ child: SizedBox.fromSize(
+ size: size / 1.3,
+ child: this.child,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/components/expansion_tile.dart b/lib/components/expansion_tile.dart
new file mode 100644
index 0000000..21e3089
--- /dev/null
+++ b/lib/components/expansion_tile.dart
@@ -0,0 +1,222 @@
+// Copyright 2017 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';
+
+const Duration _kExpand = Duration(milliseconds: 200);
+
+/// A single-line [ListTile] with a trailing button that expands or collapses
+/// the tile to reveal or hide the [children].
+///
+/// This widget is typically used with [ListView] to create an
+/// "expand / collapse" list entry. When used with scrolling widgets like
+/// [ListView], a unique [PageStorageKey] must be specified to enable the
+/// [ExpansionTile] to save and restore its expanded state when it is scrolled
+/// in and out of view.
+///
+/// See also:
+///
+/// * [ListTile], useful for creating expansion tile [children] when the
+/// expansion tile represents a sublist.
+/// * The "Expand/collapse" section of
+/// .
+class ExpansionTile extends StatefulWidget {
+ /// Creates a single-line [ListTile] with a trailing button that expands or collapses
+ /// the tile to reveal or hide the [children]. The [initiallyExpanded] property must
+ /// be non-null.
+ const ExpansionTile({
+ Key key,
+ this.headerBackgroundColor,
+ this.leading,
+ @required this.title,
+ this.backgroundColor,
+ this.iconColor,
+ this.onExpansionChanged,
+ this.children = const [],
+ this.trailing,
+ this.initiallyExpanded = false,
+ }) : assert(initiallyExpanded != null),
+ super(key: key);
+
+ /// A widget to display before the title.
+ ///
+ /// Typically a [CircleAvatar] widget.
+ final Widget leading;
+
+ /// The primary content of the list item.
+ ///
+ /// Typically a [Text] widget.
+ final Widget title;
+
+ /// Called when the tile expands or collapses.
+ ///
+ /// When the tile starts expanding, this function is called with the value
+ /// true. When the tile starts collapsing, this function is called with
+ /// the value false.
+ final ValueChanged onExpansionChanged;
+
+ /// The widgets that are displayed when the tile expands.
+ ///
+ /// Typically [ListTile] widgets.
+ final List children;
+
+ /// The color to display behind the sublist when expanded.
+ final Color backgroundColor;
+
+ /// The color to display the background of the header.
+ final Color headerBackgroundColor;
+
+ /// The color to display the icon of the header.
+ final Color iconColor;
+
+ /// A widget to display instead of a rotating arrow icon.
+ final Widget trailing;
+
+ /// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
+ final bool initiallyExpanded;
+
+ @override
+ _ExpansionTileState createState() => _ExpansionTileState();
+}
+
+class _ExpansionTileState extends State
+ with SingleTickerProviderStateMixin {
+ static final Animatable _easeOutTween =
+ CurveTween(curve: Curves.easeOut);
+ static final Animatable _easeInTween =
+ CurveTween(curve: Curves.easeIn);
+ static final Animatable _halfTween =
+ Tween(begin: 0.0, end: 0.5);
+
+ final ColorTween _borderColorTween = ColorTween();
+ final ColorTween _headerColorTween = ColorTween();
+ final ColorTween _iconColorTween = ColorTween();
+ final ColorTween _backgroundColorTween = ColorTween();
+
+ AnimationController _controller;
+ Animation _iconTurns;
+ Animation _heightFactor;
+ Animation _borderColor;
+ Animation _headerColor;
+ Animation _iconColor;
+ Animation _backgroundColor;
+
+ bool _isExpanded = false;
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = AnimationController(duration: _kExpand, vsync: this);
+ _heightFactor = _controller.drive(_easeInTween);
+ _iconTurns = _controller.drive(_halfTween.chain(_easeInTween));
+ _borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween));
+ _headerColor = _controller.drive(_headerColorTween.chain(_easeInTween));
+ _iconColor = _controller.drive(_iconColorTween.chain(_easeInTween));
+ _backgroundColor =
+ _controller.drive(_backgroundColorTween.chain(_easeOutTween));
+
+ _isExpanded =
+ PageStorage.of(context)?.readState(context) ?? widget.initiallyExpanded;
+ if (_isExpanded) _controller.value = 1.0;
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ void _handleTap() {
+ setState(() {
+ _isExpanded = !_isExpanded;
+ if (_isExpanded) {
+ _controller.forward();
+ } else {
+ _controller.reverse().then((void value) {
+ if (!mounted) return;
+ setState(() {
+ // Rebuild without widget.children.
+ });
+ });
+ }
+ PageStorage.of(context)?.writeState(context, _isExpanded);
+ });
+ if (widget.onExpansionChanged != null)
+ widget.onExpansionChanged(_isExpanded);
+ }
+
+ Widget _buildChildren(BuildContext context, Widget child) {
+ final Color borderSideColor = _borderColor.value ?? Colors.transparent;
+ final Color titleColor = _headerColor.value;
+
+ return Container(
+ decoration: BoxDecoration(
+ color: _backgroundColor.value ?? Colors.transparent,
+ border: Border(
+ top: BorderSide(color: borderSideColor),
+ bottom: BorderSide(color: borderSideColor),
+ )),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ IconTheme.merge(
+ data: IconThemeData(color: _iconColor.value),
+ child: Container(
+ color: widget.headerBackgroundColor ?? Colors.black,
+ child: ListTile(
+ onTap: _handleTap,
+ leading: widget.leading,
+ title: DefaultTextStyle(
+ style: Theme.of(context)
+ .textTheme
+ .subhead
+ .copyWith(color: titleColor),
+ child: widget.title,
+ ),
+ trailing: widget.trailing ??
+ RotationTransition(
+ turns: _iconTurns,
+ child: Icon(
+ Icons.expand_more,
+ color: widget.iconColor ?? Colors.grey,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ClipRect(
+ child: Align(
+ heightFactor: _heightFactor.value,
+ child: child,
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ @override
+ void didChangeDependencies() {
+ final ThemeData theme = Theme.of(context);
+ _borderColorTween..end = theme.dividerColor;
+ _headerColorTween
+ ..begin = theme.textTheme.subhead.color
+ ..end = theme.primaryColor;
+ _iconColorTween
+ ..begin = theme.unselectedWidgetColor
+ ..end = theme.primaryColor;
+ _backgroundColorTween..end = widget.backgroundColor;
+ super.didChangeDependencies();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final bool closed = !_isExpanded && _controller.isDismissed;
+ return AnimatedBuilder(
+ animation: _controller.view,
+ builder: _buildChildren,
+ child: closed ? null : Column(children: widget.children),
+ );
+ }
+}
diff --git a/lib/components/headerComp.dart b/lib/components/headerComp.dart
deleted file mode 100644
index b1c3b52..0000000
--- a/lib/components/headerComp.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-import 'package:flutter/material.dart';
-
-class Index extends StatelessWidget {
- final String text;
- Index(this.text);
- @override
- Widget build(BuildContext context) {
- return Text(
- this.text,
- style: TextStyle(
- // fontStyle: FontStyle.normal,
- ),
- );
- }
-}
diff --git a/lib/components/markdownComp.dart b/lib/components/markdown_comp.dart
similarity index 100%
rename from lib/components/markdownComp.dart
rename to lib/components/markdown_comp.dart
diff --git a/lib/components/updatingComp.dart b/lib/components/updating_comp.dart
similarity index 100%
rename from lib/components/updatingComp.dart
rename to lib/components/updating_comp.dart
diff --git a/lib/components/webviewComp.dart b/lib/components/webview_comp.dart
similarity index 62%
rename from lib/components/webviewComp.dart
rename to lib/components/webview_comp.dart
index 499d58d..60c68aa 100644
--- a/lib/components/webviewComp.dart
+++ b/lib/components/webview_comp.dart
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
-import 'headerComp.dart' as Header;
-import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' show FlutterWebviewPlugin, WebviewScaffold;
+import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'
+ show FlutterWebviewPlugin, WebviewScaffold;
class Index extends StatelessWidget {
final String url;
@@ -18,17 +18,21 @@ class Index extends StatelessWidget {
Widget build(BuildContext context) {
return WebviewScaffold(
url: this.url,
- appBar: new AppBar(
- title: Header.Index(this.title),
+ enableAppScheme: false,
+ appBar: AppBar(
+ elevation: 0,
+ title: Text(
+ this.title,
+ ),
+ leading: IconButton(
+ icon: Icon(Icons.arrow_back),
+ color: Theme.of(context).primaryTextTheme.title.color,
+ onPressed: () => Navigator.pop(context),
+ ),
),
withZoom: true,
withLocalStorage: true,
hidden: true,
- // initialChild: Container(
- // child: const Center(
- // child: CircularProgressIndicator(),
- // ),
- // ),
);
}
}
diff --git a/lib/components/widgetComp.dart b/lib/components/widgetComp.dart
deleted file mode 100644
index 8a06d9d..0000000
--- a/lib/components/widgetComp.dart
+++ /dev/null
@@ -1,214 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:efox_flutter/store/index.dart' show Store;
-import 'headerComp.dart' as Header;
-import 'package:efox_flutter/components/markdownComp.dart' as MarkDownComp;
-import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
-import 'package:efox_flutter/components/baseComp.dart' as BaseComp;
-import 'package:efox_flutter/components/exampleComp.dart' as ExampleComp;
-import 'package:efox_flutter/components/updatingComp.dart' as UpdatingComp;
-import 'package:efox_flutter/utils/file.dart' as FileUtils;
-import 'package:efox_flutter/utils/loadAsset.dart' as LoadAssetUtils;
-import 'package:efox_flutter/router/index.dart' show FluroRouter;
-import 'package:efox_flutter/config/theme.dart' show AppTheme;
-import 'package:efox_flutter/utils/share.dart' as AppShare;
-
-class Index extends StatefulWidget {
- final List demoChild;
- final String originCodeUrl;
- final String mdUrl;
- final String title;
- Index({
- Key key,
- this.title,
- this.demoChild,
- this.originCodeUrl,
- this.mdUrl,
- }) : super(key: key);
-
- @override
- State createState() => IndexState(
- title: title,
- demoChild: demoChild,
- originCodeUrl: originCodeUrl,
- mdUrl: mdUrl);
-}
-
-class IndexState extends State {
- List _bodyList = [];
- final dynamic modelChild;
- final List mdList;
- final List demoChild;
- final String originCodeUrl;
- final String mdUrl;
- final String title;
- bool loading = true;
- dynamic model;
-
- IndexState({
- Key key,
- this.title,
- this.modelChild,
- this.mdList,
- this.demoChild,
- this.originCodeUrl,
- this.mdUrl,
- });
-
- @override
- void initState() {
- super.initState();
- this.init();
- }
-
- void init() async {
- this._bodyList.length = 0;
- String mdText = await this.getMdFile(this.mdUrl);
- if (mdText.length > 30) {
- this
- ._bodyList
- .add(await MarkDownComp.Index(mdText));
- // demo
- if (this.demoChild != null && this.demoChild.length > 0) {
- this.demoChild.forEach((Widget item) {
- this._bodyList.add(ExampleComp.Index(child: item));
- });
- }
- } else {
- this._bodyList.add(UpdatingComp.Index());
- }
- setState(() {
- this.loading = false;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- return Store.connect(builder: (context, child, model) {
- this.model = model;
- return Scaffold(
- appBar: AppBar(
- title: Header.Index(
- this.title,
- ),
- actions: this.getActions(
- context,
- ),
- ),
- body: this.loading ? this.renderLoading() : this.renderWidget(),
- );
- });
- }
-
- openPage(context) async {
- String url = this.mdUrl;
- // 加载页面
- if (this.model.config.state.isPro) {
- FluroRouter.router.navigateTo(context,
- '/webview?title=${this.title}&url=${Uri.encodeComponent(this.model.config.state.env.githubAssetOrigin + url.replaceAll(RegExp('/index.md'), '').replaceAll('docs', 'lib'))}');
- } else {
- // 加载本地
- String mdStr = await FileUtils.readLocaleFile(url);
- Navigator.of(context).push(
- MaterialPageRoute(builder: (BuildContext context) {
- return BaseComp.Index(
- title: this.title,
- child: (context, child, model) {
- return MarkDownComp.Index(mdStr);
- },
- );
- }),
- );
- }
- }
-
- Future getMdFile(url) async {
- String mdStr = (await LoadAssetUtils.loadMarkdownAssets(url)).toString();
- return mdStr;
- }
-
- getActions(context) {
- return [
- IconButton(
- icon: Icon(
- Icons.insert_link,
- ),
- onPressed: () async {
- FluroRouter.router.navigateTo(
- context,
- '/webview?title=${this.title}&url=${Uri.encodeComponent(this.originCodeUrl)}',
- );
- },
- ),
- IconButton(
- icon: Icon(
- Icons.code,
- ),
- onPressed: () async {
- this.openPage(context);
- },
- ),
- IconButton(
- icon: Icon(Icons.share),
- onPressed: () {
- final String msg =
- this.model.config.state.env.githubAssetOrigin + this.mdUrl;
- AppShare.shareText(msg);
- },
- ),
- ];
- }
-
- Widget renderLoading() {
- return Center(
- child: Stack(
- children: [
- // 遮罩
- Opacity(
- opacity: .8,
- child: ModalBarrier(
- color: Colors.black87,
- ),
- ),
- // 居中显示
- Center(
- child: Container(
- padding: const EdgeInsets.all(20.0),
- decoration: BoxDecoration(
- color: Colors.black87,
- borderRadius: BorderRadius.circular(4.0),
- ),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisSize: MainAxisSize.min,
- children: [
- CircularProgressIndicator(
- strokeWidth: 4,
- ),
- Container(
- padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0),
- child: Text(
- AppLocalizations.$t('loading'),
- style: TextStyle(
- color: Color(AppTheme.secondColor), fontSize: 20.0),
- ),
- )
- ],
- ),
- ),
- ),
- ],
- ),
- );
- }
-
- Widget renderWidget() {
- // 加载完成后返回页面
- return Scrollbar(
- child: ListView(
- padding: EdgeInsets.all(10.0),
- children: this._bodyList,
- ),
- );
- }
-}
diff --git a/lib/components/widget_comp.dart b/lib/components/widget_comp.dart
new file mode 100644
index 0000000..be5db94
--- /dev/null
+++ b/lib/components/widget_comp.dart
@@ -0,0 +1,241 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/components/markdown_comp.dart' as markdown_comp;
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+import 'package:efox_flutter/components/example_comp.dart' as example_comp;
+import 'package:efox_flutter/components/updating_comp.dart' as updating_comp;
+import 'package:efox_flutter/utils/loadAsset.dart' as AssetUtils;
+import 'package:efox_flutter/router/index.dart' show FluroRouter;
+import 'package:efox_flutter/config/theme.dart' show AppTheme;
+import 'package:efox_flutter/utils/share.dart' as AppShare;
+import 'package:efox_flutter/widget/author_list.dart' as AuthorList;
+import 'package:efox_flutter/store/objects/author_info.dart' show AuthorInfo;
+import 'package:efox_flutter/store/index.dart' show AuthorModel, ConfigModel, Store;
+
+class Index extends StatefulWidget {
+ final List demoChild;
+ final String originCodeUrl;
+ final String mdUrl;
+ final String title;
+ Index({
+ Key key,
+ this.title,
+ this.demoChild,
+ this.originCodeUrl,
+ this.mdUrl,
+ }) : super(key: key);
+
+ @override
+ State createState() => IndexState();
+}
+
+class IndexState extends State {
+ List _bodyList = [];
+ bool loading = true;
+ dynamic model;
+
+ @override
+ void initState() {
+ super.initState();
+ this.init();
+ }
+
+ authorTile(nameKey) {
+ AuthorInfo info = Store.value(context).list[nameKey];
+ return Container(
+ child: ListTile(
+ onTap: () {
+ FluroRouter.webview(context: context, title: 'GitHub-' + info.name, url: Uri.encodeComponent(info.url));
+ },
+ leading: CircleAvatar(
+ backgroundImage: NetworkImage(
+ info.avatarUrl,
+ ),
+ radius: 30,
+ ),
+ title: Text(
+ info.name,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20,
+ ),
+ ),
+ subtitle: Text(
+ info.url,
+ style: TextStyle(color: Colors.grey),
+ ),
+ trailing: Icon(
+ Icons.keyboard_arrow_right,
+ color: Color(AppTheme.mainColor),
+ ),
+ ),
+ );
+ }
+
+ void init() async {
+ this._bodyList.length = 0;
+ String mdText = await this.getMdFile(widget.mdUrl);
+ String nameKey = AuthorList.list[widget.title];
+ /*if (nameKey != null) {
+ this._bodyList.add(authorTile(nameKey));
+ this._bodyList.add(Divider());
+ }*/
+ print('文档完成长度:${mdText.length}');
+ if (mdText.length > 30) {
+ this._bodyList.add(await markdown_comp.Index(mdText));
+ // demo
+ if (widget.demoChild != null && widget.demoChild.length > 0) {
+ widget.demoChild.forEach((Widget item) {
+ this._bodyList.add(example_comp.Index(child: item));
+ });
+ }
+ } else {
+ this._bodyList.add(updating_comp.Index());
+ }
+ setState(() {
+ this.loading = false;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ print('widget_comp context =$context');
+ return Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ backgroundColor: Color(AppTheme.secondColor),
+ actions: this.getActions(
+ context,
+ ),
+ brightness: Brightness.light,
+ leading: IconButton(
+ icon: Icon(Icons.arrow_back),
+ color: Color(AppTheme.blackColor),
+ onPressed: () => Navigator.pop(context),
+ ),
+ ),
+ body: this.loading ? this.renderLoading() : this.renderWidget(),
+ );
+ }
+
+ showCode(context) async {
+ /*if (Store.value(context).isPro) {
+ // 线上文档
+ FluroRouter.router.navigateTo(
+ context,
+ 'webview?title=${widget.title}&url=${Uri.encodeComponent(Store.value(context).env.githubAssetOrigin+widget.mdUrl)}'
+ );
+ } else {*/
+ // 加载本地
+ String mdStr = await AssetUtils.readLocaleFile(widget.mdUrl);
+ Navigator.of(context).push(
+ MaterialPageRoute(builder: (BuildContext build) {
+ return Scaffold(
+ appBar: AppBar(title: Text(widget.title),),
+ body: ListView(
+ children: [markdown_comp.Index(mdStr)],
+ ),
+ );
+ })
+ );
+ //}
+ }
+
+ Future getMdFile(url) async {
+ // bool productionEnv = Store.value(context).isPro;
+ bool productionEnv = false;
+ if (productionEnv) {
+ return await AssetUtils.readRemoteFile(url);
+ } else {
+ return await AssetUtils.readLocaleFile(url);
+ }
+ }
+
+ getActions(context) {
+ return [
+ /*IconButton(
+ color: Color(AppTheme.blackColor),
+ icon: Icon(
+ Icons.code
+ ),
+ onPressed: () async {
+ this.showCode(context);
+ },
+ ),
+ IconButton(
+ color: Color(AppTheme.blackColor),
+ icon: Icon(
+ Icons.insert_link,
+ ),
+ onPressed: () async {
+ FluroRouter.router.navigateTo(
+ context,
+ '/webview?title=${widget.title}&url=${Uri.encodeComponent(widget.originCodeUrl)}',
+ );
+ },
+ ),*/
+ IconButton(
+ icon: Icon(Icons.share),
+ color: Color(AppTheme.blackColor),
+ onPressed: () {
+ dynamic origin =
+ Store.value(context).env.githubAssetOrigin;
+ AppShare.shareText(origin + widget.mdUrl);
+ },
+ ),
+ ];
+ }
+
+ Widget renderLoading() {
+ return Center(
+ child: Stack(
+ children: [
+ // 遮罩
+ Opacity(
+ opacity: .8,
+ child: ModalBarrier(
+ color: Colors.black87,
+ ),
+ ),
+ // 居中显示
+ Center(
+ child: Container(
+ padding: const EdgeInsets.all(20.0),
+ decoration: BoxDecoration(
+ color: Colors.black87,
+ borderRadius: BorderRadius.circular(4.0),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ CircularProgressIndicator(
+ strokeWidth: 4,
+ ),
+ Container(
+ padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0),
+ child: Text(
+ AppLocalizations.$t('loading'),
+ style: TextStyle(
+ color: Color(AppTheme.secondColor), fontSize: 20.0),
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget renderWidget() {
+ // 加载完成后返回页面
+ return Scrollbar(
+ child: ListView(
+ padding: EdgeInsets.all(10.0),
+ children: this._bodyList,
+ ),
+ );
+ }
+}
diff --git a/lib/config/color.dart b/lib/config/color.dart
new file mode 100644
index 0000000..1cbf1da
--- /dev/null
+++ b/lib/config/color.dart
@@ -0,0 +1,26 @@
+Map materialColor = {
+ 'red': 0xFFF44336,
+ 'pink': 0xFFE91E63,
+ 'purple': 0xFF9C27B0,
+ 'deepPurple': 0xFF673AB7,
+ 'indigo': 0xFF3F51B5,
+ //
+
+ 'blue': 0xFF2196F3,
+ 'lightBlue': 0xFF03A9F4,
+ 'cyan': 0xFF00BCD4,
+ 'teal': 0xFF009688,
+ 'green': 0xFF4CAF50,
+ //
+ 'lightGreen': 0xFF8BC34A,
+ 'lime': 0xFFCDDC39,
+ 'yellow': 0xFFFFEB3B,
+ 'amber': 0xFFFFC107,
+ 'orange': 0xFFFF9800,
+ //
+ 'deepOrange': 0xFFFF5722,
+ 'brown': 0xFF795548,
+ 'grey': 0xFF9E9E9E,
+ 'blueGrey': 0xFF607D8B,
+ 'black': 0xFF222222,
+};
diff --git a/lib/config/index.dart b/lib/config/index.dart
index 350fcd5..787f047 100644
--- a/lib/config/index.dart
+++ b/lib/config/index.dart
@@ -1,6 +1,7 @@
import 'development.dart' as Development;
import 'production.dart' as Production;
-const bool isPro = true;
+const bool isPro = false;
+const String owner_repo = 'efoxTeam/flutter-ui';
Object env = isPro ? Production.Config() : Development.Config();
diff --git a/lib/config/theme.dart b/lib/config/theme.dart
index 4746a6c..4d34214 100644
--- a/lib/config/theme.dart
+++ b/lib/config/theme.dart
@@ -1,30 +1,48 @@
import 'package:flutter/material.dart';
+import 'color.dart' show materialColor;
+/**
+ * yello #FFEB3B
+ * red #F44336
+ * blue #2196F3
+ */
class AppTheme {
- static int mainColor = 0xFFD32F2F;
+ //static int mainColor = 0xFFD32F2F;
+ static int mainColor = materialColor['red'];
static int secondColor = 0xFFFFFFFF;
static int thirdColor = 0xFFFAFAFA;
static int greyColor = 0x8A000000;
static int blackColor = 0xFF000000;
- static ThemeData themData = ThemeData(
- textTheme: TextTheme(
- body1: TextStyle(
- // color: Colors.black,
- // fontWeight: FontWeight.bold,
- ),
- ),
- platform: TargetPlatform.iOS,
- iconTheme: IconThemeData(
- size: 32,
- color: Color(thirdColor),
- opacity: 0.85,
- ),
- // primaryIconTheme 导航栏按钮颜色
- primaryIconTheme: IconThemeData(
- color: Color(secondColor),
- ),
- accentColor: Colors.grey, // 选中颜色
- primaryColor: Color(mainColor), // appbar背景
- scaffoldBackgroundColor: Color(thirdColor), // 整体的scaffold背景颜色
- );
+ static int lineColor = 0xFFEEEEEE;
+ static getThemeData(String theme) {
+ print('==================================getThemeData=$theme');
+ mainColor = materialColor[theme];
+ ThemeData themData = ThemeData(
+ textTheme: TextTheme(
+ body1: TextStyle(
+ // color: Colors.black,
+ // fontWeight: FontWeight.bold,
+ ),
+ ),
+ //platform: TargetPlatform.iOS,
+ iconTheme: IconThemeData(
+ size: 32,
+ color: Color(thirdColor),
+ opacity: 0.85,
+ ),
+ // primaryIconTheme 导航栏按钮颜色
+ primaryIconTheme: IconThemeData(
+ color: Color(secondColor),
+ ),
+ accentColor: Colors.grey, // 选中颜色
+ primaryColor: Color(mainColor), // appbar背景
+ primaryTextTheme: TextTheme(
+ title: TextStyle(
+ // color: Colors.red
+ ),
+ button: TextStyle(color: Colors.red)),
+ scaffoldBackgroundColor: Color(secondColor), // 整体的scaffold背景颜色
+ );
+ return themData;
+ }
}
diff --git a/lib/controller/index.dart b/lib/controller/index.dart
index 48c6efc..6e4b37d 100644
--- a/lib/controller/index.dart
+++ b/lib/controller/index.dart
@@ -1,5 +1,19 @@
-import 'package:efox_flutter/store/index.dart' show model;
+import 'package:efox_flutter/store/index.dart'
+ show Store, ConfigModel, UserModel;
-void initState() {
- model.dispatch('config', 'setVersion');
-}
\ No newline at end of file
+import 'package:efox_flutter/utils/appVersion.dart' show AppVersion;
+
+void initState() async {
+ // 获取版本号
+ Store.value().getAppVersion();
+ // 登录
+ /*Store.value().getLocalUserInfo().then((res) {
+ if (res) {
+ Store.value().getUserStar();
+ }
+ });*/
+ // Store.value().getFlutterUIStar();
+ Future.delayed(Duration(seconds: 3), () {
+ AppVersion().check(Store.context);
+ });
+}
diff --git a/lib/http/index.dart b/lib/http/index.dart
new file mode 100644
index 0000000..9ae1631
--- /dev/null
+++ b/lib/http/index.dart
@@ -0,0 +1,89 @@
+import 'package:dio/dio.dart'
+ show
+ Dio,
+ DioError,
+ Options,
+ InterceptorsWrapper,
+ RequestOptions,
+ LogInterceptor,
+ Response;
+import 'package:efox_flutter/utils/localStorage.dart' show LocalStorage;
+import 'loading.dart' as AppLoading;
+
+Dio getDio({options, loading}) {
+ if (options == null) {
+ options = Options(
+ headers: {
+ 'context-type': 'application/json',
+ },
+ );
+ }
+ Dio dio = new Dio(); // with default Options
+
+ // dio.options.baseUrl = "http://www.dtworkroom.com/doris/1/2.0.0/";
+ dio.options.connectTimeout = 30 * 1000; //5s
+ dio.options.receiveTimeout = 30 * 1000;
+ dio.options.headers = options.headers;
+
+ // Add request interceptor
+ dio.interceptors.add(InterceptorsWrapper(
+ onRequest: (RequestOptions options) async {
+ String token = await LocalStorage.get('githubRespLoginToken');
+ if (options.headers['Authorization'] == null && token != null) {
+ options.headers['Authorization'] = 'token $token';
+ }
+ await AppLoading.beforeRequest(options.uri, loading);
+ print('=========【发送请求】Start============');
+ print("请求地址 ${options.uri}");
+ print("请求头 ${options.headers}");
+ print("请求参数 ${options.data}");
+ print('=========【发送请求】End============');
+ return options;
+ },
+ onResponse: (Response response) async {
+ print('=========【请求成功】Start============');
+ print("请求地址 ${response.request.uri}");
+ print("请求头 ${response.statusCode}");
+ print("返回值 ${response.data}");
+ print('=========【请求成功】End============');
+ await AppLoading.afterResponse(response.request.uri, loading);
+ return response;
+ },
+ onError: (DioError e) async {
+ print('e.request.uri=======================${e.request}');
+ if (e.request != null && e.request.uri != null)
+ await AppLoading.afterResponse(e.request.uri, loading);
+ dynamic msg = e.message;
+ dynamic code = 0; // 错误码
+ dynamic status = e.type; // http请求状态
+ if (e.response != null && e.response.data != null) {
+ code = 1;
+ msg = e.response.data;
+ status = e.response.statusCode;
+ }
+ print('========【请求失败 Start】=============');
+ print("请求地址 ${e.request}");
+ print("状态码 ${status}");
+ print("返回msg ${msg}");
+ print('=========【请求失败 End】============');
+ return dio.reject({'msg': msg, 'code': code, 'status': status});
+ },
+ ));
+ dio.interceptors.add(LogInterceptor(responseBody: false)); //开启请求日志
+
+ return dio;
+}
+
+Future get({url, data = const {}, options, loading}) async {
+ return getDio(options: options, loading: loading ?? Map()).get(url);
+}
+
+Future post({url, data = const {}, options, loading}) async {
+ return getDio(options: options, loading: loading ?? Map())
+ .post(url, data: data);
+}
+
+Future put({url, data = const {}, options, loading}) async {
+ return getDio(options: options, loading: loading ?? Map())
+ .put(url, data: data);
+}
diff --git a/lib/http/loading.dart b/lib/http/loading.dart
new file mode 100644
index 0000000..ecac0b3
--- /dev/null
+++ b/lib/http/loading.dart
@@ -0,0 +1,92 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/store/index.dart' show Store;
+
+
+bool loading = false;
+Set dict = Set();
+
+void beforeRequest(uri, Map options) {
+ dict.add(uri);
+ if (loading == false) {
+ showAppLoading(options);
+ loading = true;
+ }
+}
+
+void afterResponse(uri, Map options) {
+ dict.remove(uri);
+ if (dict.length == 0 && loading == true) {
+ Navigator.of(Store.context, rootNavigator: true).pop('close dialog');
+ loading = false;
+ }
+}
+
+/**
+ * loading: 可配置参数
+ * requestOrComplete: 是否发送请求或已完成 true表示发送请求需要开启loading,false表示完成请求可关闭loading
+ */
+void showAppLoading(Map options) {
+ options = {
+ 'notLoading': options['notLoading'] ?? false,
+ 'text': options['text'] ?? 'loading...'
+ };
+ showDialog(
+ context: Store.context,
+ builder: (context) {
+ return LoadingDialog(text: options['text']);
+ },
+ );
+}
+
+class LoadingDialog extends StatefulWidget {
+ final String text;
+ LoadingDialog({Key key, @required this.text}) : super(key: key);
+
+ @override
+ LoadingDialogState createState() => LoadingDialogState();
+}
+
+class LoadingDialogState extends State {
+
+ @override
+ void initState() {
+ super.initState();
+ }
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ SizedBox(
+ child: CircularProgressIndicator(
+ strokeWidth: 5,
+ ),
+ height: 50,
+ width: 50,
+ ),
+ Divider(
+ height: 10,
+ ),
+ widget.text != null
+ ? Text(
+ widget.text,
+ style: TextStyle(
+ color: Theme.of(context).primaryTextTheme.title.color),
+ )
+ : ''
+ ],
+ ),
+ ),
+ );
+ }
+
+ @override
+ void dispose() async {
+ await super.dispose();
+ // loading = false;
+ // await dict.clear();
+ }
+}
diff --git a/lib/lang/index.dart b/lib/lang/index.dart
index c6ca568..95450cd 100644
--- a/lib/lang/index.dart
+++ b/lib/lang/index.dart
@@ -3,6 +3,7 @@ import 'dart:async';
import 'dart:convert';
import 'package:efox_flutter/lang/config.dart' as I18NConfig;
import 'package:flutter/services.dart' show rootBundle;
+import 'package:efox_flutter/utils/localStorage.dart' show LocalStorage;
class AppLocalizations {
Locale _locale; // language
@@ -21,7 +22,8 @@ class AppLocalizations {
}
// 设置语言切换代理
- static void setProxy(Function setState, AppLocalizationsDelegate delegate) async {
+ static void setProxy(
+ Function setState, AppLocalizationsDelegate delegate) async {
_setState = setState;
_delegate = delegate;
print("_delegate = $_delegate");
@@ -29,17 +31,17 @@ class AppLocalizations {
static get languageCode => _inst._locale.languageCode;
- static void getLanguageJson([Locale locale]) async {
+ static Future getLanguageJson([Locale locale]) async {
Locale _tmpLocale = _inst._locale;
print(_tmpLocale.languageCode);
String jsonLang;
try {
- jsonLang = await rootBundle
- .loadString('locale/${_tmpLocale.languageCode}.json');
+ jsonLang =
+ await rootBundle.loadString('locale/${_tmpLocale.languageCode}.json');
} catch (e) {
_inst._locale = Locale(I18NConfig.ConfigLanguage.defualtLanguage.code);
- jsonLang = await rootBundle
- .loadString('locale/${I18NConfig.ConfigLanguage.defualtLanguage.code}.json');
+ jsonLang = await rootBundle.loadString(
+ 'locale/${I18NConfig.ConfigLanguage.defualtLanguage.code}.json');
}
json.decode(jsonLang);
jsonLanguage = json.decode(jsonLang);
@@ -54,10 +56,12 @@ class AppLocalizations {
: Locale("zh", "CH");
}
_inst._locale = locale;
- getLanguageJson(); // 根据语言获取对应的国际化文件
- _setState(() {
- _delegate = AppLocalizationsDelegate(locale);
- });
+ LocalStorage.set('lang', locale.languageCode);
+ getLanguageJson().then((v) {
+ _setState(() {
+ _delegate = AppLocalizationsDelegate(locale);
+ });
+ }); // 根据语言获取对应的国际化文件
}
// get local language
@@ -95,17 +99,23 @@ class AppLocalizations {
class AppLocalizationsDelegate extends LocalizationsDelegate {
final Locale locale;
- AppLocalizationsDelegate ([this.locale]);
+ AppLocalizationsDelegate([this.locale]);
@override
bool isSupported(Locale locale) {
- return I18NConfig.ConfigLanguage.sopportLanguage.keys.toList().contains(locale.languageCode);
+ return I18NConfig.ConfigLanguage.sopportLanguage.keys
+ .toList()
+ .contains(locale.languageCode);
}
@override
Future load(Locale _locale) async {
- Locale _tmpLocale = locale ?? _locale;
- return await AppLocalizations.init(_tmpLocale);
+ String lang = await LocalStorage.get('lang');
+ Locale __locale = locale ?? _locale;
+ if (lang != null) {
+ __locale = Locale(lang);
+ }
+ return await AppLocalizations.init(__locale);
}
@override
@@ -113,4 +123,4 @@ class AppLocalizationsDelegate extends LocalizationsDelegate {
// false时 不执行上述重写函数
return false;
}
-}
\ No newline at end of file
+}
diff --git a/lib/main.dart b/lib/main.dart
index 90e8934..e53f8a7 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,28 +1,20 @@
import 'package:flutter/material.dart';
-
-//语言包实例化
-import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:flutter_localizations/flutter_localizations.dart'; //语言包实例化
import 'package:efox_flutter/lang/index.dart'
show AppLocalizationsDelegate, AppLocalizations;
import 'package:efox_flutter/lang/config.dart' show ConfigLanguage;
+import 'package:efox_flutter/store/index.dart'; //引用Store 层
+import 'package:efox_flutter/router/index.dart' show FluroRouter; //路由
+import 'package:efox_flutter/config/theme.dart' show AppTheme; //主题
+import 'package:efox_flutter/utils/analytics.dart' as Analytics; //统计
+import 'package:oktoast/oktoast.dart' show OKToast;
+import 'package:efox_flutter/page/home.dart' as HomePage;
-//引用Store 层
-import 'package:efox_flutter/store/index.dart' show model, Store;
-
-//路由
-import 'package:efox_flutter/router/index.dart' show FluroRouter;
-
-//主题
-import 'package:efox_flutter/config/theme.dart' show AppTheme;
-
-//统计
-import 'package:efox_flutter/utils/analytics.dart' as Analytics;
-
-void main() => runApp(MainApp());
-
+// import './mock/index.dart' as TestCase;
class MainApp extends StatefulWidget {
MainApp() {
FluroRouter.initRouter();
+ // TestCase.runTestCase();
}
@override
@@ -32,43 +24,63 @@ class MainApp extends StatefulWidget {
class MainAppState extends State {
// 定义全局 语言代理
AppLocalizationsDelegate _delegate;
-
@override
void initState() {
//实例化多语言
super.initState();
_delegate = AppLocalizationsDelegate();
+
+ Future.delayed(Duration.zero, () async {
+ Store.value().getTheme();
+ });
}
@override
Widget build(BuildContext context) {
- return Store.init(
- model: model,
- child: MaterialApp(
- localeResolutionCallback: (deviceLocale, supportedLocales) {
- print(
- 'deviceLocale=$deviceLocale supportedLocales=$supportedLocales');
- Locale _locale = supportedLocales.contains(deviceLocale)
- ? deviceLocale
- : Locale('zh');
- return _locale;
- },
- onGenerateTitle: (context) {
- // 设置多语言代理
- AppLocalizations.setProxy(setState, _delegate);
- return 'flutter';
- },
- localizationsDelegates: [
- GlobalMaterialLocalizations.delegate,
- GlobalWidgetsLocalizations.delegate,
- _delegate,
- ],
- supportedLocales: ConfigLanguage.supportedLocales,
-// title: 'Flutter Demo',
- theme: AppTheme.themData,
- onGenerateRoute: FluroRouter.router.generator,
- navigatorObservers: [Analytics.observer],
+ Store.of(context);
+ return Consumer(
+ builder: (context, configModel, child) {
+ return MaterialApp(
+ localeResolutionCallback: (deviceLocale, supportedLocales) {
+ print(
+ 'deviceLocale=$deviceLocale supportedLocales=$supportedLocales context=$context');
+ Locale _locale = supportedLocales.contains(deviceLocale)
+ ? deviceLocale
+ : Locale('zh');
+ return _locale;
+ },
+ onGenerateTitle: (ctx) {
+ // 设置多语言代理
+ AppLocalizations.setProxy(setState, _delegate);
+ return 'flutter';
+ },
+ localizationsDelegates: [
+ GlobalMaterialLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ _delegate,
+ ],
+ supportedLocales: ConfigLanguage.supportedLocales,
+ theme: AppTheme.getThemeData(configModel.theme),
+ onGenerateRoute: FluroRouter.router.generator,
+ // home: HomePage.Index(),
+ navigatorObservers: [Analytics.observer],
+ );
+ },
+ );
+ }
+}
+
+class MyApp extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ home: OKToast(
+ child: Store.init(child: MainApp()),
),
);
}
}
+
+void main() => runApp(
+ MyApp(),
+ );
diff --git a/lib/mock/index.dart b/lib/mock/index.dart
new file mode 100644
index 0000000..85054bb
--- /dev/null
+++ b/lib/mock/index.dart
@@ -0,0 +1,5 @@
+import 'login.dart' as LoginTest;
+
+runTestCase () async {
+ await LoginTest.testLogin();
+}
\ No newline at end of file
diff --git a/lib/mock/login.dart b/lib/mock/login.dart
new file mode 100644
index 0000000..9a398d3
--- /dev/null
+++ b/lib/mock/login.dart
@@ -0,0 +1,13 @@
+import 'package:efox_flutter/store/objects/user_info.dart' show UserInfo;
+const user = {
+ "id": 123,
+ "plan": {
+ 'name': '123'
+ }
+};
+
+testLogin () {
+ UserInfo _user = UserInfo.fromJson(user);
+ print('_user $_user');
+ print('_user ${_user.plan.name}');
+}
\ No newline at end of file
diff --git a/lib/package/README.md b/lib/package/README.md
new file mode 100644
index 0000000..21f6e02
--- /dev/null
+++ b/lib/package/README.md
@@ -0,0 +1,2 @@
+# Flutter Packages for FLUTTER UI APP
+> packages 为纯flutter 组件,沉淀通用组件,通用方法,通用模块
\ No newline at end of file
diff --git a/lib/package/router/router.dart b/lib/package/router/router.dart
new file mode 100644
index 0000000..e69de29
diff --git a/lib/page/app_login/index.dart b/lib/page/app_login/index.dart
new file mode 100644
index 0000000..1db5abf
--- /dev/null
+++ b/lib/page/app_login/index.dart
@@ -0,0 +1,285 @@
+import 'package:flutter/material.dart';
+import 'dart:math' as math;
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+import 'package:efox_flutter/store/index.dart' show Store, UserModel;
+import './text.dart' as Content;
+
+class Index extends StatefulWidget {
+ Index({Key key}) : super(key: key);
+
+ @override
+ _IndexState createState() => _IndexState();
+}
+
+class _IndexState extends State {
+ TextEditingController nameCtl = TextEditingController(text: '');
+ TextEditingController pwdCtl = TextEditingController(text: '');
+
+ GlobalKey _formKey = GlobalKey();
+ OverlayState _overlayState;
+ OverlayEntry _overlayEntry;
+
+ /**
+ * 弹窗内容
+ */
+ renderOverlay(String text) {
+ _overlayEntry?.remove();
+ Size _size = MediaQuery.of(context).size;
+ _overlayState = Overlay.of(context);
+ _overlayEntry = OverlayEntry(builder: (context) {
+ return Scaffold(
+ backgroundColor: Colors.transparent,
+ body: GestureDetector(
+ child: Stack(
+ children: [
+ Opacity(
+ opacity: 0.75,
+ child: Container(
+ decoration: BoxDecoration(
+ color: Colors.black,
+ ),
+ ),
+ ),
+ SizedBox.expand(
+ child: Center(
+ child: SizedBox(
+ height: _size.height / 1.3,
+ width: _size.width / 1.3,
+ child: Container(
+ padding: EdgeInsets.all(20),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ boxShadow: [
+ BoxShadow(
+ color: Colors.grey,
+ blurRadius: 2,
+ // offset: Offset(0, 1),
+ ),
+ ],
+ ),
+ child: Column(
+ children: [
+ Text(
+ "说明",
+ style: TextStyle(
+ color: Colors.black,
+ fontSize: 22,
+ ),
+ ),
+ SizedBox(
+ height: 10,
+ ),
+ Expanded(
+ child: SingleChildScrollView(
+ child: Text(
+ text,
+ textAlign: TextAlign.left,
+ style: TextStyle(
+ color: Colors.black,
+ fontSize: 16,
+ ),
+ ),
+ ),
+ ),
+ FlatButton(
+ textColor: Theme.of(context).primaryColor,
+ onPressed: () {
+ beforeDispose();
+ },
+ child: Padding(
+ padding: EdgeInsets.all(10),
+ child: Text("确定"),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ onTap: () {
+ beforeDispose();
+ },
+ ),
+ );
+ });
+ _overlayState.insert(_overlayEntry);
+ }
+
+ /**
+ * 顶部图标
+ */
+ renderGithubImage() {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Image.asset(
+ 'assets/imgs/github_2.png',
+ width: 50,
+ height: 50,
+ ),
+ SizedBox(
+ width: 10,
+ ),
+ Transform.rotate(
+ child: Icon(
+ Icons.import_export,
+ color: Colors.black,
+ ),
+ angle: math.pi / 2,
+ ),
+ SizedBox(
+ width: 10,
+ ),
+ Image.asset(
+ 'assets/imgs/github_1.png',
+ width: 50,
+ height: 50,
+ ),
+ ],
+ );
+ }
+
+ @override
+ Widget build(BuildContext ctx) {
+ // return WillPopScope(
+ // child: ,
+ // onWillPop: () {
+ // beforeDispose();
+ // },
+ // );
+ return Scaffold(
+ appBar: AppBar(
+ centerTitle: true,
+ title: Text(
+ AppLocalizations.$t('common.login'),
+ textAlign: TextAlign.center,
+ ),
+ // automaticallyImplyLeading: false,
+ ),
+ body: Builder(builder: (BuildContext context) {
+ return SingleChildScrollView(
+ child: Padding(
+ padding: EdgeInsets.symmetric(vertical: 50, horizontal: 24),
+ child: Form(
+ key: _formKey,
+ autovalidate: true,
+ child: Column(
+ children: [
+ renderGithubImage(),
+ TextFormField(
+ controller: nameCtl,
+ autofocus: false,
+ decoration: InputDecoration(
+ labelText: AppLocalizations.$t('login.account'),
+ hintText: AppLocalizations.$t('login.account_tips'),
+ icon: Icon(Icons.person),
+ ),
+ validator: (v) {
+ return v.trim().length > 0
+ ? null
+ : AppLocalizations.$t('login.account_error_tips');
+ },
+ ),
+ TextFormField(
+ controller: pwdCtl,
+ decoration: InputDecoration(
+ labelText: AppLocalizations.$t('login.password'),
+ hintText: AppLocalizations.$t('login.password_tips'),
+ icon: Icon(Icons.lock),
+ ),
+ obscureText: true,
+ validator: (v) {
+ return v.trim().length > 0
+ ? null
+ : AppLocalizations.$t('login.password_error_tips');
+ },
+ ),
+ Padding(
+ padding: EdgeInsets.only(top: 50),
+ child: Row(
+ children: [
+ Expanded(
+ child: RaisedButton(
+ padding: EdgeInsets.all(15),
+ color: Theme.of(context).primaryColor,
+ textColor:
+ Theme.of(context).primaryTextTheme.title.color,
+ child: Text(
+ AppLocalizations.$t('common.login'),
+ ),
+ onPressed: () async {
+ if ((_formKey.currentState as FormState)
+ .validate()) {
+ await Store.value(context)
+ .loginController(context, {
+ 'name': nameCtl.text.trim(),
+ 'pwd': pwdCtl.text.trim()
+ });
+ await Store.value(context)
+ .getUserStar();
+ }
+ },
+ ),
+ )
+ ],
+ ),
+ ),
+ SizedBox(
+ height: 10,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ GestureDetector(
+ child: Text(
+ 'Github账户登录说明',
+ style: TextStyle(
+ decoration: TextDecoration.underline,
+ textBaseline: TextBaseline.ideographic,
+ decorationColor: Color(0xff000000),
+ ),
+ ),
+ onTap: () {
+ renderOverlay(Content.loginText);
+ },
+ ),
+ SizedBox(
+ width: 10,
+ ),
+ GestureDetector(
+ child: Text(
+ '软件许可及服务协议',
+ style: TextStyle(
+ decoration: TextDecoration.underline,
+ textBaseline: TextBaseline.ideographic,
+ decorationColor: const Color(0xff000000),
+ ),
+ ),
+ onTap: () {
+ renderOverlay(" Text 2");
+ },
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ ),
+ );
+ }),
+ );
+ }
+
+ beforeDispose() {
+ if (_overlayEntry != null) {
+ _overlayEntry.remove();
+ _overlayEntry = null;
+ } else {
+ Navigator.of(context).pop();
+ }
+ }
+}
diff --git a/lib/page/app_login/text.dart b/lib/page/app_login/text.dart
new file mode 100644
index 0000000..3ecb96a
--- /dev/null
+++ b/lib/page/app_login/text.dart
@@ -0,0 +1 @@
+const loginText = 'a1sd56a1sd56as1d';
\ No newline at end of file
diff --git a/lib/page/comment/details.dart b/lib/page/comment/details.dart
new file mode 100644
index 0000000..30fb8fa
--- /dev/null
+++ b/lib/page/comment/details.dart
@@ -0,0 +1,274 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+import 'package:efox_flutter/store/index.dart';
+import 'package:efox_flutter/store/objects/flutter_ui_issues.dart' show IssuesContent;
+import 'package:efox_flutter/store/objects/issues_comment.dart' show IssuesDetails;
+import 'package:efox_flutter/page/app_login/index.dart' as LoginIndex;
+
+class Index extends StatefulWidget {
+ final int indexes;
+ Index({ Key key, @required this.indexes }):super(key: key);
+ @override
+ _IndexState createState() => _IndexState();
+}
+
+class _IndexState extends State {
+ final TextEditingController _controller = TextEditingController();
+ var _getComment;
+ bool isCanSend = false;
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+ _getComment = this._getIssueComment(context);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ centerTitle: true,
+ title: Text(
+ AppLocalizations.$t('title_comment_detials')
+ ),
+ ),
+ body: Stack(
+ children: [
+ Container(
+ margin: EdgeInsets.only(bottom: 50),
+ child: _ContentList(context),
+ ),
+ _SendComment(context)
+ ],
+ )
+ );
+ }
+
+ Widget _ContentList (BuildContext context) {
+ return ListView(
+ children: [
+ _IssueContent(context),
+ _CommentContent(context)
+ ],
+ );
+ }
+
+ Widget _IssueContent (BuildContext context) {
+ return Consumer(
+ builder: (context, model,child) {
+ IssuesContent issuesContent = model.flutter_ui_issues.issuesContent[widget.indexes];
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ ListTile(
+ leading: CircleAvatar(
+ backgroundImage: NetworkImage(
+ issuesContent.user.avatarUrl??'http://thumb10.jfcdns.com/2018-06/bce5b10ae530f530.png',
+ ),
+ ),
+ title: Text('${issuesContent.user.login}'),
+ subtitle: Text('更新时间:${issuesContent.updatedAt}'),
+ ),
+ Container(
+ padding: EdgeInsets.fromLTRB(20.0, 20, 20, 0),
+ child: Text(
+ '${issuesContent.title != '' ? issuesContent.title : '无标题'} #${issuesContent.number}',
+ style: Theme.of(context).textTheme.title,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.fromLTRB(20.0, 10, 20, 20.0),
+ child: Text(
+ issuesContent.body,
+ // != '' ?issuesContent.body:'无主体内容'
+ style: Theme.of(context).textTheme.subhead
+ ),
+ ),
+ Divider(
+ height: 1,
+ )
+ ],
+ );
+ }
+ );
+ }
+
+ Widget _CommentContent (BuildContext context) {
+ return FutureBuilder(
+ future: _getComment,
+ // ignore: missing_return
+ builder: (BuildContext context, AsyncSnapshot snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return Container(
+ padding: EdgeInsets.all(20),
+ child: Center(
+ child: Text('loading....'),
+ ),
+ );
+ } else if(snapshot.connectionState == ConnectionState.done) {
+ if (snapshot.hasData) {
+ return Consumer(
+ builder: (context, model,child) {
+ List items = [];
+ for(var issuesDetails in model.issues_comment.issuesDetails) {
+ items.add(_CommentContentItem(context, issuesDetails));
+ }
+ return Column(
+ children: items,
+ );
+ }
+ );
+ } else {
+ return Center(
+ child: Text('暂无数据'),
+ );
+ }
+ }
+ },
+ );
+ }
+
+ Future _getIssueComment(BuildContext context) async {
+ IssuesContent issuesContent = Store.value(context).flutter_ui_issues.issuesContent[widget.indexes];
+ await Store.value(context).getIssueComment(issuesContent.number);
+ return 'end';
+ }
+
+ Widget _CommentContentItem(BuildContext context, IssuesDetails issuesDetails) {
+ return Container(
+ padding: EdgeInsets.fromLTRB(10, 20, 10, 0),
+ child: Column(
+ children: [
+ ListTile(
+ leading: CircleAvatar(
+ backgroundImage: NetworkImage(
+ issuesDetails.user.avatarUrl??'http://thumb10.jfcdns.com/2018-06/bce5b10ae530f530.png',
+ ),
+ ),
+ title: Text('${issuesDetails.user.login}'),
+ subtitle: Text('${issuesDetails.body}')
+ ),
+ Divider(height: 1,)
+ ],
+ ),
+ );
+ }
+
+ Widget _SendComment (BuildContext context) {
+ return Positioned(
+ bottom: 0,
+ left: 0,
+ child: Container(
+ width: MediaQuery.of(context).size.width,
+ height: 50,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ border: Border(
+ top: BorderSide(width: 0.5, color: Color(int.parse('0xffe4e4e4')))
+ )
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ flex: 1,
+ child: _InputBox(),
+ ),
+ Consumer(
+ builder: (context, model,child) {
+ IssuesContent issuesContent = model.flutter_ui_issues.issuesContent[widget.indexes];
+ return GestureDetector(
+ onTap: () async {
+ if (isCanSend) {
+ if (model.user.id != null) {
+ print('发布内容:${_controller.text}');
+ bool isSendSuccess = await model.setIssueComment(
+ _controller.text,
+ issuesContent.number
+ );
+ if (isSendSuccess) {
+ await this._getIssueComment(context);
+ _controller.text = '';
+ } else {
+ print('网络错误');
+ Scaffold.of(context).showSnackBar(SnackBar(
+ content: Text('网络出错,请稍后重试'),
+ ));
+ }
+ } else {
+ print('去往登陆');
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (BuildContext context) {
+ return LoginIndex.Index();
+ }
+ )
+ );
+ }
+ }
+ },
+ child: Container(
+ padding: EdgeInsets.fromLTRB(0, 0, 10, 0),
+ child: Text(
+ '发布',
+ style: TextStyle(
+ color: isCanSend ? Theme.of(context).primaryColor : Colors.grey,
+ fontSize: 17
+ )
+ ),
+ ),
+ );
+ }
+ )
+ ],
+ )
+ ),
+ );
+ }
+ Widget _InputBox() {
+ return Container(
+ height: 30,
+ margin: EdgeInsets.fromLTRB(10, 10, 10, 10),
+ decoration: BoxDecoration(
+ color: Color(int.parse('0xffEDEDED')),
+ borderRadius: BorderRadius.circular(15)
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ flex: 1,
+ child: TextField(
+ controller: _controller,
+ autofocus: false,
+ onChanged: _onChanged,
+ style: TextStyle(
+ fontSize: 18.0,
+ color: Colors.black,
+ fontWeight: FontWeight.w300
+ ),
+ decoration: InputDecoration(
+ contentPadding: EdgeInsets.fromLTRB(10, 0, 10, 0),
+ border: InputBorder.none,
+ hintText: '说点什么吧',
+ hintStyle: TextStyle(fontSize: 15)
+ ),
+ ),
+ )
+ ],
+ )
+ );
+ }
+
+ _onChanged(String text) {
+ if (text.length > 0) {
+ setState(() {
+ isCanSend = true;
+ });
+ } else {
+ setState(() {
+ isCanSend = false;
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/page/comment/index.dart b/lib/page/comment/index.dart
new file mode 100644
index 0000000..c6e70a4
--- /dev/null
+++ b/lib/page/comment/index.dart
@@ -0,0 +1,141 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+import 'package:efox_flutter/store/index.dart';
+import 'package:efox_flutter/store/objects/flutter_ui_issues.dart'
+ show IssuesContent;
+import 'package:efox_flutter/router/index.dart' show FluroRouter;
+
+class Index extends StatefulWidget {
+ @override
+ _IndexState createState() => _IndexState();
+}
+
+class _IndexState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ centerTitle: true,
+ title: Text(AppLocalizations.$t('title_comment')),
+ ),
+ body: Container(
+ padding: EdgeInsets.fromLTRB(16.0, 0, 16.0, 0),
+ child: _CommentList(context),
+ ));
+ }
+
+ Widget _CommentList(BuildContext context) {
+ return Consumer(builder: (context, model,child) {
+ if (model.flutter_ui_issues != null &&
+ model.flutter_ui_issues.issuesContent != null &&
+ model.flutter_ui_issues.issuesContent.length != 0) {
+ return ListView.builder(
+ itemCount: model.flutter_ui_issues.issuesContent.length,
+ itemBuilder: (context, index) {
+ return _CommentCard(
+ context, model.flutter_ui_issues.issuesContent[index], index);
+ },
+ );
+ } else {
+ return Center(
+ child: Text('loading....'),
+ );
+ }
+ });
+ }
+
+ Widget _CommentCard(
+ BuildContext context, IssuesContent issuesContent, int index) {
+ return Padding(
+ child: GestureDetector(
+ onTap: () {
+ // Store.value(context).getIssueComment(issuesContent.number);
+ FluroRouter.router.navigateTo(
+ context,
+ '/commentdetails?indexes=${index}',
+ );
+ },
+ child: Card(
+ elevation: 4.0,
+ child: Stack(
+ alignment: Alignment.topCenter,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ // AspectRatio(
+ // aspectRatio: 16/9,
+ // child: ClipRRect(
+ // borderRadius: BorderRadius.only(
+ // topLeft: Radius.circular(6.0),
+ // topRight: Radius.circular(6.0),
+ // bottomLeft: Radius.circular(6.0),
+ // bottomRight: Radius.circular(6.0)
+ // ),
+ // child: Image.network(
+ // issuesContent.user.avatarUrl??'http://thumb10.jfcdns.com/2018-06/bce5b10ae530f530.png',
+ // fit: BoxFit.cover,
+ // ),
+ // ),
+ // ),
+ ListTile(
+ leading: CircleAvatar(
+ backgroundImage: NetworkImage(
+ issuesContent.user.avatarUrl ??
+ 'http://thumb10.jfcdns.com/2018-06/bce5b10ae530f530.png',
+ ),
+ ),
+ title: Text(
+ '${issuesContent.user.login}',
+ style: TextStyle(color: Theme.of(context).primaryColor),
+ ),
+ subtitle: Text('更新时间:${issuesContent.updatedAt}'),
+ trailing: Icon(Icons.keyboard_arrow_right),
+ ),
+ Container(
+ padding: EdgeInsets.fromLTRB(20.0, 20, 20, 0),
+ child: Text(
+ '${issuesContent.title != '' ? issuesContent.title : '无标题'} #${issuesContent.number}',
+ style: Theme.of(context).textTheme.title,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.fromLTRB(20.0, 10, 20, 0),
+ child: Column(
+ children: [
+ Text('创建时间:${issuesContent.createdAt}',
+ style: TextStyle(
+ color: Colors.black54, fontSize: 12)),
+ Text('更新时间:${issuesContent.updatedAt}',
+ style: TextStyle(
+ color: Colors.black54, fontSize: 12))
+ ],
+ )),
+ Container(
+ padding: EdgeInsets.fromLTRB(20.0, 10, 20, 20.0),
+ child: Text(issuesContent.body,
+ // != '' ?issuesContent.body:'无主体内容'
+ style: Theme.of(context).textTheme.subhead),
+ )
+ ],
+ ),
+ // Positioned(
+ // top: 10,
+ // left: 10,
+ // child: Text(
+ // issuesContent.user.login,
+ // style: TextStyle(
+ // color: Theme.of(context).primaryColor,
+ // fontWeight: FontWeight.bold,
+ // fontSize: 20
+ // ),
+ // ),
+ // )
+ ],
+ )),
+ ),
+ padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
+ );
+ }
+}
diff --git a/lib/page/component/index.dart b/lib/page/component/index.dart
deleted file mode 100644
index cb42878..0000000
--- a/lib/page/component/index.dart
+++ /dev/null
@@ -1,167 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:efox_flutter/router/index.dart' show FluroRouter;
-import 'package:efox_flutter/store/models/main_state_model.dart'
- show MainStateModel;
-import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
-import 'package:efox_flutter/components/headerComp.dart' as Header;
-import 'package:efox_flutter/widget/index.dart' as WidgetRoot;
-import 'package:efox_flutter/config/theme.dart' show AppTheme;
-
-class Index extends StatefulWidget {
- final MainStateModel model;
-
- Index({Key key, this.model}) : super(key: key);
-
- _IndexState createState() => _IndexState();
-}
-
-class _IndexState extends State {
- List _mapList = [];
- int _isExpandedIndex = -1;
-
- @override
- initState() {
- super.initState();
- this._mapList = WidgetRoot.getAllWidgets();
- }
-
- List appBarActions() {
- return [
- PopupMenuButton(
- icon: Icon(
- Icons.more_vert,
- ),
- onSelected: (local) {
- AppLocalizations.changeLanguage(Locale(local));
- print('local=$local');
- },
- itemBuilder: (context) => [
- PopupMenuItem(
- child: Row(
- children: [
- Text('中文'),
- ],
- ),
- value: 'zh',
- ),
- PopupMenuItem(
- child: Row(
- children: [
- Text('english'),
- ],
- ),
- value: 'en',
- ),
- ],
- ),
- ];
- }
-
- renderPanel(widgetsItem, index) {
- String nameSpaces = widgetsItem.nameSpaces;
- List _tmpWidgetList = widgetsItem.widgetList;
- return ExpansionPanel(
- headerBuilder: (context, flag) {
- return Container(
- // padding: EdgeInsets.all(10),
- child: ListTile(
- onTap: () {
- this.tabClick(index);
- },
- leading: Icon(
- IconData(
- widgetsItem.code,
- fontFamily: 'MaterialIcons',
- matchTextDirection: true,
- ),
- ),
- title: Text('${widgetsItem.typeName}'),
- ),
- );
- },
- body: Container(
- child: GridView.count(
- childAspectRatio: 1.3,
- padding: EdgeInsets.fromLTRB(4, 0, 4, 0),
- shrinkWrap: true,
- physics: ScrollPhysics(),
- crossAxisCount: 3,
- children: List.generate(
- _tmpWidgetList.length,
- (index) {
- return FlatButton(
- color: Color(AppTheme.secondColor),
- splashColor: Color(AppTheme.mainColor),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- Icon(
- IconData(
- _tmpWidgetList[index].code,
- fontFamily: 'MaterialIcons',
- matchTextDirection: true,
- ),
- color: Color(AppTheme.mainColor),
- size: 32,
- ),
- Text(
- '${_tmpWidgetList[index].title}',
- //overflow: TextOverflow.ellipsis,
- style:
- TextStyle(fontSize: 14, fontWeight: FontWeight.w300),
- )
- ],
- ),
- onPressed: () {
- FluroRouter.router.navigateTo(
- context,
- nameSpaces + _tmpWidgetList[index].title,
- );
- },
- );
- },
- ),
- ),
- ),
- isExpanded: _isExpandedIndex == index,
- );
- }
-
- tabClick (index) {
- if (index == this._isExpandedIndex) {
- index = -1;
- }
- setState(() {
- this._isExpandedIndex = index;
- });
- }
-
- Widget build(BuildContext context) {
- // 实例化语言包
- return Scaffold(
- appBar: AppBar(
- title: Header.Index(
- AppLocalizations.$t('nav_title_0'),
- ),
- actions: appBarActions(),
- ),
- body: SingleChildScrollView(
- physics: BouncingScrollPhysics(),
- // padding: EdgeInsets.all(10),
- child: ExpansionPanelList(
- animationDuration: Duration(milliseconds: 500),
- children: List.generate(
- _mapList.length,
- (_index) {
- return renderPanel(_mapList[_index], _index);
- },
- ),
- expansionCallback: (index, flag) {
- this.tabClick(index);
- },
- ),
- ),
- );
- }
-}
diff --git a/lib/page/component/tabs.dart b/lib/page/component/tabs.dart
new file mode 100644
index 0000000..84f9fbc
--- /dev/null
+++ b/lib/page/component/tabs.dart
@@ -0,0 +1,139 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/config/theme.dart' show AppTheme;
+import 'package:efox_flutter/widget/index.dart' as WidgetRoot;
+import 'package:efox_flutter/router/index.dart' show FluroRouter;
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+
+class Index extends StatefulWidget {
+ Index({Key key}) : super(key: key);
+ @override
+ _IndexState createState() => new _IndexState();
+}
+
+class _IndexState extends State
+ with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
+ List _mapList = WidgetRoot.getAllWidgets();
+ int _currentIndex = -1;
+ TabController _tabController;
+
+ @override
+ bool get wantKeepAlive => true;
+
+ @override
+ initState() {
+ super.initState();
+ _tabController = new TabController(vsync: this, length: _mapList.length);
+ _tabController.addListener(() {
+ if (_currentIndex != _tabController.index) {
+ _currentIndex = _tabController.index;
+ }
+ });
+ }
+
+ @override
+ void dispose() {
+ _tabController.dispose();
+ super.dispose();
+ }
+
+ final GlobalKey _scaffoldKey = new GlobalKey();
+
+ // ignore: must_call_super
+ Widget build(BuildContext context) {
+ return Scaffold(
+ key: _scaffoldKey,
+ appBar: PreferredSize(
+ preferredSize: Size.fromHeight(kToolbarHeight),
+ child: Container(
+ color: Color(AppTheme.mainColor),
+ child: SafeArea(
+ child: this._TabBar(),
+ ),
+ ),
+ ),
+ body: Column(
+ children: [
+ //this._TabBar(),
+ this._TabView()
+ ],
+ ));
+ }
+
+ Widget _TabBar() {
+ return TabBar(
+ indicatorColor: Color(AppTheme.secondColor),
+ controller: _tabController,
+ isScrollable: true,
+ tabs: _mapList.map((v) {
+ return new Tab(
+ text: AppLocalizations.$t(v.typeName),
+ );
+ }).toList());
+ }
+
+ Widget _TabView() {
+ return Expanded(
+ child: new TabBarView(
+ controller: _tabController,
+ children: List.generate(_mapList.length, (index) {
+ return this.Grids(_mapList[index], index);
+ })),
+ );
+ }
+
+ Widget Grids(widgetsItem, index) {
+ String nameSpaces = widgetsItem.nameSpaces;
+ List _tmpWidgetList = widgetsItem.widgetList;
+
+ return Container(
+ child: GridView.count(
+ childAspectRatio: 1.3,
+ padding: EdgeInsets.fromLTRB(4, 0, 4, 0),
+ shrinkWrap: true,
+ physics: ScrollPhysics(),
+ crossAxisCount: 3,
+ children: List.generate(
+ _tmpWidgetList.length,
+ (index) {
+ return Container(
+ decoration: BoxDecoration(
+ border:
+ Border.all(color: Color(AppTheme.lineColor), width: 0.5)),
+ child: FlatButton(
+ color: Color(AppTheme.secondColor),
+ splashColor: Color(AppTheme.mainColor),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Icon(
+ IconData(
+ _tmpWidgetList[index].code,
+ fontFamily: 'MaterialIcons',
+ matchTextDirection: true,
+ ),
+ color: Color(AppTheme.mainColor),
+ size: 32,
+ ),
+ Text(
+ '${_tmpWidgetList[index].title}',
+ //overflow: TextOverflow.ellipsis,
+ style:
+ TextStyle(fontSize: 14, fontWeight: FontWeight.w300),
+ )
+ ],
+ ),
+ onPressed: () {
+ FluroRouter.router.navigateTo(
+ context,
+ nameSpaces + _tmpWidgetList[index].title,
+ );
+ },
+ ),
+ );
+ },
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/page/home.dart b/lib/page/home.dart
index ae6a0f6..53f7add 100644
--- a/lib/page/home.dart
+++ b/lib/page/home.dart
@@ -1,10 +1,14 @@
import 'package:flutter/material.dart';
import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
-import 'package:efox_flutter/store/index.dart' show Store;
import 'package:efox_flutter/controller/index.dart' as Controller;
-
-import 'component/index.dart' as TabIndex;
+import 'package:efox_flutter/config/theme.dart' show AppTheme;
+import 'component/tabs.dart' as TabIndex;
import 'mine/index.dart' as MyIndex;
+import 'app_login/index.dart' as LoginIndex;
+import 'comment/index.dart' as CommentIndex;
+import 'library/index.dart' as LibraryIndex;
+
+import 'package:efox_flutter/store/index.dart';
class Index extends StatefulWidget {
@override
@@ -14,7 +18,6 @@ class Index extends StatefulWidget {
class _IndexState extends State {
int _currentIndex = 0;
PageController _pageController;
-
@override
void initState() {
super.initState();
@@ -28,44 +31,181 @@ class _IndexState extends State {
super.dispose();
}
- Widget _bottomNavigationBar(model) {
- return BottomNavigationBar(
- items: [
- BottomNavigationBarItem(
- title: Text(AppLocalizations.$t('title_component')),
- icon: Icon(Icons.dashboard)),
- BottomNavigationBarItem(
- title: Text(AppLocalizations.$t('title_my')), icon: Icon(Icons.person_outline)),
- ],
- type: BottomNavigationBarType.fixed,
- currentIndex: _currentIndex,
- onTap: (int index) {
- _pageController.jumpToPage(index);
- },
+ Widget _bottomNavigationBar() {
+ return BottomAppBar(
+ elevation: 0,
+ color: Color(0xFFf7f7f7),
+ shape: CircularNotchedRectangle(),
+ clipBehavior: Clip.antiAlias,
+ child: BottomNavigationBar(
+ //backgroundColor: Color(0xff000000),
+ elevation: 0,
+ backgroundColor: Color(0xFFf7f7f7),
+ type: BottomNavigationBarType.fixed,
+ items: [
+ BottomNavigationBarItem(
+ title: Text(AppLocalizations.$t('title_component')),
+ icon: Icon(Icons.dashboard)),
+/* BottomNavigationBarItem(
+ title: Text(AppLocalizations.$t('title_comment')),
+ icon: Icon(Icons.comment)),
+ BottomNavigationBarItem(
+ title: Text(AppLocalizations.$t('title_library')),
+ icon: Icon(Icons.library_add)),*/
+ BottomNavigationBarItem(
+ title: Text(AppLocalizations.$t('title_my')),
+ icon: Icon(Icons.person_outline)),
+ ],
+ // type: BottomNavigationBarType.fixed,
+ currentIndex: _currentIndex,
+ onTap: (int index) {
+ /* if (index == 1 && _currentIndex != index) {
+ Store.value(context).getIssueFlutterUI();
+ }*/
+ _pageController.jumpToPage(index);
+ },
+ ),
);
}
- @override
- Widget build(BuildContext context) {
- return Store.connect(
- builder: (context, child, model) {
- return Scaffold(
- bottomNavigationBar: _bottomNavigationBar(model),
- body: PageView(
- controller: _pageController,
- physics: NeverScrollableScrollPhysics(),
- onPageChanged: (int index) {
- setState(() {
- _currentIndex = index;
- });
- },
+ List renderTiles(id) {
+ if (id != null) {
+ return [
+ ListTile(
+ leading: Icon(Icons.exit_to_app),
+ title: Text(AppLocalizations.$t('common.logout')),
+ onTap: () {
+ Store.value(context).clearUserInfo();
+ Store.value(context).changeIsStar(false);
+ },
+ ),
+ ];
+ }
+ return [
+ ListTile(
+ leading: Icon(Icons.account_circle),
+ title: Text(AppLocalizations.$t('common.login')),
+ onTap: () {
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (BuildContext context) {
+ return LoginIndex.Index();
+ },
+ ),
+ );
+ },
+ )
+ ];
+ }
+
+ /**
+ * 抽屉面板
+ */
+ renderDrawer() {
+ print('renderDrawer $context');
+ return Drawer(
+ child: Consumer(builder: (context, model,child) {
+ print('render model $model');
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ height: 200,
+ decoration: BoxDecoration(
+ color: Color(AppTheme.mainColor),
+ ),
+ child: Row(
+ children: [
+ Padding(
+ padding: EdgeInsets.symmetric(horizontal: 20.0),
+ child: ClipOval(
+ child: model.user.avatar_url != null
+ ? Image.network(
+ model.user.avatar_url,
+ width: 80,
+ )
+ : Icon(Icons.account_box),
+ ),
+ ),
+ Text(
+ model.user.name ?? 'Guest',
+ style: TextStyle(fontWeight: FontWeight.bold),
+ )
+ ],
+ ),
+ ),
+ Expanded(
+ child: ListView(
+ children: renderTiles(model.user.id),
+ ),
+ ),
+ ],
+ );
+ }),
+ );
+ }
+
+ Widget _floatingActionButton(context) {
+ return Consumer(builder: (context, model,child) {
+ return FloatingActionButton(
+ backgroundColor: Theme.of(context).primaryColor,
+ onPressed: () {
+ if (!model.isStar && model.user.id != null) {
+ print('进行star');
+ model.setStarFlutterUI();
+ } else {
+ print('不满足进行star条件');
+ if (model.user.id == null) {
+ Navigator.of(context)
+ .push(MaterialPageRoute(builder: (BuildContext context) {
+ return LoginIndex.Index();
+ }));
+ } else {
+ Scaffold.of(context).showSnackBar(SnackBar(
+ content: Text('已star'),
+ ));
+ }
+ }
+ },
+ child: Container(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
children: [
- TabIndex.Index(model: model),
- MyIndex.Index(model: model),
+ model.isStar
+ ? Icon(Icons.star, size: 20, color: Colors.white)
+ : Icon(Icons.star_border, size: 20, color: Colors.white),
+ Text('${model.flutter_ui_info.stargazersCount.toString()}',
+ style: TextStyle(color: Colors.white))
],
),
- );
- },
+ ),
+ );
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ // Store.setWidgetCtx(context); // 初始化scaffold的上下文作为全局上下文,提供弹窗等使用。
+ return Scaffold(
+ drawer: renderDrawer(),
+ bottomNavigationBar: _bottomNavigationBar(),
+ // floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
+ // floatingActionButton: _floatingActionButton(context),
+ body: PageView(
+ controller: _pageController,
+ physics: NeverScrollableScrollPhysics(),
+ onPageChanged: (int index) {
+ setState(() {
+ _currentIndex = index;
+ });
+ },
+ children: [
+ TabIndex.Index(),
+ // CommentIndex.Index(),
+ //LibraryIndex.Index(),
+ MyIndex.Index(),
+ ],
+ ),
);
}
}
diff --git a/lib/page/library/index.dart b/lib/page/library/index.dart
new file mode 100644
index 0000000..2e710ea
--- /dev/null
+++ b/lib/page/library/index.dart
@@ -0,0 +1,25 @@
+import 'package:flutter/material.dart';
+import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
+
+class Index extends StatefulWidget {
+ @override
+ _IndexState createState() => _IndexState();
+}
+
+class _IndexState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ centerTitle: true,
+ title: Text(
+ AppLocalizations.$t('title_library')
+ ),
+ ),
+ body: Center(
+ child: Text('第三方库'),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/page/mine/index.dart b/lib/page/mine/index.dart
index 636d2da..b7a192b 100644
--- a/lib/page/mine/index.dart
+++ b/lib/page/mine/index.dart
@@ -1,131 +1,164 @@
import 'package:flutter/material.dart';
+import 'dart:io' show Platform;
import 'package:efox_flutter/lang/index.dart' show AppLocalizations;
-import 'package:efox_flutter/router/index.dart' show FluroRouter;
+import 'package:efox_flutter/config/theme.dart' show AppTheme;
+import 'package:efox_flutter/store/index.dart' show ConfigModel, Store;
+import 'package:efox_flutter/config/color.dart' show materialColor;
+import 'package:efox_flutter/utils/appVersion.dart' show AppVersion;
+import 'package:efox_flutter/components/expansion_tile.dart' as Comp;
+import 'package:oktoast/oktoast.dart';
class _IndexState extends State {
- static String _version = '';
-
@override
void initState() {
super.initState();
- _version = widget.model.config.state.version;
- }
-
- List _getList() {
- return [
- {
- 'name': AppLocalizations.$t('common.changeLanguage'),
- 'icon': 59540, // language
- 'index': 0
- },
- {
- 'name': AppLocalizations.$t('common.changeVersion') + ' ' + _version,
- 'icon': 58919, // sync
- 'index': 1,
- 'show': !widget.model.config.state.isPro
- },
- {
- 'name': AppLocalizations.$t('common.changeEnvironment'),
- 'icon': 57539, // import_export
- 'index': 2,
- 'show': !widget.model.config.state.isPro
- },
- {
- 'name': AppLocalizations.$t('common.compProgress'),
- 'icon': 57709, // low_priority
- 'index': 3
- }
- ];
}
- actionsEvent(int index) {
- switch (index) {
- case 0:
- AppLocalizations.changeLanguage();
- break;
- case 1:
- widget.model.dispatch('config', 'setVersion').then((resp) {
- _version = widget.model.config.state.version;
- });
- break;
- case 2:
- widget.model.dispatch('config', 'setEnv');
- break;
- case 3:
- FluroRouter.router.navigateTo(
- context,
- '/webview?url=${Uri.encodeComponent(widget.model.config.state.env.githubWeb)}&title=${Uri.encodeComponent(AppLocalizations.$t('common.compProgress'))}',
+ /**
+ * 国际化
+ */
+ void openLanguageSelectMenu() async {
+ await showModalBottomSheet(
+ context: context,
+ builder: (BuildContext bc) {
+ return Container(
+ child: Wrap(
+ children: [
+ ListTile(
+ title: Text(
+ '中文',
+ ),
+ onTap: () {
+ AppLocalizations.changeLanguage(Locale('zh'));
+ Navigator.pop(context);
+ },
+ ),
+ ListTile(
+ title: Text('English'),
+ onTap: () {
+ AppLocalizations.changeLanguage(Locale('en'));
+ Navigator.pop(context);
+ },
+ ),
+ ],
+ ),
);
- break;
- }
+ },
+ );
}
@override
Widget build(BuildContext context) {
- return LayoutBuilder(
- builder: (context, constraints) {
- return NestedScrollView(
- headerSliverBuilder: (context, flag) {
- return [
- SliverOverlapAbsorber(
- handle:
- NestedScrollView.sliverOverlapAbsorberHandleFor(context),
- child: SliverAppBar(
- pinned: true,
- expandedHeight: 150,
- centerTitle: true,
- flexibleSpace: FlexibleSpaceBar(
- collapseMode: CollapseMode.pin,
- title: Text(
- 'Flutter UI',
- ),
+ List _EdageList = [];
+ materialColor.forEach((k, v) {
+ _EdageList.add(this.Edage(k, v, context));
+ });
+ return Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ centerTitle: true,
+ title: Text(
+ AppLocalizations.$t('title_my'),
+ ),
+ ),
+ body: ListView(
+ children: [
+ ListTile(
+ onTap: () => this.openLanguageSelectMenu(),
+ leading: Icon(Icons.language),
+ title: Text(AppLocalizations.$t('common_mine_1.language')),
+ trailing: Container(
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(AppLocalizations.languageCode),
+ Icon(Icons.navigate_next)
+ ],
),
- ),
+ )),
+ Divider(
+ color: Color(AppTheme.lineColor),
+ ),
+ Comp.ExpansionTile(
+ leading: Icon(
+ Icons.color_lens,
),
- ];
- },
- body: Builder(builder: (context) {
- List list = this._getList();
- return CustomScrollView(
- slivers: [
- // SliverOverlapInjector与SliverOverlapAbsorber是相对成立的,
- // 若不增加SliverOverlapInjector,则下方的list顶部会被上方headerSliverBuilder所创建的组件遮住,
- // 增加后,类似clear:both效果,使得布局能顺畅衔接
- SliverOverlapInjector(
- // This is the flip side of the SliverOverlapAbsorber above.
- handle:
- NestedScrollView.sliverOverlapAbsorberHandleFor(context),
- ),
- SliverList(
- delegate: SliverChildBuilderDelegate(
- (context, index) {
- dynamic item = list[index];
- if (item['show'] ?? true) {
- return ListTile(
- onTap: () {
- this.actionsEvent(item['index']);
- },
- leading: Icon(
- IconData(
- item['icon'],
- fontFamily: 'MaterialIcons',
- matchTextDirection: true,
- ),
- ),
- title: Text('${item['name']}'),
- );
- } else {
- return Container();
- }
- },
- childCount: this._getList().length,
+ headerBackgroundColor: Colors.transparent,
+ title: Row(
+ children: [
+ Text(AppLocalizations.$t('common_mine_1.theme')),
+ Container(
+ margin: EdgeInsets.fromLTRB(5, 5, 0, 0),
+ child: Container(
+ color: Color(materialColor[
+ Store.value(context).theme]),
+ height: 15,
+ width: 15,
+ ),
+ )
+ ],
+ ),
+ children: [
+ Padding(
+ padding: EdgeInsets.all(10),
+ child: Wrap(
+ spacing: 10,
+ runSpacing: 5,
+ children: _EdageList,
),
- ),
+ )
],
- );
- }),
- );
+ ),
+ /* Divider(
+ color: Color(AppTheme.lineColor),
+ ),
+ ListTile(
+ onTap: () {
+ Store.value(context).setIsPro();
+ },
+ leading: Icon(Icons.verified_user),
+ title: Text(Store.value(context).isPro
+ ? AppLocalizations.$t('common_mine_1.doc_online')
+ : AppLocalizations.$t('common_mine_1.doc_offline')),
+ ),*/
+ Divider(
+ color: Color(AppTheme.lineColor),
+ ),
+ if (Platform.isAndroid)
+ ListTile(
+ onTap: () {
+ AppVersion().check(context, showTips: true);
+ },
+ leading: Icon(Icons.history),
+ title: Text(AppLocalizations.$t('common_mine_1.version')),
+ trailing: Container(
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(Store.value(context).appVersion),
+ Icon(Icons.navigate_next)
+ ],
+ ),
+ ),
+ ),
+ if (Platform.isAndroid)
+ Divider(
+ color: Color(AppTheme.lineColor),
+ ),
+ ],
+ ));
+ }
+
+ Widget Edage(name, color, context) {
+ return GestureDetector(
+ onTap: () {
+ Store.value(context).setTheme(name);
},
+ child: Container(
+ color: Color(color),
+ height: 30,
+ width: 30,
+ ),
);
}
}
diff --git a/lib/plugin/README.md b/lib/plugin/README.md
new file mode 100644
index 0000000..88bf7f9
--- /dev/null
+++ b/lib/plugin/README.md
@@ -0,0 +1,2 @@
+# Flutter Plugin for FLUTTER UI APP
+> plugin 为混编 flutter 组件,沉淀通用组件,通用方法,通用模块
\ No newline at end of file
diff --git a/lib/router/controller.dart b/lib/router/controller.dart
new file mode 100644
index 0000000..e69de29
diff --git a/lib/router/handles.dart b/lib/router/handles.dart
index 53a1878..201bae9 100644
--- a/lib/router/handles.dart
+++ b/lib/router/handles.dart
@@ -1,12 +1,12 @@
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
-import 'package:efox_flutter/components/webviewComp.dart' as WebViewComp;
+import 'package:efox_flutter/components/webview_comp.dart' as webview_comp;
Handler webviewHandler = Handler(
handlerFunc: (BuildContext context, Map params) {
String url = params["url"]?.first;
String title = params["title"]?.first ?? 'WebView';
- return WebViewComp.Index(
+ return webview_comp.Index(
url: url,
title: title
);
diff --git a/lib/router/index.dart b/lib/router/index.dart
index 27a8afe..6ff106a 100644
--- a/lib/router/index.dart
+++ b/lib/router/index.dart
@@ -2,6 +2,8 @@ import 'package:flutter/widgets.dart';
import 'package:fluro/fluro.dart';
//首页
import 'package:efox_flutter/page/home.dart' as HomePage;
+// 评论详细页面
+import 'package:efox_flutter/page/comment/details.dart' as CommentDetails;
import 'package:efox_flutter/widget/index.dart' as WidgetConfig;
import 'handles.dart';
//统计
@@ -10,6 +12,10 @@ import 'package:efox_flutter/utils/analytics.dart' show analytics;
class FluroRouter {
static Router router;
+ static webview({context, title, url}) {
+ router.navigateTo(context, '/webview?title=${title}&url=${url}');
+ }
+
static Router initRouter() {
FluroRouter.router = Router();
router.define(
@@ -20,6 +26,18 @@ class FluroRouter {
},
),
);
+ // 评论详情页面
+ router.define(
+ '/commentdetails',
+ handler: Handler(
+ handlerFunc: (BuildContext context, Map params) {
+ String indexes = params["indexes"]?.first;
+ return CommentDetails.Index(
+ indexes: int.parse('${indexes}')
+ );
+ }
+ )
+ );
router.define('/webview', handler: webviewHandler);
diff --git a/lib/store/http.dart b/lib/store/http.dart
deleted file mode 100644
index 0700e9a..0000000
--- a/lib/store/http.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-import 'package:dio/dio.dart'
- show Dio, Options, LogInterceptor, DioError, BaseOptions;
-
-Dio getDio([Options options]) {
- Dio dio = new Dio(BaseOptions(
- connectTimeout: 30 * 1000,
- receiveTimeout: 30 * 1000,
- )); // with default Options
- dio.interceptors.add(LogInterceptor(responseBody: true));
- return dio;
-}
-
-Future get(url, [data = const {}]) async {
- try {
- return await getDio().get(url).then((res) {
- return res.data;
- });
- } on DioError catch (e) {
- return e.response;
- }
-}
-
-Future post(url, [data = const {}, params = const {}]) async {
- return getDio().post(url, data: data, queryParameters: params);
-}
diff --git a/lib/store/index.dart b/lib/store/index.dart
index 8598364..dd2d030 100644
--- a/lib/store/index.dart
+++ b/lib/store/index.dart
@@ -1,28 +1,39 @@
-import 'package:scoped_model/scoped_model.dart' show ScopedModel, ScopedModelDescendant;
-import './models/main_state_model.dart' show MainStateModel;
-//export './models/main_state_model.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart'
+ show ChangeNotifierProvider, MultiProvider, Consumer, Provider;
+export 'package:provider/provider.dart';
+//
+import './models/config_state_model.dart' show ConfigModel;
+import './models/user_model.dart' show UserModel;
+import './models/author_state_model.dart' show AuthorModel;
+export './models/config_state_model.dart' show ConfigModel;
+export './models/user_model.dart' show UserModel;
+export './models/author_state_model.dart' show AuthorModel;
-/**
- * import 'package:efox_flutter/store/index.dart' as Store
- * Store.model.config.state.isPro
- */
class Store {
- static init({model, child}) {
- return ScopedModel(model: model, child: child);
+ static BuildContext context;
+ static of(BuildContext context) {
+ Store.context ??= context;
+ return context;
}
- static get(context) => ScopedModel.of(context);
-
- static connect({
- builder,
- child,
- rebuildOnChange = true,
- }) {
- print('builder=$builder');
- return ScopedModelDescendant(
- builder: builder, child: child, rebuildOnChange: rebuildOnChange);
+ static init({child,context}) {
+ Store.context ??= context;
+ return MultiProvider(
+ child: child,
+ providers: [
+ ChangeNotifierProvider(builder: (_) => ConfigModel()),
+ ChangeNotifierProvider(builder: (_) => UserModel()),
+ ChangeNotifierProvider(builder: (_) => AuthorModel()),
+ ],
+ );
+ }
+
+ static T value([BuildContext context]) {
+ context ??= Store.context;
+ return Provider.of(context);
}
-}
-MainStateModel model = MainStateModel();
+
+}
diff --git a/lib/store/index_for_provide.dart b/lib/store/index_for_provide.dart
new file mode 100644
index 0000000..4872213
--- /dev/null
+++ b/lib/store/index_for_provide.dart
@@ -0,0 +1,97 @@
+import 'package:flutter/material.dart' show StreamBuilder;
+import 'package:provide/provide.dart'
+ show
+ Provider,
+ Provide,
+ ProviderNode,
+ Providers,
+ ProvideMulti,
+ ProviderScope;
+export 'package:provide/provide.dart';
+import './models/config_state_model.dart' show ConfigModel;
+import './models/user_model.dart' show UserModel;
+import './models/author_state_model.dart' show AuthorModel;
+export './models/config_state_model.dart' show ConfigModel;
+export './models/user_model.dart' show UserModel;
+export './models/author_state_model.dart' show AuthorModel;
+import 'package:flutter/material.dart';
+
+class Store {
+ static dynamic storeCtx = null;
+ static dynamic widgetCtx = null;
+ static init({model, child, dispose = true}) {
+ final providers = Providers()
+ ..provide(Provider.value(ConfigModel()))
+ ..provide(Provider.value(UserModel()))
+ ..provide(Provider.value(AuthorModel()));
+
+ return ProviderNode(
+ child: child,
+ providers: providers,
+ dispose: dispose,
+ );
+ }
+ /**
+ * 设置数据层上下文
+ */
+ static setStoreCtx(context) {
+ storeCtx = context;
+ }
+
+ /**
+ * 设置Widget上下文
+ */
+ static setWidgetCtx(context) {
+ widgetCtx = context;
+ }
+
+ /**
+ * 获取
+ */
+ static T valueNotCtx() {
+ return Provide.value(storeCtx);
+ }
+
+ /**
+ * 根据 Context 获取
+ */
+ static T value(context, {scope}) {
+ return Provide.value(context, scope: scope);
+ }
+
+ /**
+ * 监听
+ */
+ static connect({builder, child, scope}) {
+ return Provide(
+ builder: builder,
+ child: child,
+ scope: scope,
+ );
+ }
+
+ /**
+ * 通过流的方式 监听
+ */
+ static stream({builder, model, context}) {
+ return StreamBuilder(
+ initialData: model,
+ stream: Provide.stream(context),
+ builder: builder);
+ }
+
+ /**
+ * 链接多个类型
+ */
+ static multi(
+ {builder,
+ child,
+ List requestedValues,
+ Map> requestedScopedValues}) {
+ return ProvideMulti(
+ builder: builder,
+ child: child,
+ requestedValues: requestedValues,
+ requestedScopedValues: requestedScopedValues);
+ }
+}
diff --git a/lib/store/models/author_state_model.dart b/lib/store/models/author_state_model.dart
new file mode 100644
index 0000000..ed4ca92
--- /dev/null
+++ b/lib/store/models/author_state_model.dart
@@ -0,0 +1,25 @@
+import '../objects/author_info.dart' show AuthorInfo;
+import 'package:flutter/foundation.dart' show ChangeNotifier;
+
+class AuthorModel extends ChangeNotifier {
+ Map list = {
+ 'ken': AuthorInfo(
+ name: 'Ken',
+ avatarUrl: 'https://avatars0.githubusercontent.com/u/3890513?s=400&v=4',
+ id: 'ken',
+ url: 'https://github.com/ckken',
+ ),
+ 'wanwu': AuthorInfo(
+ name: 'wanwu',
+ avatarUrl: 'https://avatars3.githubusercontent.com/u/15372930?s=460&v=4',
+ id: 'wanwu',
+ url: 'https://github.com/wanwusangzhi',
+ ),
+ 'lhr': AuthorInfo(
+ name: 'Lin-Haoran',
+ avatarUrl: 'https://avatars3.githubusercontent.com/u/30428314?s=400&v=4',
+ id: 'lhr',
+ url: 'https://github.com/DIVINER-only',
+ ),
+ };
+}
diff --git a/lib/store/models/config_state_model.dart b/lib/store/models/config_state_model.dart
index 8ae30c9..20064b4 100644
--- a/lib/store/models/config_state_model.dart
+++ b/lib/store/models/config_state_model.dart
@@ -1,42 +1,40 @@
-import 'dart:convert';
import 'package:efox_flutter/config/index.dart' as Config;
-import 'package:efox_flutter/store/index.dart' show model;
-import 'package:efox_flutter/utils/loadAsset.dart' show loadAssets;
+import 'package:efox_flutter/utils/localStorage.dart' show LocalStorage;
+import 'package:package_info/package_info.dart' show PackageInfo;
+import 'package:flutter/foundation.dart' show ChangeNotifier;
class ConfigInfo {
bool isPro = Config.isPro;
String version = '1.0';
dynamic env = Config.env;
+ String theme = 'red';
+ String appVersion = '-';
}
-ConfigInfo _appConfigInfo = new ConfigInfo();
-
-class ConfigModel {
- get state => _appConfigInfo;
+class ConfigModel extends ConfigInfo with ChangeNotifier {
+ Future getAppVersion() async {
+ PackageInfo packageInfo = await PackageInfo.fromPlatform();
+ appVersion = await packageInfo.version;
+ notifyListeners();
+ }
- dynamic getVersion () async {
- print('version ${model.config.state.env.versionUrl}');
- String _version = await loadAssets(model.config.state.env.versionUrl).then((resp) {
- Map res = json.decode(resp);
- return res['version'].toString() ?? '0.1';
- }).catchError((err) {
- print('err $err');
- return '0.0';
- });
- print('_version ${_version}');
- return _version;
+ Future getTheme() async {
+ String _theme = await LocalStorage.get('theme');
+ print('config get Theme ${_theme}');
+ if (_theme != null) {
+ setTheme(_theme);
+ }
}
- methods(name, payload) async {
- print('payload= $payload');
+ Future setTheme(payload) async {
+ theme = payload;
+ LocalStorage.set('theme', payload);
+ notifyListeners();
+ }
- switch (name) {
- case 'setEnv':
- _appConfigInfo.isPro = !_appConfigInfo.isPro;
- break;
- case 'setVersion':
- _appConfigInfo.version = await this.getVersion();
- break;
- }
+ Future setIsPro() async {
+ isPro = !isPro;
+ notifyListeners();
}
+
}
diff --git a/lib/store/models/main_state_model.dart b/lib/store/models/main_state_model.dart
deleted file mode 100644
index 0808905..0000000
--- a/lib/store/models/main_state_model.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import 'package:scoped_model/scoped_model.dart';
-import 'user_model.dart' show UserModel;
-import 'config_state_model.dart' show ConfigModel;
-
-/**
- * get state: model.modelName.state.xxx
- * dispatch method: model.dispatch('modelName', 'methodsName', payload)
- *
- * import 'package:efox_flutter/store/index.dart' as Store
- * Store.model.config.state.isPro
- */
-
-///主数据模型,需要全局使用的数据在这里添加模型
-class MainStateModel extends Model with UserModel {
- Map state = {};
- ConfigModel config = ConfigModel();
-
- MainStateModel() {
- // 初始化实例数据
- // order for dispatch to get destination model's methods
- this.state = {
- 'config': config,
- };
- }
-
- /**
- * dispatch method: model.dispatch('modelName', 'methodsName', payload)
- */
- Future dispatch(nameSpace, method, [payload]) async {
- await this.state[nameSpace].methods(method, payload);
- notifyListeners();
- return Future.value(this.state);
- }
-}
-
-//MainStateModel model = MainStateModel();
diff --git a/lib/store/models/user_model.dart b/lib/store/models/user_model.dart
index 1a5880f..74a02eb 100644
--- a/lib/store/models/user_model.dart
+++ b/lib/store/models/user_model.dart
@@ -1,17 +1,273 @@
-import 'package:scoped_model/scoped_model.dart';
-import '../objects/user_info.dart';
+import 'package:flutter/material.dart';
+import 'dart:convert';
+import 'package:flutter/foundation.dart' show ChangeNotifier;
+import 'package:dio/dio.dart' show Options;
+import '../objects/user_info.dart' show UserInfo;
+import '../objects/github_resp_info.dart' show GitHubRespInfo;
+import 'package:efox_flutter/http/index.dart' as Http;
+import 'package:efox_flutter/utils/localStorage.dart' show LocalStorage;
+import 'package:efox_flutter/config/index.dart' show owner_repo;
+import '../objects/flutter_ui_info.dart' show FlutterUiInfo;
+import '../objects/flutter_ui_issues.dart' show FlutterUiIssues;
+import '../objects/issues_comment.dart' show IssuesComment;
-mixin UserModel on Model {
- UserInfo _userInfo = UserInfo();
- get userInfo => _userInfo;
+class UserModelInfo {
+ bool isStar = false; // 用户是否star了flutter ui项目
+ FlutterUiInfo flutter_ui_info = FlutterUiInfo(); // flutter ui项目信息
+ FlutterUiIssues flutter_ui_issues = FlutterUiIssues(); // flutter ui的issues内容
+ IssuesComment issues_comment = IssuesComment(); // issues comment内容
+}
+
+class UserModel extends UserModelInfo with ChangeNotifier {
+ UserInfo user = UserInfo();
+ Future testLogin() async {
+ return await Http.post(url: 'http://www.baidu.com').then((res) {
+ return true;
+ }).catchError((error) async {
+ return await getUserInfo();
+ });
+ }
+
+ /**
+ * 登录控制
+ */
+ Future loginController(context, payload) async {
+ dynamic result = await login(payload);
+ // dynamic result = await testLogin();
+ print('返回result $result');
+ if (result == true) {
+ print('登录成功后退');
+ Navigator.of(context).pop();
+ } else {
+ print('登录失败');
+ Scaffold.of(context).showSnackBar(new SnackBar(
+ content: new Text('登录失败'),
+ ));
+ }
+ }
+
+ Future login(payload) async {
+ var name = payload['name'];
+ var pwd = payload['pwd'];
+ var bytes = utf8.encode("$name:$pwd");
+ var credentials = base64.encode(bytes);
+ const data = {
+ "scopes": ["user", "repo", "gist", "notifications", "public_repo"],
+ "note": "admin_script",
+ "client_id": "d8eef6133f1a2be3a842",
+ "client_secret": "2b005eed01c72aefd68fac5c5c7f2654f81c227a"
+ };
+ Options options = Options(headers: {'Authorization': 'Basic $credentials'});
+ var response = Http.post(
+ url: 'https://api.github.com/authorizations',
+ data: data,
+ options: options,
+ );
+ return await response.then((resp) async {
+ return await setLoginRespInfo(resp.data);
+ }).catchError((error) {
+ clearUserInfo();
+ return false;
+ });
+ }
+
+ setLoginRespInfo(payload) async {
+ GitHubRespInfo user = GitHubRespInfo.fromJson(payload);
+ LocalStorage.set('githubRespInfo', user.toString());
+ print('user.token.toString() ${user.token.toString()}');
+ LocalStorage.set('githubRespLoginToken', user.token.toString());
+ return await getUserInfo(); // 授权成功获取用户信息
+ }
+
+ /**
+ * 授权成功或打开app时获取用户信息
+ */
+ Future getUserInfo() async {
+ var response = Http.post(
+ url: 'https://api.github.com/user',
+ );
+ return await response.then((resp) {
+ UserInfo user = UserInfo.fromJson(resp.data);
+ setUserInfo(user);
+ return true;
+ }).catchError((error) {
+ print('ERROR $error');
+ return false;
+ });
+ }
+
+ /**
+ * 获取本地数据,减少调用接口
+ */
+ getLocalUserInfo() async {
+ String data = await LocalStorage.get('githubUserInfo');
+ print("本地数据 $data");
+ if (data != null) {
+ UserInfo user = UserInfo.fromJson(json.decode(data));
+ setUserInfo(user);
+ return true;
+ }
+ if (data == null) {
+ return await getUserInfo();
+ }
+ }
+
+ /**
+ * 设置用户信息
+ */
+ setUserInfo(payload) {
+ user = payload;
+ if (user != null && user.id != null) {
+ LocalStorage.set('githubUserInfo', json.encode(user));
+ }
+ notifyListeners();
+ }
- Future getAction() async {
- _userInfo.loading = true;
+ /**
+ * 清空用户信息
+ */
+ clearUserInfo() {
+ user = UserInfo();
+ LocalStorage.remove('githubUserInfo');
+ LocalStorage.remove('githubRespInfo');
+ LocalStorage.remove('githubRespLoginToken');
notifyListeners();
}
- void setAge() {
- _userInfo.age += 1;
+ /**
+ * 修改star显示
+ */
+ changeIsStar(isShow){
+ isStar = isShow;
notifyListeners();
}
+
+ /**
+ * 获取flutter ui star数量
+ */
+ getFlutterUIStar() {
+ var response = Http.get(
+ url: 'https://api.github.com/repos/$owner_repo'
+ );
+ response.then((resp) {
+ print('获取flutter ui信息:$resp');
+ flutter_ui_info= FlutterUiInfo.fromJson(resp.data);
+ notifyListeners();
+ }).catchError((error) {
+ print('获取flutter ui信息出错:$error');
+ });
+ }
+
+ /**
+ * 获取用户的star flutter ui信息
+ */
+ getUserStar() async {
+ var response = Http.get(
+ url: 'https://api.github.com/user/starred/$owner_repo'
+ );
+ response.then((resp) {
+ print('用户的star信息状态码:${resp.statusCode}');
+ if (resp.statusCode == 204) {
+ // TODO user have focused the repository
+ isStar = true;
+ notifyListeners();
+ return ;
+ }
+ if (resp.statusCode == 404) {
+ // TODO user have not focused the repository
+ isStar = false;
+ notifyListeners();
+ return;
+ }
+ }).catchError((error) {
+ print('获取用户star信息出错$error');
+ if (error.statusCode == 404) {
+ // TODO user have not focused the repository
+ isStar = false;
+ notifyListeners();
+ }
+ });
+ }
+
+ /**
+ * 用户star flutter ui项目
+ */
+ setStarFlutterUI() {
+ var response = Http.put(
+ url: 'https://api.github.com/user/starred/$owner_repo'
+ );
+ response.then((resp) {
+ print('用户star flutter ui项目状态码: ${resp.statusCode}');
+ if (resp.statusCode == 204) {
+ // star success
+ getFlutterUIStar();
+ getUserStar();
+ }
+ }).catchError((error) {
+ print('用户star flutter ui项目错误: $error');
+ });
+ }
+
+ /**
+ * 获取flutter ui的issue内容
+ */
+ getIssueFlutterUI() {
+ var response = Http.get(
+ url: 'https://api.github.com/repos/$owner_repo/issues'
+ );
+ response.then((resp) {
+ var data = {
+ "issues_content": resp.data
+ };
+ print('获取flutter ui的issue内容:${data}');
+ flutter_ui_issues = FlutterUiIssues.fromJson(data);
+ notifyListeners();
+ return flutter_ui_issues;
+ }).catchError((error) {
+ print('获取flutter ui的issue内容出错:$error');
+ });
+ }
+
+ /**
+ * 获取对应issue下的回复内容
+ */
+ getIssueComment(int number) async {
+ var response = await Http.get(
+ url: 'https://api.github.com/repos/$owner_repo/issues/$number/comments'
+ );
+ try {
+ var data = {
+ "issues_details": response.data
+ };
+ print('获取对应issue下的回复内容:${response.data}');
+ issues_comment = IssuesComment.fromJson(data);
+ notifyListeners();
+ } catch(error) {
+ print('获取对应issue下的回复内容出错:$error');
+ }
+ }
+
+ /**
+ * 回复issue评论
+ */
+ setIssueComment(String text, int number) async {
+ var data = {
+ "body": "$text"
+ };
+ var response = await Http.post(
+ url: 'https://api.github.com/repos/$owner_repo/issues/$number/comments',
+ data: data
+ );
+ try {
+ print('回复issue评论状态码:${response.statusCode}');
+ if (response.statusCode == 201) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (error) {
+ print('回复issue评论出错:$error');
+ return false;
+ }
+ }
}
diff --git a/lib/store/objects/author_info.dart b/lib/store/objects/author_info.dart
new file mode 100644
index 0000000..d90f8db
--- /dev/null
+++ b/lib/store/objects/author_info.dart
@@ -0,0 +1,8 @@
+class AuthorInfo extends Object {
+ String name;
+ String avatarUrl;
+ String url;
+ String id;
+
+ AuthorInfo({this.name, this.avatarUrl, this.id, this.url});
+}
diff --git a/lib/store/objects/flutter_ui_info.dart b/lib/store/objects/flutter_ui_info.dart
new file mode 100644
index 0000000..af34786
--- /dev/null
+++ b/lib/store/objects/flutter_ui_info.dart
@@ -0,0 +1,492 @@
+class FlutterUiInfo {
+ int id;
+ String nodeId;
+ String name;
+ String fullName;
+ bool private;
+ Owner owner;
+ String htmlUrl;
+ String description;
+ bool fork;
+ String url;
+ String forksUrl;
+ String keysUrl;
+ String collaboratorsUrl;
+ String teamsUrl;
+ String hooksUrl;
+ String issueEventsUrl;
+ String eventsUrl;
+ String assigneesUrl;
+ String branchesUrl;
+ String tagsUrl;
+ String blobsUrl;
+ String gitTagsUrl;
+ String gitRefsUrl;
+ String treesUrl;
+ String statusesUrl;
+ String languagesUrl;
+ String stargazersUrl;
+ String contributorsUrl;
+ String subscribersUrl;
+ String subscriptionUrl;
+ String commitsUrl;
+ String gitCommitsUrl;
+ String commentsUrl;
+ String issueCommentUrl;
+ String contentsUrl;
+ String compareUrl;
+ String mergesUrl;
+ String archiveUrl;
+ String downloadsUrl;
+ String issuesUrl;
+ String pullsUrl;
+ String milestonesUrl;
+ String notificationsUrl;
+ String labelsUrl;
+ String releasesUrl;
+ String deploymentsUrl;
+ String createdAt;
+ String updatedAt;
+ String pushedAt;
+ String gitUrl;
+ String sshUrl;
+ String cloneUrl;
+ String svnUrl;
+ String homepage;
+ int size;
+ int stargazersCount; // star数量
+ int watchersCount;
+ String language;
+ bool hasIssues;
+ bool hasProjects;
+ bool hasDownloads;
+ bool hasWiki;
+ bool hasPages;
+ int forksCount; // fork数量
+ Null mirrorUrl;
+ bool archived;
+ bool disabled;
+ int openIssuesCount;
+ Null license;
+ int forks;
+ int openIssues;
+ int watchers;
+ String defaultBranch;
+ Organization organization;
+ int networkCount;
+ int subscribersCount;
+
+ FlutterUiInfo(
+ {this.id,
+ this.nodeId,
+ this.name,
+ this.fullName,
+ this.private,
+ this.owner,
+ this.htmlUrl,
+ this.description,
+ this.fork,
+ this.url,
+ this.forksUrl,
+ this.keysUrl,
+ this.collaboratorsUrl,
+ this.teamsUrl,
+ this.hooksUrl,
+ this.issueEventsUrl,
+ this.eventsUrl,
+ this.assigneesUrl,
+ this.branchesUrl,
+ this.tagsUrl,
+ this.blobsUrl,
+ this.gitTagsUrl,
+ this.gitRefsUrl,
+ this.treesUrl,
+ this.statusesUrl,
+ this.languagesUrl,
+ this.stargazersUrl,
+ this.contributorsUrl,
+ this.subscribersUrl,
+ this.subscriptionUrl,
+ this.commitsUrl,
+ this.gitCommitsUrl,
+ this.commentsUrl,
+ this.issueCommentUrl,
+ this.contentsUrl,
+ this.compareUrl,
+ this.mergesUrl,
+ this.archiveUrl,
+ this.downloadsUrl,
+ this.issuesUrl,
+ this.pullsUrl,
+ this.milestonesUrl,
+ this.notificationsUrl,
+ this.labelsUrl,
+ this.releasesUrl,
+ this.deploymentsUrl,
+ this.createdAt,
+ this.updatedAt,
+ this.pushedAt,
+ this.gitUrl,
+ this.sshUrl,
+ this.cloneUrl,
+ this.svnUrl,
+ this.homepage,
+ this.size,
+ this.stargazersCount,
+ this.watchersCount,
+ this.language,
+ this.hasIssues,
+ this.hasProjects,
+ this.hasDownloads,
+ this.hasWiki,
+ this.hasPages,
+ this.forksCount,
+ this.mirrorUrl,
+ this.archived,
+ this.disabled,
+ this.openIssuesCount,
+ this.license,
+ this.forks,
+ this.openIssues,
+ this.watchers,
+ this.defaultBranch,
+ this.organization,
+ this.networkCount,
+ this.subscribersCount});
+
+ FlutterUiInfo.fromJson(Map json) {
+ id = json['id'];
+ nodeId = json['node_id'];
+ name = json['name'];
+ fullName = json['full_name'];
+ private = json['private'];
+ owner = json['owner'] != null ? new Owner.fromJson(json['owner']) : null;
+ htmlUrl = json['html_url'];
+ description = json['description'];
+ fork = json['fork'];
+ url = json['url'];
+ forksUrl = json['forks_url'];
+ keysUrl = json['keys_url'];
+ collaboratorsUrl = json['collaborators_url'];
+ teamsUrl = json['teams_url'];
+ hooksUrl = json['hooks_url'];
+ issueEventsUrl = json['issue_events_url'];
+ eventsUrl = json['events_url'];
+ assigneesUrl = json['assignees_url'];
+ branchesUrl = json['branches_url'];
+ tagsUrl = json['tags_url'];
+ blobsUrl = json['blobs_url'];
+ gitTagsUrl = json['git_tags_url'];
+ gitRefsUrl = json['git_refs_url'];
+ treesUrl = json['trees_url'];
+ statusesUrl = json['statuses_url'];
+ languagesUrl = json['languages_url'];
+ stargazersUrl = json['stargazers_url'];
+ contributorsUrl = json['contributors_url'];
+ subscribersUrl = json['subscribers_url'];
+ subscriptionUrl = json['subscription_url'];
+ commitsUrl = json['commits_url'];
+ gitCommitsUrl = json['git_commits_url'];
+ commentsUrl = json['comments_url'];
+ issueCommentUrl = json['issue_comment_url'];
+ contentsUrl = json['contents_url'];
+ compareUrl = json['compare_url'];
+ mergesUrl = json['merges_url'];
+ archiveUrl = json['archive_url'];
+ downloadsUrl = json['downloads_url'];
+ issuesUrl = json['issues_url'];
+ pullsUrl = json['pulls_url'];
+ milestonesUrl = json['milestones_url'];
+ notificationsUrl = json['notifications_url'];
+ labelsUrl = json['labels_url'];
+ releasesUrl = json['releases_url'];
+ deploymentsUrl = json['deployments_url'];
+ createdAt = json['created_at'];
+ updatedAt = json['updated_at'];
+ pushedAt = json['pushed_at'];
+ gitUrl = json['git_url'];
+ sshUrl = json['ssh_url'];
+ cloneUrl = json['clone_url'];
+ svnUrl = json['svn_url'];
+ homepage = json['homepage'];
+ size = json['size'];
+ stargazersCount = json['stargazers_count'];
+ watchersCount = json['watchers_count'];
+ language = json['language'];
+ hasIssues = json['has_issues'];
+ hasProjects = json['has_projects'];
+ hasDownloads = json['has_downloads'];
+ hasWiki = json['has_wiki'];
+ hasPages = json['has_pages'];
+ forksCount = json['forks_count'];
+ mirrorUrl = json['mirror_url'];
+ archived = json['archived'];
+ disabled = json['disabled'];
+ openIssuesCount = json['open_issues_count'];
+ license = json['license'];
+ forks = json['forks'];
+ openIssues = json['open_issues'];
+ watchers = json['watchers'];
+ defaultBranch = json['default_branch'];
+ organization = json['organization'] != null
+ ? new Organization.fromJson(json['organization'])
+ : null;
+ networkCount = json['network_count'];
+ subscribersCount = json['subscribers_count'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['name'] = this.name;
+ data['full_name'] = this.fullName;
+ data['private'] = this.private;
+ if (this.owner != null) {
+ data['owner'] = this.owner.toJson();
+ }
+ data['html_url'] = this.htmlUrl;
+ data['description'] = this.description;
+ data['fork'] = this.fork;
+ data['url'] = this.url;
+ data['forks_url'] = this.forksUrl;
+ data['keys_url'] = this.keysUrl;
+ data['collaborators_url'] = this.collaboratorsUrl;
+ data['teams_url'] = this.teamsUrl;
+ data['hooks_url'] = this.hooksUrl;
+ data['issue_events_url'] = this.issueEventsUrl;
+ data['events_url'] = this.eventsUrl;
+ data['assignees_url'] = this.assigneesUrl;
+ data['branches_url'] = this.branchesUrl;
+ data['tags_url'] = this.tagsUrl;
+ data['blobs_url'] = this.blobsUrl;
+ data['git_tags_url'] = this.gitTagsUrl;
+ data['git_refs_url'] = this.gitRefsUrl;
+ data['trees_url'] = this.treesUrl;
+ data['statuses_url'] = this.statusesUrl;
+ data['languages_url'] = this.languagesUrl;
+ data['stargazers_url'] = this.stargazersUrl;
+ data['contributors_url'] = this.contributorsUrl;
+ data['subscribers_url'] = this.subscribersUrl;
+ data['subscription_url'] = this.subscriptionUrl;
+ data['commits_url'] = this.commitsUrl;
+ data['git_commits_url'] = this.gitCommitsUrl;
+ data['comments_url'] = this.commentsUrl;
+ data['issue_comment_url'] = this.issueCommentUrl;
+ data['contents_url'] = this.contentsUrl;
+ data['compare_url'] = this.compareUrl;
+ data['merges_url'] = this.mergesUrl;
+ data['archive_url'] = this.archiveUrl;
+ data['downloads_url'] = this.downloadsUrl;
+ data['issues_url'] = this.issuesUrl;
+ data['pulls_url'] = this.pullsUrl;
+ data['milestones_url'] = this.milestonesUrl;
+ data['notifications_url'] = this.notificationsUrl;
+ data['labels_url'] = this.labelsUrl;
+ data['releases_url'] = this.releasesUrl;
+ data['deployments_url'] = this.deploymentsUrl;
+ data['created_at'] = this.createdAt;
+ data['updated_at'] = this.updatedAt;
+ data['pushed_at'] = this.pushedAt;
+ data['git_url'] = this.gitUrl;
+ data['ssh_url'] = this.sshUrl;
+ data['clone_url'] = this.cloneUrl;
+ data['svn_url'] = this.svnUrl;
+ data['homepage'] = this.homepage;
+ data['size'] = this.size;
+ data['stargazers_count'] = this.stargazersCount;
+ data['watchers_count'] = this.watchersCount;
+ data['language'] = this.language;
+ data['has_issues'] = this.hasIssues;
+ data['has_projects'] = this.hasProjects;
+ data['has_downloads'] = this.hasDownloads;
+ data['has_wiki'] = this.hasWiki;
+ data['has_pages'] = this.hasPages;
+ data['forks_count'] = this.forksCount;
+ data['mirror_url'] = this.mirrorUrl;
+ data['archived'] = this.archived;
+ data['disabled'] = this.disabled;
+ data['open_issues_count'] = this.openIssuesCount;
+ data['license'] = this.license;
+ data['forks'] = this.forks;
+ data['open_issues'] = this.openIssues;
+ data['watchers'] = this.watchers;
+ data['default_branch'] = this.defaultBranch;
+ if (this.organization != null) {
+ data['organization'] = this.organization.toJson();
+ }
+ data['network_count'] = this.networkCount;
+ data['subscribers_count'] = this.subscribersCount;
+ return data;
+ }
+}
+
+class Owner {
+ String login;
+ int id;
+ String nodeId;
+ String avatarUrl;
+ String gravatarId;
+ String url;
+ String htmlUrl;
+ String followersUrl;
+ String followingUrl;
+ String gistsUrl;
+ String starredUrl;
+ String subscriptionsUrl;
+ String organizationsUrl;
+ String reposUrl;
+ String eventsUrl;
+ String receivedEventsUrl;
+ String type;
+ bool siteAdmin;
+
+ Owner(
+ {this.login,
+ this.id,
+ this.nodeId,
+ this.avatarUrl,
+ this.gravatarId,
+ this.url,
+ this.htmlUrl,
+ this.followersUrl,
+ this.followingUrl,
+ this.gistsUrl,
+ this.starredUrl,
+ this.subscriptionsUrl,
+ this.organizationsUrl,
+ this.reposUrl,
+ this.eventsUrl,
+ this.receivedEventsUrl,
+ this.type,
+ this.siteAdmin});
+
+ Owner.fromJson(Map json) {
+ login = json['login'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ avatarUrl = json['avatar_url'];
+ gravatarId = json['gravatar_id'];
+ url = json['url'];
+ htmlUrl = json['html_url'];
+ followersUrl = json['followers_url'];
+ followingUrl = json['following_url'];
+ gistsUrl = json['gists_url'];
+ starredUrl = json['starred_url'];
+ subscriptionsUrl = json['subscriptions_url'];
+ organizationsUrl = json['organizations_url'];
+ reposUrl = json['repos_url'];
+ eventsUrl = json['events_url'];
+ receivedEventsUrl = json['received_events_url'];
+ type = json['type'];
+ siteAdmin = json['site_admin'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['login'] = this.login;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['avatar_url'] = this.avatarUrl;
+ data['gravatar_id'] = this.gravatarId;
+ data['url'] = this.url;
+ data['html_url'] = this.htmlUrl;
+ data['followers_url'] = this.followersUrl;
+ data['following_url'] = this.followingUrl;
+ data['gists_url'] = this.gistsUrl;
+ data['starred_url'] = this.starredUrl;
+ data['subscriptions_url'] = this.subscriptionsUrl;
+ data['organizations_url'] = this.organizationsUrl;
+ data['repos_url'] = this.reposUrl;
+ data['events_url'] = this.eventsUrl;
+ data['received_events_url'] = this.receivedEventsUrl;
+ data['type'] = this.type;
+ data['site_admin'] = this.siteAdmin;
+ return data;
+ }
+}
+
+class Organization {
+ String login;
+ int id;
+ String nodeId;
+ String avatarUrl;
+ String gravatarId;
+ String url;
+ String htmlUrl;
+ String followersUrl;
+ String followingUrl;
+ String gistsUrl;
+ String starredUrl;
+ String subscriptionsUrl;
+ String organizationsUrl;
+ String reposUrl;
+ String eventsUrl;
+ String receivedEventsUrl;
+ String type;
+ bool siteAdmin;
+
+ Organization(
+ {this.login,
+ this.id,
+ this.nodeId,
+ this.avatarUrl,
+ this.gravatarId,
+ this.url,
+ this.htmlUrl,
+ this.followersUrl,
+ this.followingUrl,
+ this.gistsUrl,
+ this.starredUrl,
+ this.subscriptionsUrl,
+ this.organizationsUrl,
+ this.reposUrl,
+ this.eventsUrl,
+ this.receivedEventsUrl,
+ this.type,
+ this.siteAdmin});
+
+ Organization.fromJson(Map json) {
+ login = json['login'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ avatarUrl = json['avatar_url'];
+ gravatarId = json['gravatar_id'];
+ url = json['url'];
+ htmlUrl = json['html_url'];
+ followersUrl = json['followers_url'];
+ followingUrl = json['following_url'];
+ gistsUrl = json['gists_url'];
+ starredUrl = json['starred_url'];
+ subscriptionsUrl = json['subscriptions_url'];
+ organizationsUrl = json['organizations_url'];
+ reposUrl = json['repos_url'];
+ eventsUrl = json['events_url'];
+ receivedEventsUrl = json['received_events_url'];
+ type = json['type'];
+ siteAdmin = json['site_admin'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['login'] = this.login;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['avatar_url'] = this.avatarUrl;
+ data['gravatar_id'] = this.gravatarId;
+ data['url'] = this.url;
+ data['html_url'] = this.htmlUrl;
+ data['followers_url'] = this.followersUrl;
+ data['following_url'] = this.followingUrl;
+ data['gists_url'] = this.gistsUrl;
+ data['starred_url'] = this.starredUrl;
+ data['subscriptions_url'] = this.subscriptionsUrl;
+ data['organizations_url'] = this.organizationsUrl;
+ data['repos_url'] = this.reposUrl;
+ data['events_url'] = this.eventsUrl;
+ data['received_events_url'] = this.receivedEventsUrl;
+ data['type'] = this.type;
+ data['site_admin'] = this.siteAdmin;
+ return data;
+ }
+}
\ No newline at end of file
diff --git a/lib/store/objects/flutter_ui_issues.dart b/lib/store/objects/flutter_ui_issues.dart
new file mode 100644
index 0000000..ddf1f82
--- /dev/null
+++ b/lib/store/objects/flutter_ui_issues.dart
@@ -0,0 +1,254 @@
+class FlutterUiIssues {
+ List issuesContent;
+
+ FlutterUiIssues({this.issuesContent});
+
+ FlutterUiIssues.fromJson(Map json) {
+ if (json['issues_content'] != null) {
+ issuesContent = new List();
+ json['issues_content'].forEach((v) {
+ issuesContent.add(new IssuesContent.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ if (this.issuesContent != null) {
+ data['issues_content'] =
+ this.issuesContent.map((v) => v.toJson()).toList();
+ }
+ return data;
+ }
+}
+
+class IssuesContent {
+ String url;
+ String repositoryUrl;
+ String labelsUrl;
+ String commentsUrl;
+ String eventsUrl;
+ String htmlUrl;
+ int id;
+ String nodeId;
+ int number;
+ String title;
+ User user;
+ List labels;
+ String state;
+ bool locked;
+ List assignees;
+ int comments;
+ String createdAt;
+ String updatedAt;
+ String authorAssociation;
+ String body;
+
+ IssuesContent(
+ {this.url,
+ this.repositoryUrl,
+ this.labelsUrl,
+ this.commentsUrl,
+ this.eventsUrl,
+ this.htmlUrl,
+ this.id,
+ this.nodeId,
+ this.number,
+ this.title,
+ this.user,
+ this.labels,
+ this.state,
+ this.locked,
+ this.assignees,
+ this.comments,
+ this.createdAt,
+ this.updatedAt,
+ this.authorAssociation,
+ this.body});
+
+ IssuesContent.fromJson(Map json) {
+ url = json['url'];
+ repositoryUrl = json['repository_url'];
+ labelsUrl = json['labels_url'];
+ commentsUrl = json['comments_url'];
+ eventsUrl = json['events_url'];
+ htmlUrl = json['html_url'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ number = json['number'];
+ title = json['title'];
+ user = json['user'] != null ? new User.fromJson(json['user']) : null;
+ labels = json['labels'].cast();
+ state = json['state'];
+ locked = json['locked'];
+ assignees = json['assignees'].cast();
+ comments = json['comments'];
+ createdAt = json['created_at'];
+ updatedAt = json['updated_at'];
+ authorAssociation = json['author_association'];
+ body = json['body'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['url'] = this.url;
+ data['repository_url'] = this.repositoryUrl;
+ data['labels_url'] = this.labelsUrl;
+ data['comments_url'] = this.commentsUrl;
+ data['events_url'] = this.eventsUrl;
+ data['html_url'] = this.htmlUrl;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['number'] = this.number;
+ data['title'] = this.title;
+ if (this.user != null) {
+ data['user'] = this.user.toJson();
+ }
+ data['labels'] = this.labels;
+ data['state'] = this.state;
+ data['locked'] = this.locked;
+ data['assignees'] = this.assignees;
+ data['comments'] = this.comments;
+ data['created_at'] = this.createdAt;
+ data['updated_at'] = this.updatedAt;
+ data['author_association'] = this.authorAssociation;
+ data['body'] = this.body;
+ return data;
+ }
+}
+
+class User {
+ String login;
+ int id;
+ String nodeId;
+ String avatarUrl;
+ String gravatarId;
+ String url;
+ String htmlUrl;
+ String followersUrl;
+ String followingUrl;
+ String gistsUrl;
+ String starredUrl;
+ String subscriptionsUrl;
+ String organizationsUrl;
+ String reposUrl;
+ String eventsUrl;
+ String receivedEventsUrl;
+ String type;
+ bool siteAdmin;
+
+ User(
+ {this.login,
+ this.id,
+ this.nodeId,
+ this.avatarUrl,
+ this.gravatarId,
+ this.url,
+ this.htmlUrl,
+ this.followersUrl,
+ this.followingUrl,
+ this.gistsUrl,
+ this.starredUrl,
+ this.subscriptionsUrl,
+ this.organizationsUrl,
+ this.reposUrl,
+ this.eventsUrl,
+ this.receivedEventsUrl,
+ this.type,
+ this.siteAdmin});
+
+ User.fromJson(Map json) {
+ login = json['login'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ avatarUrl = json['avatar_url'];
+ gravatarId = json['gravatar_id'];
+ url = json['url'];
+ htmlUrl = json['html_url'];
+ followersUrl = json['followers_url'];
+ followingUrl = json['following_url'];
+ gistsUrl = json['gists_url'];
+ starredUrl = json['starred_url'];
+ subscriptionsUrl = json['subscriptions_url'];
+ organizationsUrl = json['organizations_url'];
+ reposUrl = json['repos_url'];
+ eventsUrl = json['events_url'];
+ receivedEventsUrl = json['received_events_url'];
+ type = json['type'];
+ siteAdmin = json['site_admin'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['login'] = this.login;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['avatar_url'] = this.avatarUrl;
+ data['gravatar_id'] = this.gravatarId;
+ data['url'] = this.url;
+ data['html_url'] = this.htmlUrl;
+ data['followers_url'] = this.followersUrl;
+ data['following_url'] = this.followingUrl;
+ data['gists_url'] = this.gistsUrl;
+ data['starred_url'] = this.starredUrl;
+ data['subscriptions_url'] = this.subscriptionsUrl;
+ data['organizations_url'] = this.organizationsUrl;
+ data['repos_url'] = this.reposUrl;
+ data['events_url'] = this.eventsUrl;
+ data['received_events_url'] = this.receivedEventsUrl;
+ data['type'] = this.type;
+ data['site_admin'] = this.siteAdmin;
+ return data;
+ }
+}
+
+
+
+
+
+// [
+// {
+// "url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/53",
+// "repository_url": "https://api.github.com/repos/efoxTeam/flutter-ui",
+// "labels_url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/53/labels{/name}",
+// "comments_url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/53/comments",
+// "events_url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/53/events",
+// "html_url": "https://github.com/efoxTeam/flutter-ui/issues/53",
+// "id": 454062553,
+// "node_id": "MDU6SXNzdWU0NTQwNjI1NTM=",
+// "number": 53,
+// "title": "test issue",
+// "user": {
+// "login": "DIVINER-onlys",
+// "id": 35843543,
+// "node_id": "MDQ6VXNlcjM1ODQzNTQz",
+// "avatar_url": "https://avatars0.githubusercontent.com/u/35843543?v=4",
+// "gravatar_id": "",
+// "url": "https://api.github.com/users/DIVINER-onlys",
+// "html_url": "https://github.com/DIVINER-onlys",
+// "followers_url": "https://api.github.com/users/DIVINER-onlys/followers",
+// "following_url": "https://api.github.com/users/DIVINER-onlys/following{/other_user}",
+// "gists_url": "https://api.github.com/users/DIVINER-onlys/gists{/gist_id}",
+// "starred_url": "https://api.github.com/users/DIVINER-onlys/starred{/owner}{/repo}",
+// "subscriptions_url": "https://api.github.com/users/DIVINER-onlys/subscriptions",
+// "organizations_url": "https://api.github.com/users/DIVINER-onlys/orgs",
+// "repos_url": "https://api.github.com/users/DIVINER-onlys/repos",
+// "events_url": "https://api.github.com/users/DIVINER-onlys/events{/privacy}",
+// "received_events_url": "https://api.github.com/users/DIVINER-onlys/received_events",
+// "type": "User",
+// "site_admin": false
+// },
+// "labels": [""],
+// "state": "open",
+// "locked": false,
+// "assignee": null,
+// "assignees": [""],
+// "milestone": null,
+// "comments": 1,
+// "created_at": "2019-06-10T08:47:37Z",
+// "updated_at": "2019-06-10T08:51:54Z",
+// "closed_at": null,
+// "author_association": "NONE",
+// "body": "api test"
+// }
+// ]
\ No newline at end of file
diff --git a/lib/store/objects/github_resp_info.dart b/lib/store/objects/github_resp_info.dart
new file mode 100644
index 0000000..21bca5e
--- /dev/null
+++ b/lib/store/objects/github_resp_info.dart
@@ -0,0 +1,94 @@
+/**
+ * github登录后返回的数据
+ */
+class GitHubRespInfo extends Object {
+ num id;
+ String url;
+ App app;
+ String token;
+ String hashed_token;
+ String token_last_eight;
+ String note;
+ Map note_url;
+ String created_at;
+ String updated_at;
+ List scopes;
+ Map fingerprint;
+
+ GitHubRespInfo({
+ this.id,
+ this.url,
+ this.app,
+ this.token,
+ this.hashed_token,
+ this.token_last_eight,
+ this.note,
+ this.note_url,
+ this.created_at,
+ this.updated_at,
+ this.scopes,
+ this.fingerprint,
+ });
+
+ GitHubRespInfo.fromJson(json) {
+ id = json['id'];
+ url = json['url'];
+ app = App.fromJson(json['app']);
+ token = json['token'];
+ hashed_token = json['hashed_token'];
+ token_last_eight = json['token_last_eight'];
+ note = json['note'];
+ note_url = json['note_url'];
+ created_at = json['created_at'];
+ updated_at = json['updated_at'];
+ scopes = json['scopes'];
+ fingerprint = json['fingerprint'];
+ }
+
+ Map toJson() => {
+ 'id': id,
+ 'url': url,
+ 'app': app,
+ 'token': token,
+ 'hashed_token': hashed_token,
+ 'token_last_eight': token_last_eight,
+ 'note': note,
+ 'note_url': note_url,
+ 'created_at': created_at,
+ 'updated_at': updated_at,
+ 'scopes': scopes,
+ 'fingerprint': fingerprint,
+ };
+}
+
+class App extends Object {
+ String str;
+ num number;
+ bool boolean;
+ List array;
+ Map map;
+
+ App({
+ this.str,
+ this.number,
+ this.boolean,
+ this.array,
+ this.map,
+ });
+
+ App.fromJson(json) {
+ str = json['str'];
+ number = json['number'];
+ boolean = json['boolean'];
+ array = json['array'];
+ map = json['map'];
+ }
+
+ Map toJson() => {
+ 'str': str,
+ 'number': number,
+ 'boolean': boolean,
+ 'array': array,
+ 'map': map,
+ };
+}
diff --git a/lib/store/objects/issues_comment.dart b/lib/store/objects/issues_comment.dart
new file mode 100644
index 0000000..aefc74a
--- /dev/null
+++ b/lib/store/objects/issues_comment.dart
@@ -0,0 +1,199 @@
+class IssuesComment {
+ List issuesDetails;
+
+ IssuesComment({this.issuesDetails});
+
+ IssuesComment.fromJson(Map json) {
+ if (json['issues_details'] != null) {
+ issuesDetails = new List();
+ json['issues_details'].forEach((v) {
+ issuesDetails.add(new IssuesDetails.fromJson(v));
+ });
+ }
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ if (this.issuesDetails != null) {
+ data['issues_details'] =
+ this.issuesDetails.map((v) => v.toJson()).toList();
+ }
+ return data;
+ }
+}
+
+class IssuesDetails {
+ String url;
+ String htmlUrl;
+ String issueUrl;
+ int id;
+ String nodeId;
+ User user;
+ String createdAt;
+ String updatedAt;
+ String authorAssociation;
+ String body;
+
+ IssuesDetails(
+ {this.url,
+ this.htmlUrl,
+ this.issueUrl,
+ this.id,
+ this.nodeId,
+ this.user,
+ this.createdAt,
+ this.updatedAt,
+ this.authorAssociation,
+ this.body});
+
+ IssuesDetails.fromJson(Map json) {
+ url = json['url'];
+ htmlUrl = json['html_url'];
+ issueUrl = json['issue_url'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ user = json['user'] != null ? new User.fromJson(json['user']) : null;
+ createdAt = json['created_at'];
+ updatedAt = json['updated_at'];
+ authorAssociation = json['author_association'];
+ body = json['body'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['url'] = this.url;
+ data['html_url'] = this.htmlUrl;
+ data['issue_url'] = this.issueUrl;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ if (this.user != null) {
+ data['user'] = this.user.toJson();
+ }
+ data['created_at'] = this.createdAt;
+ data['updated_at'] = this.updatedAt;
+ data['author_association'] = this.authorAssociation;
+ data['body'] = this.body;
+ return data;
+ }
+}
+
+class User {
+ String login;
+ int id;
+ String nodeId;
+ String avatarUrl;
+ String gravatarId;
+ String url;
+ String htmlUrl;
+ String followersUrl;
+ String followingUrl;
+ String gistsUrl;
+ String starredUrl;
+ String subscriptionsUrl;
+ String organizationsUrl;
+ String reposUrl;
+ String eventsUrl;
+ String receivedEventsUrl;
+ String type;
+ bool siteAdmin;
+
+ User(
+ {this.login,
+ this.id,
+ this.nodeId,
+ this.avatarUrl,
+ this.gravatarId,
+ this.url,
+ this.htmlUrl,
+ this.followersUrl,
+ this.followingUrl,
+ this.gistsUrl,
+ this.starredUrl,
+ this.subscriptionsUrl,
+ this.organizationsUrl,
+ this.reposUrl,
+ this.eventsUrl,
+ this.receivedEventsUrl,
+ this.type,
+ this.siteAdmin});
+
+ User.fromJson(Map json) {
+ login = json['login'];
+ id = json['id'];
+ nodeId = json['node_id'];
+ avatarUrl = json['avatar_url'];
+ gravatarId = json['gravatar_id'];
+ url = json['url'];
+ htmlUrl = json['html_url'];
+ followersUrl = json['followers_url'];
+ followingUrl = json['following_url'];
+ gistsUrl = json['gists_url'];
+ starredUrl = json['starred_url'];
+ subscriptionsUrl = json['subscriptions_url'];
+ organizationsUrl = json['organizations_url'];
+ reposUrl = json['repos_url'];
+ eventsUrl = json['events_url'];
+ receivedEventsUrl = json['received_events_url'];
+ type = json['type'];
+ siteAdmin = json['site_admin'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['login'] = this.login;
+ data['id'] = this.id;
+ data['node_id'] = this.nodeId;
+ data['avatar_url'] = this.avatarUrl;
+ data['gravatar_id'] = this.gravatarId;
+ data['url'] = this.url;
+ data['html_url'] = this.htmlUrl;
+ data['followers_url'] = this.followersUrl;
+ data['following_url'] = this.followingUrl;
+ data['gists_url'] = this.gistsUrl;
+ data['starred_url'] = this.starredUrl;
+ data['subscriptions_url'] = this.subscriptionsUrl;
+ data['organizations_url'] = this.organizationsUrl;
+ data['repos_url'] = this.reposUrl;
+ data['events_url'] = this.eventsUrl;
+ data['received_events_url'] = this.receivedEventsUrl;
+ data['type'] = this.type;
+ data['site_admin'] = this.siteAdmin;
+ return data;
+ }
+}
+
+// {
+// "issues_details": [
+// {
+// "url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/comments/500342145",
+// "html_url": "https://github.com/efoxTeam/flutter-ui/issues/53#issuecomment-500342145",
+// "issue_url": "https://api.github.com/repos/efoxTeam/flutter-ui/issues/53",
+// "id": 500342145,
+// "node_id": "MDEyOklzc3VlQ29tbWVudDUwMDM0MjE0NQ==",
+// "user": {
+// "login": "DIVINER-onlys",
+// "id": 35843543,
+// "node_id": "MDQ6VXNlcjM1ODQzNTQz",
+// "avatar_url": "https://avatars0.githubusercontent.com/u/35843543?v=4",
+// "gravatar_id": "",
+// "url": "https://api.github.com/users/DIVINER-onlys",
+// "html_url": "https://github.com/DIVINER-onlys",
+// "followers_url": "https://api.github.com/users/DIVINER-onlys/followers",
+// "following_url": "https://api.github.com/users/DIVINER-onlys/following{/other_user}",
+// "gists_url": "https://api.github.com/users/DIVINER-onlys/gists{/gist_id}",
+// "starred_url": "https://api.github.com/users/DIVINER-onlys/starred{/owner}{/repo}",
+// "subscriptions_url": "https://api.github.com/users/DIVINER-onlys/subscriptions",
+// "organizations_url": "https://api.github.com/users/DIVINER-onlys/orgs",
+// "repos_url": "https://api.github.com/users/DIVINER-onlys/repos",
+// "events_url": "https://api.github.com/users/DIVINER-onlys/events{/privacy}",
+// "received_events_url": "https://api.github.com/users/DIVINER-onlys/received_events",
+// "type": "User",
+// "site_admin": false
+// },
+// "created_at": "2019-06-10T08:51:54Z",
+// "updated_at": "2019-06-10T08:51:54Z",
+// "author_association": "NONE",
+// "body": "ooooo"
+// }
+// ]
+// }
\ No newline at end of file
diff --git a/lib/store/objects/user_info.dart b/lib/store/objects/user_info.dart
index 97b962e..7c6af85 100644
--- a/lib/store/objects/user_info.dart
+++ b/lib/store/objects/user_info.dart
@@ -1,48 +1,195 @@
-class UserInfo extends Object{
- String fbid;
- String uid;
+//import 'dart:convert';
+
+class UserInfo extends Object {
+ String login;
+ num id;
+ String node_id;
+ String avatar_url;
+ String gravatar_id;
+ String url;
+ String html_url;
+ String followers_url;
+ String following_url;
+ String gists_url;
+ String starred_url;
+ String subscriptions_url;
+ String organizations_url;
+ String repos_url;
+ String events_url;
+ String received_events_url;
+ String type;
+ bool site_admin;
String name;
- String token;
- String avatar;
- int expiresIn;
- int expireTime;
- bool loading;
- int age;
-
- //
- UserInfo(
- {this.fbid,
- this.uid,
- this.name,
- this.token,
- this.expiresIn,
- this.age = 0,
- this.loading = false,
- this.expireTime = 0});
- //
- UserInfo.fromJson(json) {
- Map user = json['user'];
- fbid = user['fbid'];
- uid = user['uid'];
- name = user['name'];
- avatar = user['avatar'];
- token = json['token'];
- expiresIn = json['expiresIn'] ?? 0;
- if (expiresIn >= 0) {
- int now = DateTime.now().millisecondsSinceEpoch;
- expireTime = now + expiresIn * 1000;
+ String company;
+ String blog;
+ dynamic location;
+ String email;
+ dynamic hireable;
+ dynamic bio;
+ num public_repos;
+ num public_gists;
+ num followers;
+ num following;
+ String created_at;
+ String updated_at;
+ num private_gists;
+ num total_private_repos;
+ num owned_private_repos;
+ num disk_usage;
+ num collaborators;
+ bool two_factor_authentication;
+ Plan plan;
+
+ UserInfo({
+ this.login,
+ this.id,
+ this.node_id,
+ this.avatar_url,
+ this.gravatar_id,
+ this.url,
+ this.html_url,
+ this.followers_url,
+ this.following_url,
+ this.gists_url,
+ this.starred_url,
+ this.subscriptions_url,
+ this.organizations_url,
+ this.repos_url,
+ this.events_url,
+ this.received_events_url,
+ this.type,
+ this.site_admin,
+ this.name,
+ this.company,
+ this.blog,
+ this.location,
+ this.email,
+ this.hireable,
+ this.bio,
+ this.public_repos,
+ this.public_gists,
+ this.followers,
+ this.following,
+ this.created_at,
+ this.updated_at,
+ this.private_gists,
+ this.total_private_repos,
+ this.owned_private_repos,
+ this.disk_usage,
+ this.collaborators,
+ this.two_factor_authentication,
+ this.plan,
+ });
+
+ UserInfo.fromJson(instance) {
+ login = instance['login'];
+ id = instance['id'];
+ node_id = instance['node_id'];
+ avatar_url = instance['avatar_url'];
+ gravatar_id = instance['gravatar_id'];
+ url = instance['url'];
+ html_url = instance['html_url'];
+ followers_url = instance['followers_url'];
+ following_url = instance['following_url'];
+ gists_url = instance['gists_url'];
+ starred_url = instance['starred_url'];
+ subscriptions_url = instance['subscriptions_url'];
+ organizations_url = instance['organizations_url'];
+ repos_url = instance['repos_url'];
+ events_url = instance['events_url'];
+ received_events_url = instance['received_events_url'];
+ type = instance['type'];
+ site_admin = instance['site_admin'];
+ name = instance['name'];
+ company = instance['company'];
+ blog = instance['blog'];
+ location = instance['location'];
+ email = instance['email'];
+ hireable = instance['hireable'];
+ bio = instance['bio'];
+ public_repos = instance['public_repos'];
+ public_gists = instance['public_gists'];
+ followers = instance['followers'];
+ following = instance['following'];
+ created_at = instance['created_at'];
+ updated_at = instance['updated_at'];
+ private_gists = instance['private_gists'];
+ total_private_repos = instance['total_private_repos'];
+ owned_private_repos = instance['owned_private_repos'];
+ disk_usage = instance['disk_usage'];
+ collaborators = instance['collaborators'];
+ two_factor_authentication = instance['two_factor_authentication'];
+ plan = Plan.fromJson(instance['plan']);
+ }
+
+ Map toJson() => {
+ 'login': login,
+ 'id': id,
+ 'node_id': node_id,
+ 'avatar_url': avatar_url,
+ 'gravatar_id': gravatar_id,
+ 'url': url,
+ 'html_url': html_url,
+ 'followers_url': followers_url,
+ 'following_url': following_url,
+ 'gists_url': gists_url,
+ 'starred_url': starred_url,
+ 'subscriptions_url': subscriptions_url,
+ 'organizations_url': organizations_url,
+ 'repos_url': repos_url,
+ 'events_url': events_url,
+ 'received_events_url': received_events_url,
+ 'type': type,
+ 'site_admin': site_admin,
+ 'name': name,
+ 'company': company,
+ 'blog': blog,
+ 'location': location,
+ 'email': email,
+ 'hireable': hireable,
+ 'bio': bio,
+ 'public_repos': public_repos,
+ 'public_gists': public_gists,
+ 'followers': followers,
+ 'following': following,
+ 'created_at': created_at,
+ 'updated_at': updated_at,
+ 'private_gists': private_gists,
+ 'total_private_repos': total_private_repos,
+ 'owned_private_repos': owned_private_repos,
+ 'disk_usage': disk_usage,
+ 'collaborators': collaborators,
+ 'two_factor_authentication': two_factor_authentication,
+ 'plan': plan,
+ };
+}
+
+class Plan extends Object {
+ String name;
+ num space;
+ num collaborators;
+ num private_repos;
+
+ Plan({
+ this.name,
+ this.space,
+ this.collaborators,
+ this.private_repos,
+ });
+
+ Plan.fromJson(instance) {
+ if (instance != null) {
+ name = instance['name'];
+ space = instance['space'];
+ collaborators = instance['collaborators'];
+ private_repos = instance['private_repos'];
}
}
- Map toJson(UserInfo instance) => {
- 'user': {
- 'fbid': instance.fbid,
- 'uid': instance.uid,
- 'name': instance.name,
- 'avatar': instance.avatar,
- },
- 'token': instance.token,
- 'expiresIn': instance.expiresIn,
- 'expireTime': instance.expireTime,
+ Map toJson() => {
+ 'name': name,
+ 'space': space,
+ 'collaborators': collaborators,
+ 'private_repos': private_repos,
};
}
diff --git a/lib/utils/appVersion.dart b/lib/utils/appVersion.dart
new file mode 100644
index 0000000..e5f56c7
--- /dev/null
+++ b/lib/utils/appVersion.dart
@@ -0,0 +1,132 @@
+import 'dart:io';
+import 'dart:convert';
+import 'package:package_info/package_info.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:flutter_downloader/flutter_downloader.dart';
+import 'package:open_file/open_file.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:efox_flutter/http/index.dart' as Http;
+import 'package:flutter/material.dart';
+import 'package:oktoast/oktoast.dart';
+
+class AppVersion {
+ Future _checkPermission() async {
+ PermissionStatus permission = await PermissionHandler()
+ .checkPermissionStatus(PermissionGroup.storage);
+ if (permission != PermissionStatus.granted) {
+ Map permissions =
+ await PermissionHandler()
+ .requestPermissions([PermissionGroup.storage]);
+ if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ return false;
+ }
+
+ // 获取安装地址
+ Future get _apkLocalPath async {
+ final directory = await getExternalStorageDirectory();
+ return directory.path;
+ }
+
+ Future check(context, {showTips: false}) async {
+ if (!Platform.isAndroid) return;
+ // permission Status
+ bool _permissisonReady = await this._checkPermission();
+ if (!_permissisonReady) return;
+ //
+ PackageInfo packageInfo = await PackageInfo.fromPlatform();
+ String version = packageInfo.version;
+ String platform = Platform.isAndroid ? 'android' : 'ios';
+ print('version=$version $platform');
+ Map d = await checkVersion(version, platform);
+ if (d['isNew']) {
+ this._showDialog(context, d);
+ } else if (showTips) {
+ showToast('已经是最新版本');
+ /*Scaffold.of(context).showSnackBar(new SnackBar(
+ content: new Text('已经是最新版本'),
+ ));*/
+ }
+ }
+
+ Future checkVersion(String version, String platform) async {
+ Map d = {
+ 'version': version,
+ 'isNew': false,
+ 'platform': platform
+ };
+ var response = Http.get(
+ url:
+ 'https://raw.githubusercontent.com/efoxTeam/flutter-ui/master/version.json',
+ );
+ // ignore: missing_return
+ return await response.then((resp) {
+ if (resp.data != null) {
+ var data = json.decode(resp.data);
+ String newVersion =
+ (data['version'] != null) ? data['version'] : version;
+ print('$newVersion $data $version');
+ d['isNew'] = (newVersion == version) ? false : true;
+ d['version'] = newVersion;
+ return Future.value(d);
+ }
+ }).catchError((error) {
+ print('error $error');
+ });
+ }
+
+ Future _downAndInstall(String version) async {
+ String _finalApkPath = await _apkLocalPath;
+ String fileName = 'app-release.apk';
+ final taskId = await FlutterDownloader.enqueue(
+ url:
+ 'https://github.com/efoxTeam/flutter-ui/releases/download/v$version/$fileName',
+ savedDir: _finalApkPath,
+ fileName: fileName,
+ showNotification:
+ true, // show download progress in status bar (for Android)
+ openFileFromNotification:
+ true, // click on notification to open downloaded file (for Android)
+ );
+ await FlutterDownloader.loadTasks();
+ FlutterDownloader.registerCallback((id, status, progress) {
+ print(
+ 'Download task ($id) is in status ($status) and process ($progress) status ${DownloadTaskStatus.complete} _finalApkPath=$_finalApkPath');
+ if (taskId == id && status == DownloadTaskStatus.complete) {
+ OpenFile.open(_finalApkPath);
+ FlutterDownloader.open(taskId: id);
+ }
+ });
+ }
+
+ void _showDialog(context, d) {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ title: Text('升级提示'),
+ content: Text('发现新版本 ${d['version']}'),
+ actions: [
+ FlatButton(
+ child: Text('取消'),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ FlatButton(
+ textColor: Theme.of(context).primaryColor,
+ child: Text('确定'),
+ onPressed: () async {
+ await _downAndInstall(d['version']);
+ Navigator.pop(context);
+ },
+ )
+ ],
+ );
+ });
+ }
+}
diff --git a/lib/utils/file.dart b/lib/utils/file.dart
deleted file mode 100644
index f9591aa..0000000
--- a/lib/utils/file.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-import 'package:flutter/services.dart' show rootBundle;
-
-Future readLocaleFile (path) async {
- String content = await rootBundle.loadString('${path}', cache: false);
- return content;
-}
\ No newline at end of file
diff --git a/lib/utils/github.dart b/lib/utils/github.dart
new file mode 100644
index 0000000..a6553d4
--- /dev/null
+++ b/lib/utils/github.dart
@@ -0,0 +1,38 @@
+/* import 'dart:io';
+import 'package:dio/dio.dart';
+
+
+Dio _dio([Options options]) {
+ Dio dio = new Dio(BaseOptions(
+ baseUrl: 'https://api.github.com/graphql',
+ contentType: ContentType.parse('application/json;charset=UTF-8'),
+ connectTimeout: 30 * 1000,
+ receiveTimeout: 30 * 1000,
+ )); // with default Options
+ dio.interceptors.add(LogInterceptor(responseBody: true)); // debug
+ dio.interceptors
+ .add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
+ options.headers["Authorization"] = 'Bearer $token';
+ return options;
+ }, onResponse: (Response response) {
+ return response;
+ }, onError: (DioError e) {
+ return e;
+ })); //debug
+ return dio;
+}
+
+Future fetch(String query) async {
+ Map map = {'query': query};
+ return _dio().post('', data: map);
+}
+
+
+github.fetch('''
+query {
+ viewer{
+ login
+ }
+}
+ ''');
+ */
diff --git a/lib/utils/loadAsset.dart b/lib/utils/loadAsset.dart
index 510a9b0..3298b02 100644
--- a/lib/utils/loadAsset.dart
+++ b/lib/utils/loadAsset.dart
@@ -1,21 +1,10 @@
-import 'package:efox_flutter/store/index.dart' show model;
-import 'package:efox_flutter/store/http.dart' as Http;
-import 'file.dart' as FileUtil;
+import 'package:flutter/services.dart' show rootBundle;
+import 'package:efox_flutter/http/index.dart' as Http;
-Future loadMarkdownAssets(path) async {
- if (!model.config.state.isPro) {
- return FileUtil.readLocaleFile(path);
- }
- String url = model.config.state.env.githubMarkdownOrigin + path + '?v=${model.config.state.version}';
- return Http.get(url).then((res) {
- return res;
- });
+Future readLocaleFile(path) async {
+ return await rootBundle.loadString('${path}', cache: false);
}
-
-Future loadAssets(path) async {
- return Http.get(path).then((res) {
- return res;
- });
+Future readRemoteFile(path) async {
+ return await Http.get(url: path);
}
-
diff --git a/lib/utils/localStorage.dart b/lib/utils/localStorage.dart
new file mode 100644
index 0000000..22d0c3d
--- /dev/null
+++ b/lib/utils/localStorage.dart
@@ -0,0 +1,25 @@
+import 'dart:convert';
+import 'package:shared_preferences/shared_preferences.dart';
+
+class LocalStorage {
+ static Future get(String key) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ return prefs.getString(key);
+ }
+
+ static Future set(String key, String value) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ prefs.setString(key, value);
+ }
+
+ static Future setJSON(String key, value) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ value = json.encode(value);
+ prefs.setString(key, value);
+ }
+
+ static Future remove(String key) async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+ prefs.remove(key);
+ }
+}
diff --git a/lib/widget/animate/animatedbuilder/index.dart b/lib/widget/animate/animatedbuilder/index.dart
index 1f4c246..da4da47 100644
--- a/lib/widget/animate/animatedbuilder/index.dart
+++ b/lib/widget/animate/animatedbuilder/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedcontainer/index.dart b/lib/widget/animate/animatedcontainer/index.dart
index 3ca3f54..e95997d 100644
--- a/lib/widget/animate/animatedcontainer/index.dart
+++ b/lib/widget/animate/animatedcontainer/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedcrossfade/index.dart b/lib/widget/animate/animatedcrossfade/index.dart
index 2c2041a..a19c0d8 100644
--- a/lib/widget/animate/animatedcrossfade/index.dart
+++ b/lib/widget/animate/animatedcrossfade/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animateddefaulttextstyle/index.dart b/lib/widget/animate/animateddefaulttextstyle/index.dart
index 8f31477..f2b7620 100644
--- a/lib/widget/animate/animateddefaulttextstyle/index.dart
+++ b/lib/widget/animate/animateddefaulttextstyle/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedliststate/index.dart b/lib/widget/animate/animatedliststate/index.dart
index 6096f2b..d8eaeed 100644
--- a/lib/widget/animate/animatedliststate/index.dart
+++ b/lib/widget/animate/animatedliststate/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedmodalbarrier/index.dart b/lib/widget/animate/animatedmodalbarrier/index.dart
index 310a73f..5860446 100644
--- a/lib/widget/animate/animatedmodalbarrier/index.dart
+++ b/lib/widget/animate/animatedmodalbarrier/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedopacity/index.dart b/lib/widget/animate/animatedopacity/index.dart
index dda9d7b..31726f6 100644
--- a/lib/widget/animate/animatedopacity/index.dart
+++ b/lib/widget/animate/animatedopacity/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedphysicalmodel/index.dart b/lib/widget/animate/animatedphysicalmodel/index.dart
index 08ef989..db8606b 100644
--- a/lib/widget/animate/animatedphysicalmodel/index.dart
+++ b/lib/widget/animate/animatedphysicalmodel/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedpositioned/index.dart b/lib/widget/animate/animatedpositioned/index.dart
index 4951576..13e25d7 100644
--- a/lib/widget/animate/animatedpositioned/index.dart
+++ b/lib/widget/animate/animatedpositioned/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedsize/index.dart b/lib/widget/animate/animatedsize/index.dart
index 9e3dd0f..ee7c7d1 100644
--- a/lib/widget/animate/animatedsize/index.dart
+++ b/lib/widget/animate/animatedsize/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedwidget/index.dart b/lib/widget/animate/animatedwidget/index.dart
index da17cd6..92a6b89 100644
--- a/lib/widget/animate/animatedwidget/index.dart
+++ b/lib/widget/animate/animatedwidget/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animatedwidgetbasestate/index.dart b/lib/widget/animate/animatedwidgetbasestate/index.dart
index ac7338b..72d2226 100644
--- a/lib/widget/animate/animatedwidgetbasestate/index.dart
+++ b/lib/widget/animate/animatedwidgetbasestate/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/animationcontroller/index.dart b/lib/widget/animate/animationcontroller/index.dart
index 707c03d..a19d1f2 100644
--- a/lib/widget/animate/animationcontroller/index.dart
+++ b/lib/widget/animate/animationcontroller/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/decoratedboxtransition/index.dart b/lib/widget/animate/decoratedboxtransition/index.dart
index c699113..1a96f6a 100644
--- a/lib/widget/animate/decoratedboxtransition/index.dart
+++ b/lib/widget/animate/decoratedboxtransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/fadetransition/index.dart b/lib/widget/animate/fadetransition/index.dart
index 5ce625f..1eacdf9 100644
--- a/lib/widget/animate/fadetransition/index.dart
+++ b/lib/widget/animate/fadetransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/hero/index.dart b/lib/widget/animate/hero/index.dart
index 4c597b0..bdc0dce 100644
--- a/lib/widget/animate/hero/index.dart
+++ b/lib/widget/animate/hero/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/positionedtransition/index.dart b/lib/widget/animate/positionedtransition/index.dart
index 7640c1d..159155a 100644
--- a/lib/widget/animate/positionedtransition/index.dart
+++ b/lib/widget/animate/positionedtransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/rotationtransition/index.dart b/lib/widget/animate/rotationtransition/index.dart
index 485a970..e2ee19e 100644
--- a/lib/widget/animate/rotationtransition/index.dart
+++ b/lib/widget/animate/rotationtransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/scaletransition/index.dart b/lib/widget/animate/scaletransition/index.dart
index a974852..c98a659 100644
--- a/lib/widget/animate/scaletransition/index.dart
+++ b/lib/widget/animate/scaletransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/sizetransition/index.dart b/lib/widget/animate/sizetransition/index.dart
index 9850ae1..f75c8a9 100644
--- a/lib/widget/animate/sizetransition/index.dart
+++ b/lib/widget/animate/sizetransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/animate/slidetransition/index.dart b/lib/widget/animate/slidetransition/index.dart
index 6d8b4de..762116e 100644
--- a/lib/widget/animate/slidetransition/index.dart
+++ b/lib/widget/animate/slidetransition/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -14,7 +14,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/author_list.dart b/lib/widget/author_list.dart
new file mode 100644
index 0000000..eb112e2
--- /dev/null
+++ b/lib/widget/author_list.dart
@@ -0,0 +1,6 @@
+Map list = {
+ 'AnimatedBuilder': 'lhr',
+ 'GridView': 'wanwu',
+ 'ListView': 'lhr',
+ 'NestedScrollView': 'ken'
+};
diff --git a/lib/widget/bulletbox/alertdialog/index.dart b/lib/widget/bulletbox/alertdialog/index.dart
index ae86f1c..0c116af 100644
--- a/lib/widget/bulletbox/alertdialog/index.dart
+++ b/lib/widget/bulletbox/alertdialog/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -13,7 +13,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/bulletbox/bottomsheet/index.dart b/lib/widget/bulletbox/bottomsheet/index.dart
index ef41cf2..51faffd 100644
--- a/lib/widget/bulletbox/bottomsheet/index.dart
+++ b/lib/widget/bulletbox/bottomsheet/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -13,7 +13,7 @@ class Index extends StatefulWidget {
class _IndexState extends State {
@override
Widget build(BuildContext context) {
- return WidgetComp.Index(
+ return widget_comp.Index(
title: Index.title,
originCodeUrl: Index.originCodeUrl,
mdUrl: Index.mdUrl,
diff --git a/lib/widget/bulletbox/expansionPanel/index.dart b/lib/widget/bulletbox/expansionPanel/index.dart
index 4b217d6..6290217 100644
--- a/lib/widget/bulletbox/expansionPanel/index.dart
+++ b/lib/widget/bulletbox/expansionPanel/index.dart
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
-import 'package:efox_flutter/components/widgetComp.dart' as WidgetComp;
+import 'package:efox_flutter/components/widget_comp.dart' as widget_comp;
import 'demo.dart' as Demo;
class Index extends StatefulWidget {
@@ -13,7 +13,7 @@ class Index extends StatefulWidget {
class _IndexState extends State