mirror of
https://github.com/alibaba/flutter-go.git
synced 2025-08-06 09:01:00 +08:00
refactor(many files): 页面部分的文件结构调整
1.views 文件夹里面分类,页面相关文件;2.公共组件全部放在components里;3.创建resources文件夹放置资源dart文件4.修改二级菜单文字大小 BREAKING CHANGE: 重构,建议删除本地db,再编译
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../model/cat.dart';
|
||||
import '../common/widget_name_to_icon.dart';
|
||||
import '../resources/widget_name_to_icon.dart';
|
||||
import '../components/widget_item_container.dart';
|
||||
|
||||
class CateCard extends StatefulWidget {
|
||||
|
142
lib/components/category.dart
Normal file
142
lib/components/category.dart
Normal file
@ -0,0 +1,142 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../routers/application.dart';
|
||||
import '../model/cat.dart';
|
||||
import '../model/widget.dart';
|
||||
import '../widgets/index.dart';
|
||||
import '../components/widget_item_container.dart';
|
||||
|
||||
enum CateOrWigdet { Cat, WidgetDemo }
|
||||
|
||||
class CategoryHome extends StatefulWidget {
|
||||
CategoryHome(this.name);
|
||||
final String name;
|
||||
|
||||
@override
|
||||
_CategoryHome createState() => new _CategoryHome();
|
||||
}
|
||||
|
||||
class _CategoryHome extends State<CategoryHome> {
|
||||
String title = '';
|
||||
// 显示列表 cat or widget;
|
||||
List<Cat> categories = [];
|
||||
List<WidgetPoint> widgetPoints = [];
|
||||
List<Cat> catHistory = new List();
|
||||
|
||||
CatControlModel catControl = new CatControlModel();
|
||||
WidgetControlModel widgetControl = new WidgetControlModel();
|
||||
// 所有的可用demos;
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
// 初始化加入顶级的name
|
||||
this.getCatByName(widget.name).then((Cat cat) {
|
||||
catHistory.add(cat);
|
||||
searchCatOrWigdet();
|
||||
});
|
||||
}
|
||||
|
||||
Future<Cat> getCatByName(String name) async {
|
||||
return await catControl.getCatByName(name);
|
||||
}
|
||||
|
||||
Future<bool> back() {
|
||||
if (catHistory.length == 1) {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
catHistory.removeLast();
|
||||
searchCatOrWigdet();
|
||||
return Future<bool>.value(false);
|
||||
}
|
||||
|
||||
void go(Cat cat) {
|
||||
catHistory.add(cat);
|
||||
searchCatOrWigdet();
|
||||
}
|
||||
|
||||
void searchCatOrWigdet() async {
|
||||
// 假设进入这个界面的parent一定存在
|
||||
Cat parentCat = catHistory.last;
|
||||
|
||||
|
||||
// 继续搜索显示下一级depth: depth + 1, parentId: parentCat.id
|
||||
List<Cat> _categories =
|
||||
await catControl.getList(new Cat(parentId: parentCat.id));
|
||||
List<WidgetPoint> _widgetPoints = new List();
|
||||
if (_categories.isEmpty) {
|
||||
_widgetPoints =
|
||||
await widgetControl.getList(new WidgetPoint(catId: parentCat.id));
|
||||
}
|
||||
|
||||
this.setState(() {
|
||||
categories = _categories;
|
||||
title = parentCat.name;
|
||||
widgetPoints = _widgetPoints;
|
||||
});
|
||||
}
|
||||
|
||||
void onCatgoryTap(Cat cat) {
|
||||
go(cat);
|
||||
}
|
||||
|
||||
void onWidgetTap(WidgetPoint widgetPoint) {
|
||||
String targetName = widgetPoint.name;
|
||||
String targetRouter = '/category/error/404';
|
||||
widgetDemosList.forEach((item) {
|
||||
// print("targetRouter = item.routerName> ${[item.name,targetName]}");
|
||||
if (item.name == targetName) {
|
||||
targetRouter = item.routerName;
|
||||
}
|
||||
});
|
||||
Application.router.navigateTo(context, "$targetRouter");
|
||||
}
|
||||
|
||||
Widget _buildContent() {
|
||||
WidgetItemContainer wiContaienr = WidgetItemContainer(
|
||||
columnCount: 3,
|
||||
categories: categories,
|
||||
isWidgetPoint:false
|
||||
);
|
||||
if (widgetPoints.length > 0) {
|
||||
wiContaienr = WidgetItemContainer(
|
||||
categories: widgetPoints,
|
||||
columnCount: 3,
|
||||
isWidgetPoint:true
|
||||
);
|
||||
}
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(bottom: 10.0, top: 5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
image: DecorationImage(
|
||||
image: AssetImage('assets/images/paimaiLogo.png'),
|
||||
alignment: Alignment.bottomRight),
|
||||
),
|
||||
child: wiContaienr,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(title),
|
||||
),
|
||||
body: WillPopScope(
|
||||
onWillPop: () {
|
||||
return back();
|
||||
},
|
||||
child: ListView(
|
||||
children: <Widget>[
|
||||
_buildContent(),
|
||||
],
|
||||
),
|
||||
// child: Container(color: Colors.blue,child: Text('123'),),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Created with Android Studio.
|
||||
* User: 一晟
|
||||
* Date: 2019/1/5
|
||||
* Time: 下午10:20
|
||||
* email: zhu.yan@alibaba-inc.com
|
||||
* tartget: FirstPageItem
|
||||
*/
|
||||
|
||||
import '../common/Util.dart';
|
||||
|
||||
class FirstPageItem {
|
||||
bool hot;
|
||||
String isCollection;
|
||||
String tag;
|
||||
String username;
|
||||
int collectionCount;
|
||||
int commentCount;
|
||||
String title;
|
||||
String createdTime;
|
||||
String detailUrl;
|
||||
|
||||
FirstPageItem(
|
||||
{this.hot,
|
||||
this.tag,
|
||||
this.username,
|
||||
this.collectionCount,
|
||||
this.createdTime,
|
||||
this.commentCount,
|
||||
this.title,
|
||||
this.detailUrl,
|
||||
this.isCollection});
|
||||
|
||||
factory FirstPageItem.fromJson(Map<String, dynamic> json) {
|
||||
String _tag = '';
|
||||
if(json['tags'].length>0){
|
||||
_tag = '${json['tags'][0]['title']}/';
|
||||
}
|
||||
return FirstPageItem(
|
||||
hot: json['hot'],
|
||||
collectionCount: json['collectionCount'],
|
||||
commentCount: json['commentsCount'],
|
||||
tag: '$_tag${json['category']['name']}',
|
||||
username: json['user']['username'],
|
||||
createdTime: Util.getTimeDuration(json['createdAt']),
|
||||
title: json['title'],
|
||||
detailUrl: json['originalUrl'],
|
||||
isCollection: json['type'] ,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import './pager_indicator.dart';
|
||||
|
||||
class PageDragger extends StatefulWidget {
|
||||
|
||||
final canDragLeftToRight;
|
||||
final canDragRightToLeft;
|
||||
|
||||
final StreamController<SlideUpdate> slideUpdateStream;
|
||||
|
||||
|
||||
PageDragger({
|
||||
this.canDragLeftToRight,
|
||||
this.canDragRightToLeft,
|
||||
this.slideUpdateStream,
|
||||
});
|
||||
|
||||
@override
|
||||
_PageDraggerState createState() => _PageDraggerState();
|
||||
}
|
||||
|
||||
class _PageDraggerState extends State<PageDragger> {
|
||||
|
||||
static const FULL_TRANSTITION_PX = 300.0;
|
||||
|
||||
Offset dragStart;
|
||||
SlideDirection slideDirection;
|
||||
double slidePercent = 0.0;
|
||||
|
||||
onDragStart(DragStartDetails details){
|
||||
dragStart = details.globalPosition;
|
||||
}
|
||||
|
||||
onDragUpdate(DragUpdateDetails details) {
|
||||
if (dragStart != null) {
|
||||
final newPosition = details.globalPosition;
|
||||
final dx = dragStart.dx - newPosition.dx;
|
||||
|
||||
if (dx > 0 && widget.canDragRightToLeft) {
|
||||
slideDirection = SlideDirection.rightToLeft;
|
||||
} else if (dx < 0 && widget.canDragLeftToRight) {
|
||||
slideDirection = SlideDirection.leftToRight;
|
||||
} else {
|
||||
slideDirection = SlideDirection.none;
|
||||
}
|
||||
|
||||
if (slideDirection != SlideDirection.none){
|
||||
slidePercent = (dx / FULL_TRANSTITION_PX).abs().clamp(0.0, 1.0);
|
||||
} else {
|
||||
slidePercent = 0.0;
|
||||
}
|
||||
widget.slideUpdateStream.add(
|
||||
new SlideUpdate(
|
||||
UpdateType.dragging,
|
||||
slideDirection,
|
||||
slidePercent
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
onDragEnd(DragEndDetails details){
|
||||
widget.slideUpdateStream.add(
|
||||
new SlideUpdate(
|
||||
UpdateType.doneDragging,
|
||||
SlideDirection.none,
|
||||
0.0,
|
||||
)
|
||||
);
|
||||
|
||||
dragStart = null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onHorizontalDragStart: onDragStart ,
|
||||
onHorizontalDragUpdate: onDragUpdate ,
|
||||
onHorizontalDragEnd: onDragEnd ,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AnimatedPageDragger{
|
||||
|
||||
static const PERCENT_PER_MILLISECOND = 0.005;
|
||||
|
||||
final slideDirection;
|
||||
final transitionGoal;
|
||||
|
||||
AnimationController completionAnimationController;
|
||||
|
||||
AnimatedPageDragger({
|
||||
this.slideDirection,
|
||||
this.transitionGoal,
|
||||
slidePercent,
|
||||
StreamController<SlideUpdate> slideUpdateStream,
|
||||
TickerProvider vsync,
|
||||
}) {
|
||||
final startSlidePercent = slidePercent;
|
||||
var endSlidePercent;
|
||||
var duration;
|
||||
|
||||
if ( transitionGoal == TransitionGoal.open){
|
||||
endSlidePercent = 1.0;
|
||||
|
||||
final slideRemaining = 1.0 - slidePercent;
|
||||
|
||||
duration = new Duration(
|
||||
milliseconds: (slideRemaining / PERCENT_PER_MILLISECOND).round()
|
||||
);
|
||||
|
||||
} else {
|
||||
endSlidePercent = 0.0;
|
||||
duration = new Duration(
|
||||
milliseconds: (slidePercent / PERCENT_PER_MILLISECOND).round()
|
||||
);
|
||||
}
|
||||
|
||||
completionAnimationController = new AnimationController(
|
||||
duration: duration,
|
||||
vsync: vsync
|
||||
)
|
||||
..addListener((){
|
||||
slidePercent = lerpDouble(
|
||||
startSlidePercent,
|
||||
endSlidePercent,
|
||||
completionAnimationController.value
|
||||
);
|
||||
|
||||
slideUpdateStream.add(
|
||||
new SlideUpdate(
|
||||
UpdateType.animating,
|
||||
slideDirection,
|
||||
slidePercent,
|
||||
)
|
||||
);
|
||||
|
||||
})
|
||||
|
||||
..addStatusListener((AnimationStatus status){
|
||||
|
||||
if(status == AnimationStatus.completed){
|
||||
slideUpdateStream.add(
|
||||
new SlideUpdate(
|
||||
UpdateType.doneAnimating,
|
||||
slideDirection,
|
||||
endSlidePercent,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
run(){
|
||||
completionAnimationController.forward(from: 0.0);
|
||||
}
|
||||
|
||||
dispose(){
|
||||
completionAnimationController.dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enum TransitionGoal{
|
||||
open,
|
||||
close,
|
||||
}
|
||||
|
||||
enum UpdateType{
|
||||
dragging,
|
||||
doneDragging,
|
||||
animating,
|
||||
doneAnimating,
|
||||
}
|
||||
|
||||
class SlideUpdate {
|
||||
final updateType;
|
||||
final direction;
|
||||
final slidePercent;
|
||||
|
||||
SlideUpdate(
|
||||
this.updateType,
|
||||
this.direction,
|
||||
this.slidePercent
|
||||
);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PageReveal extends StatelessWidget {
|
||||
|
||||
final double revealPercent;
|
||||
final Widget child;
|
||||
|
||||
PageReveal({
|
||||
this.revealPercent,
|
||||
this.child
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipOval(
|
||||
clipper: new CircleRevealClipper(revealPercent),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CircleRevealClipper extends CustomClipper<Rect>{
|
||||
|
||||
final double revealPercent;
|
||||
|
||||
|
||||
CircleRevealClipper(
|
||||
this.revealPercent
|
||||
);
|
||||
|
||||
@override
|
||||
Rect getClip(Size size) {
|
||||
|
||||
final epicenter = new Offset(size.width / 2, size.height * 0.9);
|
||||
|
||||
double theta = atan(epicenter.dy / epicenter.dx);
|
||||
final distanceToCorner = epicenter.dy / sin(theta);
|
||||
|
||||
final radius = distanceToCorner * revealPercent;
|
||||
final diameter = 2 * radius;
|
||||
|
||||
return new Rect.fromLTWH(epicenter.dx - radius, epicenter.dy - radius, diameter, diameter);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(CustomClipper<Rect> oldClipper) {
|
||||
// TODO: implement shouldReclip
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import './pages.dart';
|
||||
|
||||
class PagerIndicator extends StatelessWidget {
|
||||
|
||||
final PagerIndicatorViewModel viewModel;
|
||||
|
||||
PagerIndicator({
|
||||
this.viewModel,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
List<PageBubble> bubbles = [];
|
||||
for(var i = 0; i < viewModel.pages.length; ++i ){
|
||||
final page = viewModel.pages[i];
|
||||
|
||||
var percentActive;
|
||||
|
||||
if(i == viewModel.activeIndex){
|
||||
percentActive = 1.0 - viewModel.slidePercent;
|
||||
} else if (i == viewModel.activeIndex - 1 && viewModel.slideDirection == SlideDirection.leftToRight){
|
||||
percentActive = viewModel.slidePercent;
|
||||
} else if (i == viewModel.activeIndex + 1 && viewModel.slideDirection == SlideDirection.rightToLeft){
|
||||
percentActive = viewModel.slidePercent;
|
||||
}else {
|
||||
percentActive = 0.0;
|
||||
}
|
||||
|
||||
bool isHollow = i > viewModel.activeIndex || (i == viewModel.activeIndex && viewModel.slideDirection == SlideDirection.leftToRight);
|
||||
|
||||
|
||||
|
||||
bubbles.add(
|
||||
new PageBubble(
|
||||
viewModel: new PageBubbleViewModel(
|
||||
page.iconAssetPath,
|
||||
page.color,
|
||||
isHollow,
|
||||
percentActive,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
final bubbleWidth = 55.0 ;
|
||||
final baseTranslation = ((viewModel.pages.length * bubbleWidth) / 2) - (bubbleWidth / 2) ;
|
||||
var translation = baseTranslation - (viewModel.activeIndex * bubbleWidth);
|
||||
|
||||
if (viewModel.slideDirection == SlideDirection.leftToRight){
|
||||
translation = bubbleWidth * viewModel.slidePercent + translation;
|
||||
}else if (viewModel.slideDirection == SlideDirection.rightToLeft){
|
||||
translation = bubbleWidth * viewModel.slidePercent - translation;
|
||||
}
|
||||
|
||||
return new Column(
|
||||
children: <Widget>[
|
||||
new Expanded(child: new Container()),
|
||||
new Transform(
|
||||
transform: new Matrix4.translationValues(0, 0.0, 0.0),
|
||||
child: new Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: bubbles,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum SlideDirection{
|
||||
leftToRight,
|
||||
rightToLeft,
|
||||
none,
|
||||
}
|
||||
|
||||
|
||||
class PagerIndicatorViewModel{
|
||||
final List<PageViewModel> pages;
|
||||
final int activeIndex;
|
||||
final SlideDirection slideDirection;
|
||||
final double slidePercent;
|
||||
|
||||
PagerIndicatorViewModel(
|
||||
this.pages,
|
||||
this.activeIndex,
|
||||
this.slideDirection,
|
||||
this.slidePercent
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
class PageBubble extends StatelessWidget {
|
||||
|
||||
final PageBubbleViewModel viewModel;
|
||||
|
||||
|
||||
PageBubble({
|
||||
this.viewModel
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Container(
|
||||
width: 55.0,
|
||||
height: 65.0,
|
||||
child: new Center(
|
||||
child: new Container(
|
||||
width: lerpDouble(20.0,45.0,viewModel.activePercent),
|
||||
height: lerpDouble(20.0,45.0,viewModel.activePercent),
|
||||
decoration: new BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: viewModel.isHollow
|
||||
? const Color(0x88FFFFFF).withAlpha(0x88 * viewModel.activePercent.round())
|
||||
: const Color(0x88FFFFFF),
|
||||
border: new Border.all(
|
||||
color: viewModel.isHollow
|
||||
? const Color(0x88FFFFFF).withAlpha((0x88 * (1.0 - viewModel.activePercent)).round())
|
||||
: Colors.transparent,
|
||||
width: 3.0,
|
||||
),
|
||||
),
|
||||
child: new Opacity(
|
||||
opacity: viewModel.activePercent,
|
||||
child: Image.asset(
|
||||
viewModel.iconAssetPath,
|
||||
color: viewModel.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PageBubbleViewModel {
|
||||
final String iconAssetPath;
|
||||
final Color color;
|
||||
final bool isHollow;
|
||||
final double activePercent;
|
||||
|
||||
PageBubbleViewModel (
|
||||
this.iconAssetPath,
|
||||
this.color,
|
||||
this.isHollow,
|
||||
this.activePercent,
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,154 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../routers/application.dart';
|
||||
import '../../routers/routers.dart';
|
||||
|
||||
final pages = [
|
||||
new PageViewModel(
|
||||
const Color(0xFFcd344f),
|
||||
//'assets/mountain.png',
|
||||
'assets/images/p2.png',
|
||||
'FlutterGo是什么?',
|
||||
'【FlutterGo】 是由"阿里拍卖"前端团队几位 Flutter 粉丝,用业余时间开发的一款,用于 Flutter 教学帮助的App,这里没有高大尚的概念,只有一个一个亲历的尝试,用最直观的方式展示的 Flutter 官方demo',
|
||||
'assets/images/plane.png'),
|
||||
new PageViewModel(
|
||||
const Color(0xFF638de3),
|
||||
//'assets/world.png',
|
||||
'assets/images/p1.png',
|
||||
'FLutterGo的背景',
|
||||
'🐢 官网文档示例较不够健全,不够直观\n🐞 运行widget demo要到处翻阅资料\n🐌 英文文档翻译生涩难懂,学习资料太少\n🚀 需要的效果不知道用哪个widget\n',
|
||||
'assets/images/calendar.png'),
|
||||
new PageViewModel(
|
||||
const Color(0xFFFF682D),
|
||||
//'assets/home.png',
|
||||
'assets/images/p3.png',
|
||||
'FlutterGo的特点',
|
||||
'🐡 详解常用widget多达 140+ 个\n🦋 持续迭代追新官方版本\n🐙 配套Demo详解widget用法\n🚀 一站式搞定所有常用widget,开箱即查\n',
|
||||
'assets/images/house.png',
|
||||
),
|
||||
];
|
||||
|
||||
class Page extends StatelessWidget {
|
||||
final PageViewModel viewModel;
|
||||
final double percentVisible;
|
||||
|
||||
Page({
|
||||
this.viewModel,
|
||||
this.percentVisible = 1.0,
|
||||
});
|
||||
_goHomePage(context) {
|
||||
Navigator.of(context)
|
||||
.pushNamedAndRemoveUntil('/home', (Route<dynamic> route) => false);
|
||||
}
|
||||
|
||||
Widget creatButton(
|
||||
BuildContext context, String txt, IconData iconName, String type) {
|
||||
return RaisedButton.icon(
|
||||
onPressed: () {
|
||||
if (type == 'start') {
|
||||
_goHomePage(context);
|
||||
} else if (type == 'goGithub') {
|
||||
Application.router.navigateTo(context,
|
||||
'${Routes.webViewPage}?title=${Uri.encodeComponent(txt)} Doc&&url=${Uri.encodeComponent("https://github.com/alibaba/flutter-go")}');
|
||||
}
|
||||
},
|
||||
elevation: 10.0,
|
||||
color: Colors.black26,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
|
||||
//如果不手动设置icon和text颜色,则默认使用foregroundColor颜色
|
||||
icon: new Icon(iconName, color: Colors.white, size: 20.0),
|
||||
label: new Text(
|
||||
txt,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: Colors.white, fontSize: 16, fontWeight: FontWeight.w700),
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new Container(
|
||||
width: double.infinity,
|
||||
color: viewModel.color,
|
||||
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
|
||||
child: new Opacity(
|
||||
opacity: percentVisible,
|
||||
child:ListView(
|
||||
children: <Widget>[
|
||||
layout(context)
|
||||
],
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Column layout(BuildContext context) {
|
||||
return new Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
new Transform(
|
||||
transform: new Matrix4.translationValues(
|
||||
0.0, 50.0 * (1.0 - percentVisible), 0.0),
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.only(top: 20.0, bottom: 10.0),
|
||||
child: new Image.asset(viewModel.heroAssetPath,
|
||||
width: 160.0, height: 160.0),
|
||||
),
|
||||
),
|
||||
new Transform(
|
||||
transform: new Matrix4.translationValues(
|
||||
0.0, 30.0 * (1.0 - percentVisible), 0.0),
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.only(top: 10.0, bottom: 10.0),
|
||||
child: new Text(
|
||||
viewModel.title,
|
||||
style: new TextStyle(
|
||||
color: Colors.white,
|
||||
fontFamily: 'FlamanteRoma',
|
||||
fontSize: 28.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
new Transform(
|
||||
transform: new Matrix4.translationValues(
|
||||
0.0, 30.0 * (1.0 - percentVisible), 0.0),
|
||||
child: new Padding(
|
||||
padding: new EdgeInsets.only(bottom: 10.0),
|
||||
child: new Text(
|
||||
viewModel.body,
|
||||
textAlign: TextAlign.center,
|
||||
style: new TextStyle(
|
||||
height: 1.2,
|
||||
color: Colors.white,
|
||||
fontFamily: 'FlamanteRomaItalic',
|
||||
fontSize: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
ButtonBar(
|
||||
alignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
creatButton(context, '开始使用', Icons.add_circle_outline, 'start'),
|
||||
creatButton(context, 'GitHub', Icons.arrow_forward, 'goGithub'),
|
||||
],
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class PageViewModel {
|
||||
final Color color;
|
||||
final String heroAssetPath;
|
||||
final String title;
|
||||
final String body;
|
||||
final String iconAssetPath;
|
||||
|
||||
PageViewModel(
|
||||
this.color,
|
||||
this.heroAssetPath,
|
||||
this.title,
|
||||
this.body,
|
||||
this.iconAssetPath,
|
||||
);
|
||||
}
|
73
lib/components/full_screen_code_dialog.dart
Normal file
73
lib/components/full_screen_code_dialog.dart
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* @Author: 一凨
|
||||
* @Date: 2019-01-14 11:42:32
|
||||
* @Last Modified by: 一凨
|
||||
* @Last Modified time: 2019-01-14 14:42:00
|
||||
*/
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_go/utils/example_code_parser.dart';
|
||||
import 'package:flutter_go/utils/syntax_highlighter.dart';
|
||||
|
||||
class FullScreenCodeDialog extends StatefulWidget {
|
||||
const FullScreenCodeDialog({this.filePath});
|
||||
|
||||
final String filePath;
|
||||
_FullScreenCodeDialogState createState() => _FullScreenCodeDialogState();
|
||||
}
|
||||
|
||||
class _FullScreenCodeDialogState extends State<FullScreenCodeDialog> {
|
||||
String _exampleCode;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
getExampleCode(context,'${widget.filePath}', DefaultAssetBundle.of(context))
|
||||
.then<void>((String code) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_exampleCode = code ?? 'Example code not found';
|
||||
});
|
||||
}
|
||||
});
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final SyntaxHighlighterStyle style =
|
||||
Theme.of(context).brightness == Brightness.dark
|
||||
? SyntaxHighlighterStyle.darkThemeStyle()
|
||||
: SyntaxHighlighterStyle.lightThemeStyle();
|
||||
|
||||
Widget body;
|
||||
if (_exampleCode == null) {
|
||||
body = const Center(child: CircularProgressIndicator());
|
||||
} else {
|
||||
body = SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(fontFamily: 'monospace', fontSize: 10.0),
|
||||
children: <TextSpan>[
|
||||
DartSyntaxHighlighter(style).format(_exampleCode)
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(
|
||||
Icons.clear,
|
||||
semanticLabel: 'Close',
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
}),
|
||||
title: const Text('Example code'),
|
||||
),
|
||||
body: body);
|
||||
}
|
||||
}
|
54
lib/components/list_view_item.dart
Normal file
54
lib/components/list_view_item.dart
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* @Author: 一凨
|
||||
* @Date: 2019-01-14 17:53:54
|
||||
* @Last Modified by: 一凨
|
||||
* @Last Modified time: 2019-01-14 17:57:51
|
||||
*/
|
||||
import 'package:flutter/material.dart';
|
||||
import '../routers/application.dart';
|
||||
import '../routers/routers.dart';
|
||||
import 'dart:core';
|
||||
|
||||
|
||||
class ListViewItem extends StatelessWidget {
|
||||
final String itemUrl;
|
||||
final String itemTitle;
|
||||
final String data;
|
||||
|
||||
const ListViewItem({Key key, this.itemUrl, this.itemTitle, this.data})
|
||||
: super(key: key);
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
elevation: 4.0,
|
||||
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
// _launchURL(itemUrl, context);
|
||||
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(itemTitle)}&url=${Uri.encodeComponent(itemUrl)}');
|
||||
},
|
||||
title: Padding(
|
||||
child: Text(
|
||||
itemTitle,
|
||||
style: TextStyle(color: Colors.black, fontSize: 15.0),
|
||||
),
|
||||
padding: EdgeInsets.only(top: 10.0),
|
||||
),
|
||||
subtitle: Row(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
child: Text(data,
|
||||
style: TextStyle(color: Colors.black54, fontSize: 10.0)),
|
||||
padding: EdgeInsets.only(top: 10.0, bottom: 10.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
trailing:
|
||||
Icon(Icons.keyboard_arrow_right, color: Colors.grey, size: 30.0),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import 'package:flutter_markdown/flutter_markdown.dart' as md;
|
||||
import '../common/high_light_code.dart';
|
||||
import 'package:flutter_go/utils/high_light_code.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 使用方法
|
||||
|
204
lib/components/widget_demo.dart
Normal file
204
lib/components/widget_demo.dart
Normal file
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @author Nealyang
|
||||
*
|
||||
* 新widget详情页模板
|
||||
*/
|
||||
import 'package:flutter/material.dart';
|
||||
import '../routers/application.dart';
|
||||
import '../routers/routers.dart';
|
||||
import '../components/markdown.dart';
|
||||
import '../model/collection.dart';
|
||||
import '../widgets/index.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import '../event/event_bus.dart';
|
||||
import '../event/event_model.dart';
|
||||
import 'dart:core';
|
||||
|
||||
class WidgetDemo extends StatefulWidget {
|
||||
final List<dynamic> contentList;
|
||||
final String docUrl;
|
||||
final String title;
|
||||
final String codeUrl;
|
||||
final Widget bottomNaviBar;
|
||||
|
||||
WidgetDemo(
|
||||
{Key key,
|
||||
@required this.title,
|
||||
@required this.contentList,
|
||||
@required this.codeUrl,
|
||||
@required this.docUrl,
|
||||
this.bottomNaviBar
|
||||
})
|
||||
: super(key: key);
|
||||
|
||||
_WidgetDemoState createState() => _WidgetDemoState();
|
||||
}
|
||||
|
||||
class _WidgetDemoState extends State<WidgetDemo> {
|
||||
bool _hasCollected = false;
|
||||
CollectionControlModel _collectionControl = new CollectionControlModel();
|
||||
var _collectionIcons;
|
||||
List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
String _router = '';
|
||||
|
||||
void showInSnackBar(String value) {
|
||||
Fluttertoast.showToast(
|
||||
msg: value,
|
||||
toastLength: Toast.LENGTH_SHORT,
|
||||
gravity: ToastGravity.CENTER,
|
||||
timeInSecForIos: 1,
|
||||
backgroundColor: Colors.grey,
|
||||
textColor: Colors.white);
|
||||
}
|
||||
|
||||
|
||||
List<Widget> _buildContent() {
|
||||
List<Widget> _list = [
|
||||
SizedBox(
|
||||
height: 10.0,
|
||||
),
|
||||
];
|
||||
widget.contentList.forEach((item) {
|
||||
if (item.runtimeType == String) {
|
||||
_list.add(MarkdownBody(item));
|
||||
_list.add(
|
||||
SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_list.add(item);
|
||||
}
|
||||
});
|
||||
return _list;
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_collectionControl.getRouterByName(widget.title).then((list) {
|
||||
widgetDemosList.forEach((item) {
|
||||
if (item.name == widget.title) {
|
||||
_router = item.routerName;
|
||||
}
|
||||
});
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = list.length > 0;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 点击收藏按钮
|
||||
_getCollection() {
|
||||
if (_hasCollected) {
|
||||
// 删除操作
|
||||
_collectionControl.deleteByName(widget.title).then((result) {
|
||||
if (result > 0 && this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = false;
|
||||
});
|
||||
showInSnackBar('已取消收藏');
|
||||
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
print('删除错误');
|
||||
});
|
||||
} else {
|
||||
// 插入操作
|
||||
_collectionControl
|
||||
.insert(Collection(name: widget.title, router: _router))
|
||||
.then((result) {
|
||||
if (this.mounted) {
|
||||
setState(() {
|
||||
_hasCollected = true;
|
||||
});
|
||||
|
||||
if (ApplicationEvent.event != null) {
|
||||
ApplicationEvent.event
|
||||
.fire(CollectionEvent(widget.title, _router, false));
|
||||
}
|
||||
|
||||
showInSnackBar('收藏成功');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _selectValue(value){
|
||||
if(value == 'doc'){
|
||||
// _launchURL(widget.docUrl);
|
||||
Application.router.navigateTo(context, '${Routes.webViewPage}?title=${Uri.encodeComponent(widget.title)} Doc&&url=${Uri.encodeComponent(widget.docUrl)}');
|
||||
}else if(value =='code'){
|
||||
Application.router.navigateTo(context, '${Routes.codeView}?filePath=${Uri.encodeComponent(widget.codeUrl)}');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_hasCollected) {
|
||||
_collectionIcons = Icons.favorite;
|
||||
} else {
|
||||
_collectionIcons = Icons.favorite_border;
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
actions: <Widget>[
|
||||
new IconButton(
|
||||
tooltip: 'goBack home',
|
||||
onPressed: () {
|
||||
Navigator.popUntil(context, ModalRoute.withName('/home'));
|
||||
},
|
||||
icon: Icon(Icons.home),
|
||||
),
|
||||
new IconButton(
|
||||
tooltip: 'collection',
|
||||
onPressed: _getCollection,
|
||||
icon: Icon(_collectionIcons),
|
||||
),
|
||||
PopupMenuButton<String>(
|
||||
onSelected: _selectValue,
|
||||
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||
const PopupMenuItem<String>(
|
||||
value: 'doc',
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.library_books,size: 22.0,),
|
||||
title: Text('查看文档'),
|
||||
),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
const PopupMenuItem<String>(
|
||||
value: 'code',
|
||||
child: ListTile(
|
||||
leading: Icon(Icons.code,size: 22.0,),
|
||||
title: Text('查看Demo'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0),
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: _buildContent(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: (widget.bottomNaviBar is Widget) ? widget
|
||||
.bottomNaviBar : null
|
||||
);
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
* @author 一凨
|
||||
*/
|
||||
import 'package:flutter/material.dart';
|
||||
import '../common/style.dart';
|
||||
import '../common/widget_name_to_icon.dart';
|
||||
import 'package:flutter_go/utils/style.dart';
|
||||
import 'package:flutter_go/resources/widget_name_to_icon.dart';
|
||||
|
||||
String _widgetName;
|
||||
|
||||
@ -13,9 +13,15 @@ class WidgetItem extends StatelessWidget {
|
||||
final int index; //用于计算border
|
||||
final int totalCount;
|
||||
final int rowLength;
|
||||
final String textSize;
|
||||
|
||||
WidgetItem(
|
||||
{this.title, this.onTap, this.index, this.totalCount, this.rowLength});
|
||||
{this.title,
|
||||
this.onTap,
|
||||
this.index,
|
||||
this.totalCount,
|
||||
this.rowLength,
|
||||
this.textSize});
|
||||
|
||||
Border _buildBorder(context) {
|
||||
Border _border;
|
||||
@ -64,6 +70,9 @@ class WidgetItem extends StatelessWidget {
|
||||
Icons.crop,
|
||||
);
|
||||
}
|
||||
final textStyle = (textSize == 'middle')
|
||||
? TextStyle(fontSize: 13.8, fontFamily: 'MediumItalic')
|
||||
: TextStyle(fontSize: 16.0);
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
@ -80,7 +89,7 @@ class WidgetItem extends StatelessWidget {
|
||||
SizedBox(
|
||||
height: 8.0,
|
||||
),
|
||||
Text(_widgetName),
|
||||
Text(_widgetName, style: textStyle),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -7,6 +7,7 @@ class WidgetItemContainer extends StatelessWidget {
|
||||
final int columnCount; //一行几个
|
||||
final List<dynamic> categories;
|
||||
final bool isWidgetPoint;
|
||||
|
||||
// 所有的可用demos;
|
||||
final List widgetDemosList = new WidgetDemoList().getDemos();
|
||||
|
||||
@ -50,6 +51,7 @@ class WidgetItemContainer extends StatelessWidget {
|
||||
index: addI,
|
||||
totalCount: length,
|
||||
rowLength: columnCount,
|
||||
textSize: isWidgetPoint ? 'middle' : 'small',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
Reference in New Issue
Block a user