🐛 修复详情页右侧滑和linkto的冲突。优化代码结构

This commit is contained in:
toly
2020-05-10 09:18:00 +08:00
parent fcf85cc399
commit 2cc2e1dbca
22 changed files with 327 additions and 536 deletions

2
.gitignore vendored
View File

@@ -32,8 +32,6 @@
.pub/
/build/
/lib/tools/
# Web related
lib/generated_plugin_registrant.dart
# Exceptions to above rules.
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

View File

@@ -23,7 +23,6 @@ class CollectBloc extends Bloc<CollectEvent, CollectState> {
Stream<CollectState> mapEventToState(
CollectEvent event,
) async* {
print('CollectState');
if (event is ToggleCollectEvent) {
await repository.toggleCollect(event.id);
final widgets = await repository.loadCollectWidgets();

View File

@@ -57,7 +57,6 @@ class GlobalBloc extends Bloc<GlobalEvent, GlobalState> {
if (event is EventChangeItemStyle) {
await sp
..setInt(SP.itemStyleIndex, event.index); //固化数据
print('EventChangeItemStyle+${event.index}');
yield state.copyWith(itemStyleIndex: event.index);
}
}

View File

@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
/// create by 张风捷特烈 on 2020-04-07
/// contact me by email 1981462002@qq.com
/// 说明:
typedef BoolWidgetBuilder = Widget Function(BuildContext context, bool selected);
class MultiChipFilter<T> extends StatefulWidget {
final List<T> data;
final BoolWidgetBuilder labelBuilder;
final IndexedWidgetBuilder avatarBuilder;
final Function(List<int>) onChange;
MultiChipFilter({@required this.data,@required this.labelBuilder,this.avatarBuilder,@required this.onChange});
@override
_MultiChipFilterState createState() => _MultiChipFilterState();
}
class _MultiChipFilterState<T> extends State<MultiChipFilter<T>> {
List<int> _selected = <int>[];
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.data.map((e) =>
_buildChild(context,widget.data.indexOf(e))).toList(),
);
}
Widget _buildChild(BuildContext context,int index) {
bool selected = _selected.contains(index);
return FilterChip(
selectedColor: Colors.orange.withAlpha(55),
labelPadding: EdgeInsets.only(left: 5,right: 5),
selectedShadowColor: Colors.blue,
shadowColor: Colors.orangeAccent,
pressElevation: 5,
elevation: 3,
avatar: widget.avatarBuilder==null?null:widget.avatarBuilder(context,index),
label: widget.labelBuilder(context,selected),
selected: selected,
onSelected: (bool value) {
setState(() {
if (value) {
_selected.add(index);
} else {
_selected.removeWhere((i) => i == index);
}
if(widget.onChange!=null) widget.onChange(_selected);
});
},
);
}
}

View File

@@ -99,7 +99,6 @@ class CategoryDao {
"ON c.id = cw.categoryId GROUP BY c.id "
"ORDER BY priority DESC,created DESC",
[]);
print(data);
return data;
}

View File

@@ -34,16 +34,13 @@ class _UnitNavigationState extends State<UnitNavigation> {
Widget build(BuildContext context) {
return BlocBuilder<HomeBloc, HomeState>(
builder: (_, state) => Scaffold(
drawer: HomeDrawer(color:state.homeColor),
//滑页
endDrawer: HomeRightDrawer(color: state.homeColor,),
//右滑页
drawer: HomeDrawer(color:state.homeColor), //左滑页
endDrawer: HomeRightDrawer(color: state.homeColor), //滑页
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
floatingActionButton: _buildSearchButton(state.homeColor),
body: PageView(
physics:const NeverScrollableScrollPhysics(),
//使用PageView实现页面的切换
physics: const NeverScrollableScrollPhysics(),
controller: _controller,
children: <Widget>[
HomePage(),

View File

@@ -16,8 +16,6 @@ class UnitPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
canvas.translate(
size.width / 2 - width * 0.5, size.height / 2 - width * 0.5);
@@ -28,7 +26,6 @@ class UnitPainter extends CustomPainter {
canvas.restore();
canvas.save();
canvas.translate(
size.width / 2 * (1 - factor), -size.width / 2 * (1 - factor));
drawColor2(canvas);

View File

@@ -22,7 +22,6 @@ class UnitSplash extends StatefulWidget {
class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
AnimationController _controller;
AnimationController _secondController;
double _factor;
Animation _curveAnim;
@@ -31,31 +30,36 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
@override
void initState() {
SystemUiOverlayStyle systemUiOverlayStyle =
SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
_controller =
AnimationController(duration: Duration(milliseconds: 1000), vsync: this)
..addListener(() => setState(() {
return _factor = _curveAnim.value;
}))
..addStatusListener((s) {
if (s == AnimationStatus.completed) {
setState(() {
_animEnd = true;
Future.delayed(Duration(milliseconds: 600)).then((e){
Navigator.of(context).pushReplacementNamed(Router.nav);
});
});
}
});
AnimationController(duration: Duration(milliseconds: 1000), vsync: this)
..addListener(_listenAnimation)
..addStatusListener(_listenStatus)
..forward();
_curveAnim =
CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn);
_controller.forward();
_curveAnim = CurvedAnimation(parent: _controller, curve: Curves.fastOutSlowIn);
super.initState();
}
void _listenAnimation() {
setState(() {
return _factor = _curveAnim.value;
});
}
void _listenStatus(AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {
_animEnd = true;
Future.delayed(Duration(milliseconds: 500)).then((e) {
Navigator.of(context).pushReplacementNamed(Router.nav);
});
});
}
}
@override
Widget build(BuildContext context) {
var winH = MediaQuery.of(context).size.height;
@@ -65,7 +69,7 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
body: Stack(
alignment: Alignment.center,
children: <Widget>[
buildLogo(Colors.blue),
_buildLogo(Colors.blue),
Container(
width: winW,
height: winH,
@@ -73,15 +77,15 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
painter: UnitPainter(factor: _factor),
),
),
buildText(winH, winW),
buildHead(),
buildPower(),
_buildText(winH, winW),
_buildHead(),
_buildPower(),
],
),
);
}
Positioned buildText(double winH, double winW) {
Widget _buildText(double winH, double winW) {
final shadowStyle = TextStyle(
fontSize: 45,
color: Theme.of(context).primaryColor,
@@ -109,7 +113,7 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
final colors = [Colors.red, Colors.yellow, Colors.blue];
Widget buildLogo(Color primaryColor) {
Widget _buildLogo(Color primaryColor) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(0, 0),
@@ -132,7 +136,7 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
);
}
Widget buildHead() => SlideTransition(
Widget _buildHead() => SlideTransition(
position: Tween<Offset>(
end: const Offset(0, 0),
begin: const Offset(0, -5),
@@ -143,21 +147,21 @@ class _UnitSplashState extends State<UnitSplash> with TickerProviderStateMixin {
child: Image.asset('assets/images/icon_head.png'),
));
Widget buildPower() => Positioned(
bottom: 30,
right: 30,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 300),
opacity: _animEnd ? 1.0 : 0.0,
child: const Text("Power By 张风捷特烈",
style: TextStyle(
color: Colors.grey,
shadows: [
Shadow(
color: Colors.black,
blurRadius: 1,
offset: Offset(0.3, 0.3))
],
fontSize: 16))),
);
Widget _buildPower() => Positioned(
bottom: 30,
right: 30,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 300),
opacity: _animEnd ? 1.0 : 0.0,
child: const Text("Power By 张风捷特烈",
style: TextStyle(
color: Colors.grey,
shadows: [
Shadow(
color: Colors.black,
blurRadius: 1,
offset: Offset(0.3, 0.3))
],
fontSize: 16))),
);
}

View File

@@ -99,7 +99,7 @@ class AboutAppPage extends StatelessWidget {
if (await canLaunch(url)) {
await launch(url);
} else {
debugPrint('Could not launch $url');
}
}

View File

@@ -26,8 +26,6 @@ class _CollectPageState extends State<CollectPage> with AutomaticKeepAliveClient
@override
Widget build(BuildContext context) {
print('-------CollectPage-------build-------');
var _topContext = context;
return Scaffold(
backgroundColor: BlocProvider.of<HomeBloc>(context).state.homeColor.withAlpha(11),
@@ -50,7 +48,6 @@ class _CollectPageState extends State<CollectPage> with AutomaticKeepAliveClient
CategoryPage(),
BlocBuilder<CollectBloc, CollectState>(
builder: (_, state) {
// print('-------BlocBuilder-------build-------');
return CustomScrollView(
slivers: <Widget>[_buildContent(context, state)],
);

View File

@@ -16,6 +16,11 @@ import 'package:flutter_unit/views/common/unit_drawer_header.dart';
/// contact me by email 1981462002@qq.com
/// 说明:
const _kTextShadowStyle= TextStyle(color: Colors.grey, shadows: [
Shadow(
color: Colors.white, offset: Offset(.5, .5), blurRadius: .5)
]);
class CategoryEndDrawer extends StatelessWidget {
final WidgetModel widget;
@@ -24,45 +29,36 @@ class CategoryEndDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Drawer(
child: _buildChild(context),
child: Container(
child: ListView(padding: EdgeInsets.zero, children: <Widget>[
UnitDrawerHeader(color: Theme.of(context).primaryColor),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Circle(color: widget.color,),
SizedBox(width: 10,),
Text(widget.name)
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Panel(
child: Text(
widget.info,
style:_kTextShadowStyle
),
),
),
Divider(),
_buildTitle(context),
Divider(),
CategoryInfo(widget.id)
])),
);
}
Widget _buildChild(BuildContext context) => Container(
child: ListView(padding: EdgeInsets.zero, children: <Widget>[
UnitDrawerHeader(color: Theme.of(context).primaryColor),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Circle(
color: widget.color,
),
SizedBox(
width: 10,
),
Text(widget.name)
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Panel(
child: Text(
widget.info,
style: TextStyle(color: Colors.grey, shadows: [
Shadow(
color: Colors.white, offset: Offset(.5, .5), blurRadius: .5)
]),
),
),
),
Divider(),
_buildTitle(context),
Divider(),
CategoryInfo(widget.id)
]));
Widget _buildTitle(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(top: 5.0, bottom: 8),
@@ -98,7 +94,6 @@ class CategoryInfo extends StatefulWidget {
final int id;
CategoryInfo(this.id);
@override
_CategoryInfoState createState() => _CategoryInfoState();
}
@@ -107,8 +102,6 @@ class _CategoryInfoState extends State<CategoryInfo> {
List<int> categoryIds = [];
List<CategoryModel> _categories = [];
// var
@override
void didChangeDependencies() {
_loadCategoryIds();
@@ -117,16 +110,11 @@ class _CategoryInfoState extends State<CategoryInfo> {
@override
Widget build(BuildContext context) {
return _buildCategory();
}
Widget _buildCategory() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Wrap(
alignment: WrapAlignment.spaceBetween,
spacing: 5,
// runSpacing: 10,
children: categories.map((e) => _buildItem(e)).toList(),
),
);
@@ -136,7 +124,6 @@ class _CategoryInfoState extends State<CategoryInfo> {
bool inHere = categoryIds.contains(category.id);
return FilterChip(
backgroundColor: Theme.of(context).primaryColor.withAlpha(33),
// backgroundColor: category.color.withAlpha(88),
selectedColor: Colors.orange.withAlpha(120),
shadowColor: Theme.of(context).primaryColor,
elevation: 1,
@@ -153,8 +140,7 @@ class _CategoryInfoState extends State<CategoryInfo> {
});
}
CategoryRepository get repository =>
BlocProvider.of<CategoryBloc>(context).repository;
CategoryRepository get repository => BlocProvider.of<CategoryBloc>(context).repository;
List<CategoryModel> get categories {
var state = BlocProvider.of<CategoryBloc>(context).state;
@@ -166,10 +152,7 @@ class _CategoryInfoState extends State<CategoryInfo> {
void _loadCategoryIds() async {
categoryIds = await repository.getCategoryByWidget(widget.id);
print(categoryIds);
if(mounted)
setState(() {
});
setState(() {});
}
}

View File

@@ -2,16 +2,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_star/flutter_star.dart';
import 'package:flutter_unit/app/res/cons.dart';
import 'package:flutter_unit/app/router.dart';
import 'package:flutter_unit/app/style/TolyIcon.dart';
import 'package:flutter_unit/app/utils/Toast.dart';
import 'package:flutter_unit/blocs/collect/collect_bloc.dart';
import 'package:flutter_unit/blocs/collect/collect_event.dart';
import 'package:flutter_unit/blocs/collect/collect_state.dart';
import 'package:flutter_unit/blocs/detail/detail_bloc.dart';
import 'package:flutter_unit/blocs/detail/detail_event.dart';
import 'package:flutter_unit/blocs/detail/detail_state.dart';
import 'package:flutter_unit/blocs/global/global_bloc.dart';
import 'package:flutter_unit/blocs/bloc_exp.dart';
import 'package:flutter_unit/components/permanent/feedback_widget.dart';
import 'package:flutter_unit/components/permanent/panel.dart';
import 'package:flutter_unit/components/project/widget_node_panel.dart';
@@ -31,7 +24,6 @@ class WidgetDetailPage extends StatefulWidget {
class _WidgetDetailPageState extends State<WidgetDetailPage> {
List<WidgetModel> _models = [];
bool openBottom = false;
@override
void initState() {
@@ -41,88 +33,42 @@ class _WidgetDetailPageState extends State<WidgetDetailPage> {
@override
Widget build(BuildContext context) {
print('build---_WidgetDetailPageState---');
return WillPopScope(
onWillPop: () async {
_models.removeLast();
if (_models.length > 0) {
setState(() {
BlocProvider.of<DetailBloc>(context)
.add(FetchWidgetDetail(_models.last));
});
return false;
} else {
return true;
}
},
child: Scaffold(
endDrawer: CategoryEndDrawer(widget: _models.last,),
appBar: AppBar(
title: Text(_models.last.name),
actions: <Widget>[
Builder(builder: (ctx)=>GestureDetector(
onLongPress: (){
Scaffold.of(ctx).openEndDrawer();
},
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Icon(Icons.home),
),
onTap: () {
Navigator.of(ctx).pop();
})),
_buildCollectButton(_models.last, context),
],
),
body: SingleChildScrollView(
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
WidgetDetailTitle(
model: _models.last,
),
BlocBuilder<DetailBloc, DetailState>(builder: (_, state) {
print('build---${state.runtimeType}---');
if (state is DetailWithData) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding:
const EdgeInsets.only(left: 15, right: 5),
child: Icon(
Icons.link,
color: Colors.blue,
),
),
Text(
'相关组件',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 16),
),
],
),
_buildLinkTo(
context,
state.links,
),
Divider(),
_buildNodes(state.nodes, state.widgetModel.name)
],
);
}
return Container();
})
],
),
),
)),
return Scaffold(
endDrawer: CategoryEndDrawer(widget: _models.last),
appBar: AppBar(
title: Text(_models.last.name),
actions: <Widget>[
_buildToHome(),
_buildCollectButton(_models.last, context),
],
),
body: Builder(builder: _buildContent),
);
}
Widget _buildContent(BuildContext context) => WillPopScope(
onWillPop: () => _whenPop(context),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
WidgetDetailTitle(
model: _models.last,
),
BlocBuilder<DetailBloc, DetailState>(builder: _buildDetail)
],
),
));
Widget _buildToHome() => Builder(
builder: (ctx) => GestureDetector(
onLongPress: () => Scaffold.of(ctx).openEndDrawer(),
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Icon(Icons.home),
),
onTap: () => Navigator.of(ctx).pop()));
Widget _buildCollectButton(WidgetModel model, BuildContext context) {
//监听 CollectBloc 伺机弹出toast
return BlocListener<CollectBloc, CollectState>(
@@ -130,36 +76,42 @@ class _WidgetDetailPageState extends State<WidgetDetailPage> {
bool collected = st.widgets.contains(model);
var msg =
collected ? "收藏【${model.name}】组件成功!" : "已取消【${model.name}】组件收藏!";
Toast.toast(ctx, msg,
duration: Duration(milliseconds: collected?1500:600),
action: collected
? SnackBarAction(
textColor: Colors.white, label: '收藏夹管理', onPressed: () {
Scaffold.of(ctx).openEndDrawer();
}): null,);
_showToast(ctx, msg, collected);
},
child: FeedbackWidget(
onPressed: () => BlocProvider.of<CollectBloc>(context)
.add(ToggleCollectEvent(id: model.id)),
child: BlocBuilder<CollectBloc, CollectState>(builder: (_, s) {
return Padding(
padding: const EdgeInsets.only(right: 20.0),
child: Icon(
s.widgets.contains(model)
? TolyIcon.icon_star_ok
: TolyIcon.icon_star_add,
size: 25,
),
);
}),
child: BlocBuilder<CollectBloc, CollectState>(
builder: (_, s) => Padding(
padding: const EdgeInsets.only(right: 20.0),
child: Icon(
s.widgets.contains(model)
? TolyIcon.icon_star_ok
: TolyIcon.icon_star_add,
size: 25,
),
)),
));
}
_showToast(BuildContext ctx, String msg, bool collected) {
Toast.toast(
ctx,
msg,
duration: Duration(milliseconds: collected ? 1500 : 600),
action: collected
? SnackBarAction(
textColor: Colors.white,
label: '收藏夹管理',
onPressed: () => Scaffold.of(ctx).openEndDrawer())
: null,
);
}
final List<int> colors = Cons.tabColors;
Widget _buildNodes(List<NodeModel> nodes, String name) {
var globalState = BlocProvider.of<GlobalBloc>(context).state;
print('build---_buildNodes---${widget.model}');
return Column(
children: nodes
.asMap()
@@ -176,6 +128,52 @@ class _WidgetDetailPageState extends State<WidgetDetailPage> {
.toList());
}
Future<bool> _whenPop(BuildContext context) async {
if (Scaffold.of(context).isEndDrawerOpen) return true;
_models.removeLast();
if (_models.length > 0) {
setState(() {
BlocProvider.of<DetailBloc>(context)
.add(FetchWidgetDetail(_models.last));
});
return false;
} else {
return true;
}
}
Widget _buildDetail(BuildContext context, DetailState state) {
if (state is DetailWithData) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
const Padding(
padding: EdgeInsets.only(left: 15, right: 5),
child: Icon(
Icons.link,
color: Colors.blue,
),
),
const Text(
'相关组件',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
],
),
_buildLinkTo(
context,
state.links,
),
Divider(),
_buildNodes(state.nodes, state.widgetModel.name)
],
);
}
return Container();
}
_buildLinkTo(BuildContext context, List<WidgetModel> links) {
if (links == null || links.isEmpty) {
return Padding(

View File

@@ -20,67 +20,21 @@ class HomeDrawer extends StatelessWidget {
child: _buildChild(context),
);
}
Widget _buildChild(BuildContext context) => Container(
color: color.withAlpha(33),
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UnitDrawerHeader(color:color),
ListTile(
leading: Icon(
TolyIcon.icon_them,
color: Theme.of(context).primaryColor,
),
trailing: _nextIcon(context),
title: Text('我的主题'),
onTap: () {
Navigator.of(context).pushNamed(Router.setting);
},
),
ListTile(
leading: Icon(
TolyIcon.icon_layout,
color: Theme.of(context).primaryColor,
),
title: Text('数据统计'),
trailing: _nextIcon(context),
onTap: () {},
),
Divider(
height: 1,
),
UnitDrawerHeader(color: color),
_buildItem(context,TolyIcon.icon_them,'我的主题',Router.setting),
_buildItem(context,TolyIcon.icon_layout,'数据统计',null),
Divider(height: 1),
_buildFlutterUnit(context),
ListTile(
leading: Icon(
TolyIcon.icon_code,
color: Theme.of(context).primaryColor,
),
title: Text('Dart 手册'),
trailing: _nextIcon(context),
onTap: () {},
),
Divider(
height: 1,
),
ListTile(
leading: Icon(
Icons.info,
color: Theme.of(context).primaryColor,
),
title: Text('关于应用'),
trailing: _nextIcon(context),
onTap: () => Navigator.of(context).pushNamed(Router.about_app),
),
ListTile(
leading: Icon(
TolyIcon.icon_kafei,
color: Theme.of(context).primaryColor,
),
title: Text('联系本王'),
trailing: _nextIcon(context),
onTap: () => Navigator.of(context).pushNamed(Router.about_me),
),
_buildItem(context,TolyIcon.icon_code,'Dart 手册',null),
Divider(height: 1),
_buildItem(context, Icons.info,'关于应用',Router.about_app),
_buildItem(context, TolyIcon.icon_kafei,'联系本王',Router.about_me),
],
),
);
@@ -93,52 +47,21 @@ class HomeDrawer extends StatelessWidget {
),
title: Text('Flutter 集录'),
children: <Widget>[
ListTile(
leading: Icon(
TolyIcon.icon_tag,
color: Theme.of(context).primaryColor,
),
title: Text('属性集录'),
trailing: _nextIcon(context),
onTap: () {
Navigator.of(context).pushNamed(Router.attr);
},
),
ListTile(
leading: Icon(
Icons.palette,
color: Theme.of(context).primaryColor,
),
title: Text('绘画集录'),
trailing: _nextIcon(context),
onTap: () => Navigator.of(context).pushNamed(Router.paint),
),
ListTile(
leading: Icon(
Icons.widgets,
color: Theme.of(context).primaryColor,
),
title: Text('布局集录'),
trailing: _nextIcon(context),
onTap: () {
Navigator.of(context).pushNamed(Router.layout);
},
),
ListTile(
leading: Icon(
TolyIcon.icon_bug,
color: Theme.of(context).primaryColor,
),
trailing: _nextIcon(context),
title: Text('bug/feature 集录'),
onTap: () {
Navigator.of(context).pushNamed(Router.bug);
},
),
_buildItem(context, TolyIcon.icon_tag,'属性集录',Router.attr),
_buildItem(context, Icons.palette,'绘画集录',Router.paint),
_buildItem(context, Icons.widgets,'布局集录',Router.layout),
_buildItem(context, TolyIcon.icon_bug,'bug/feature 集录',Router.bug),
],
);
Widget _nextIcon(BuildContext context) =>
Icon(Icons.chevron_right, color: Theme.of(context).primaryColor);
Widget _buildItem(
BuildContext context, IconData icon, String title, String linkTo) =>
ListTile(
leading: Icon(icon,
color: Theme.of(context).primaryColor,
),
title: Text(title),
trailing: Icon(Icons.chevron_right, color: Theme.of(context).primaryColor),
onTap: () => linkTo??Navigator.of(context).pushNamed(linkTo),
);
}

View File

@@ -31,8 +31,8 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
@override
Widget build(BuildContext context) {
super.build(context);
var color = context.bloc<HomeBloc>().state.homeColor;
// var color = BlocProvider.of<HomeBloc>(context).state.homeColor;
return Scaffold(
appBar: TolyAppBar(
selectIndex: Cons.tabColors.indexOf(color.value),
@@ -41,18 +41,20 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
),
body: Stack(
children: <Widget>[
BlocBuilder<GlobalBloc, GlobalState>(builder: (_, state) {
if (state.showBackGround) {
return Background();
}
return Container();
}),
BlocBuilder<GlobalBloc, GlobalState>(builder: _buildBackground),
BlocBuilder<HomeBloc, HomeState>(builder: _buildContent)
],
),
);
}
Widget _buildBackground(BuildContext context, GlobalState state) {
if (state.showBackGround) {
return Background();
}
return Container();
}
Widget _buildContent(BuildContext context, HomeState state) {
if (state is WidgetsLoaded) {
var items = state.widgets;
@@ -70,14 +72,11 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
return Container();
}
Widget _buildHomeItem(
WidgetModel model,
) =>
Widget _buildHomeItem(WidgetModel model) =>
BlocBuilder<GlobalBloc, GlobalState>(
condition: (p, c) => (p.itemStyleIndex != c.itemStyleIndex),
builder: (_, state) {
return
FeedbackWidget(
return FeedbackWidget(
duration: const Duration(milliseconds: 200),
onPressed: () => _toDetailPage(model),
child: HomeItemSupport.get(model, state.itemStyleIndex));
@@ -104,6 +103,6 @@ class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

View File

@@ -15,22 +15,19 @@ class TolyAppBar extends StatefulWidget implements PreferredSizeWidget {
TolyAppBar({this.onItemClick, this.preferredSize, this.selectIndex = 0});
}
const _kBorderRadius = BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
);
const _kTabTextStyle = TextStyle(color: Colors.white, shadows: [
const Shadow(color: Colors.black, offset: Offset(0.5, 0.5), blurRadius: 0.5)
]);
class _TolyAppBarState extends State<TolyAppBar>
with SingleTickerProviderStateMixin {
final borderRadius = const BorderRadius.only(
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
);
final tabTextStyle = const TextStyle(color: Colors.white, shadows: [
const Shadow(
color: Colors.black, offset: const Offset(0.5, 0.5), blurRadius: 0.5)
]);
double _width = 0;
int _selectIndex = 0;
double factor = 1.0;
List<int> colors = Cons.tabColors;
List info = Cons.tabs;
@@ -41,16 +38,22 @@ class _TolyAppBarState extends State<TolyAppBar>
void initState() {
_controller = AnimationController(
duration: const Duration(milliseconds: 300), vsync: this)
..addListener(() => setState(() => factor = _controller.value))
..addStatusListener((s) {
if (s == AnimationStatus.completed) {
setState(() {});
}
});
..addListener(_render)
..addStatusListener(_listenStatus);
_selectIndex = widget.selectIndex;
super.initState();
}
void _render() {
setState(() {});
}
void _listenStatus(AnimationStatus status) {
if (status == AnimationStatus.completed) {
setState(() {});
}
}
int get nextIndex => (_selectIndex + 1) % colors.length;
@override
@@ -60,28 +63,11 @@ class _TolyAppBarState extends State<TolyAppBar>
alignment: Alignment.center,
child: Flow(
delegate: TolyAppBarDelegate(
_selectIndex, factor, widget.preferredSize.height),
_selectIndex, _controller.value, widget.preferredSize.height),
children: [
...colors
.map((e) => GestureDetector(
onTap: () => _onTap(e),
child: Container(
alignment: const Alignment(0, 0.4),
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: _selectIndex == colors.indexOf(e)
? Colors.transparent
: Color(colors[_selectIndex]),
offset: Offset(1, 1),
blurRadius: 2)
], color: Color(e), borderRadius: borderRadius),
height: widget.preferredSize.height + 20,
width: _width,
child: Text(
info[colors.indexOf(e)],
style: tabTextStyle,
),
)))
onTap: () => _onTap(e), child: _buildChild(e)))
.toList(),
...colors.map((e) => Circle(
color: Color(e),
@@ -91,6 +77,24 @@ class _TolyAppBarState extends State<TolyAppBar>
);
}
Widget _buildChild(int color) => Container(
alignment: const Alignment(0, 0.4),
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: _selectIndex == colors.indexOf(color)
? Colors.transparent
: Color(colors[_selectIndex]),
offset: Offset(1, 1),
blurRadius: 2)
], color: Color(color), borderRadius: _kBorderRadius),
height: widget.preferredSize.height + 20,
width: _width,
child: Text(
info[colors.indexOf(color)],
style: _kTabTextStyle,
),
);
_onTap(int color) {
setState(() {
_controller.reset();
@@ -147,7 +151,5 @@ class TolyAppBarDelegate extends FlowDelegate {
}
@override
bool shouldRepaint(FlowDelegate oldDelegate) {
return true;
}
bool shouldRepaint(FlowDelegate oldDelegate) => true;
}

View File

@@ -17,7 +17,7 @@ import 'package:flutter_unit/views/pages/search/app_search_bar.dart';
import 'package:flutter_unit/views/pages/search/error_page.dart';
import 'package:flutter_unit/views/common/loading_page.dart';
import 'package:flutter_unit/views/pages/search/not_search_page.dart';
import 'package:flutter_unit/views/pages/search/start_filter.dart';
import 'package:flutter_unit/components/permanent/multi_chip_filter.dart';
import 'empty_page.dart';
@@ -41,7 +41,7 @@ class _SearchPageState extends State<SearchPage> {
slivers: <Widget>[
_buildSliverAppBar(),
SliverToBoxAdapter(child: _buildStarFilter()),
BlocBuilder<SearchBloc, SearchState>(builder: (_, state) => _buildBodyByState(state))
BlocBuilder<SearchBloc, SearchState>(builder:_buildBodyByState)
],
),
),
@@ -98,7 +98,7 @@ class _SearchPageState extends State<SearchPage> {
],
);
Widget _buildBodyByState(SearchState state) {
Widget _buildBodyByState(BuildContext context,SearchState state) {
if (state is SearchStateNoSearch) return SliverToBoxAdapter(child: NotSearchPage(),);
if (state is SearchStateLoading) return SliverToBoxAdapter(child: LoadingPage());
if (state is SearchStateError) return SliverToBoxAdapter(child: ErrorPage());

View File

@@ -1,113 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_unit/blocs/search/search_bloc.dart';
import 'package:flutter_unit/blocs/search/search_event.dart';
import 'package:flutter_unit/storage/dao/widget_dao.dart';
/// create by 张风捷特烈 on 2020-04-07
/// contact me by email 1981462002@qq.com
/// 说明:
typedef BoolWidgetBuilder = Widget Function(BuildContext context, bool selected);
class MultiChipFilter<T> extends StatefulWidget {
final List<T> data;
final BoolWidgetBuilder labelBuilder;
final IndexedWidgetBuilder avatarBuilder;
final Function(List<int>) onChange;
MultiChipFilter({@required this.data,@required this.labelBuilder,this.avatarBuilder,@required this.onChange});
@override
_MultiChipFilterState createState() => _MultiChipFilterState();
}
class _MultiChipFilterState<T> extends State<MultiChipFilter<T>> {
List<int> _selected = <int>[];
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: widget.data.map((e) =>
_buildChild(context,widget.data.indexOf(e))).toList(),
);
}
Widget _buildChild(BuildContext context,int index) {
bool selected = _selected.contains(index);
return FilterChip(
selectedColor: Colors.orange.withAlpha(55),
labelPadding: EdgeInsets.only(left: 5,right: 5),
selectedShadowColor: Colors.blue,
shadowColor: Colors.orangeAccent,
pressElevation: 5,
elevation: 3,
avatar: widget.avatarBuilder==null?null:widget.avatarBuilder(context,index),
label: widget.labelBuilder(context,selected),
selected: selected,
onSelected: (bool value) {
setState(() {
if (value) {
_selected.add(index);
} else {
_selected.removeWhere((i) => i == index);
}
if(widget.onChange!=null) widget.onChange(_selected);
});
},
);
}
}
//class StartFilter extends StatefulWidget {
// @override
// _StartFilterState createState() => _StartFilterState();
//}
//
//class _StartFilterState extends State<StartFilter> {
// List<int> data = [1,2,3,4,5];
// List<int> _selected = <int>[];
//
// @override
// Widget build(BuildContext context) {
// return Row(
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
// children: data.map((e) =>
// _buildChild(e)).toList(),
// );
// }
//
// Widget _buildChild(int e) {
// bool selected = _selected.contains(e);
// return FilterChip(
// selectedColor: Colors.orange.withAlpha(55),
// labelPadding: EdgeInsets.only(left: 5,right: 5),
// selectedShadowColor: Colors.blue,
// shadowColor: Colors.orangeAccent,
// pressElevation: 5,
// elevation: 3,
// avatar: CircleAvatar(child: Text((data.indexOf(e)+1).toString())),
// label: Icon(Icons.star,color: selected?Colors.blue:Colors.grey,size: 18,),
// selected: selected,
// onSelected: (bool value) {
// setState(() {
// if (value) {
// _selected.add(e);
// } else {
// _selected.removeWhere((name) => name == e);
// }
// var args = _selected.map((e)=>e).toList();
// if(args.length<5){
// args.addAll(List.generate(5-args.length, (e)=>-1));
// }
// BlocProvider.of<SearchBloc>(context)
// .add(EventTextChanged(args:SearchArgs(name: '',stars: args)));
// });
// },
// );
// }
//}

View File

@@ -22,7 +22,6 @@ class ItemStyleSettingPage extends StatelessWidget {
title: Text('item样式设置'),
),
body: BlocBuilder<GlobalBloc, GlobalState>(builder: (_, state) {
print('EventChangeItemStyle${state.itemStyleIndex}');
return _buildFontCell(context, state.itemStyleIndex);
}),
);

View File

@@ -1,18 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_unit/app/router.dart';
import 'package:flutter_unit/blocs/collect/collect_bloc.dart';
import 'package:flutter_unit/blocs/collect/collect_event.dart';
import 'package:flutter_unit/blocs/collect/collect_state.dart';
import 'package:flutter_unit/blocs/detail/detail_bloc.dart';
import 'package:flutter_unit/blocs/detail/detail_event.dart';
import 'package:flutter_unit/components/permanent/animated_text.dart';
import 'package:flutter_unit/components/permanent/circle_image.dart';
import 'package:flutter_unit/model/widget_model.dart';
import 'package:flutter_unit/views/items/collect_widget_list_item.dart';
import 'package:flutter_unit/views/items/techno_widget_list_item.dart';
import '../../common/empty_page.dart';
class AttrUnitPage extends StatelessWidget {
final info = '【Flutter属性集录】是Unit项目计划的第二阶段的功能之一。'

View File

@@ -1,20 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_unit/app/router.dart';
import 'package:flutter_unit/blocs/collect/collect_bloc.dart';
import 'package:flutter_unit/blocs/collect/collect_event.dart';
import 'package:flutter_unit/blocs/collect/collect_state.dart';
import 'package:flutter_unit/blocs/detail/detail_bloc.dart';
import 'package:flutter_unit/blocs/detail/detail_event.dart';
import 'package:flutter_unit/components/permanent/animated_text.dart';
import 'package:flutter_unit/components/permanent/circle_image.dart';
import 'package:flutter_unit/model/widget_model.dart';
import 'package:flutter_unit/views/items/collect_widget_list_item.dart';
import 'package:flutter_unit/views/items/techno_widget_list_item.dart';
import '../../common/empty_page.dart';
class BugUnitPage extends StatelessWidget {
final info = '【Flutter异常集录】是Unit项目计划的第二阶段的功能之一。'

View File

@@ -1,20 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_unit/app/router.dart';
import 'package:flutter_unit/blocs/collect/collect_bloc.dart';
import 'package:flutter_unit/blocs/collect/collect_event.dart';
import 'package:flutter_unit/blocs/collect/collect_state.dart';
import 'package:flutter_unit/blocs/detail/detail_bloc.dart';
import 'package:flutter_unit/blocs/detail/detail_event.dart';
import 'package:flutter_unit/components/permanent/animated_text.dart';
import 'package:flutter_unit/components/permanent/circle_image.dart';
import 'package:flutter_unit/model/widget_model.dart';
import 'package:flutter_unit/views/items/collect_widget_list_item.dart';
import 'package:flutter_unit/views/items/techno_widget_list_item.dart';
import '../../common/empty_page.dart';
class LayoutUnitPage extends StatelessWidget {
final info = '【Flutter布局集录】是Unit项目计划的第二阶段的功能之一。'

View File

@@ -1,20 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_unit/app/router.dart';
import 'package:flutter_unit/blocs/collect/collect_bloc.dart';
import 'package:flutter_unit/blocs/collect/collect_event.dart';
import 'package:flutter_unit/blocs/collect/collect_state.dart';
import 'package:flutter_unit/blocs/detail/detail_bloc.dart';
import 'package:flutter_unit/blocs/detail/detail_event.dart';
import 'package:flutter_unit/components/permanent/animated_text.dart';
import 'package:flutter_unit/components/permanent/circle_image.dart';
import 'package:flutter_unit/model/widget_model.dart';
import 'package:flutter_unit/views/items/collect_widget_list_item.dart';
import 'package:flutter_unit/views/items/techno_widget_list_item.dart';
import '../../common/empty_page.dart';
class PaintUnitPage extends StatelessWidget {
final info = '【Flutter绘制集录】是Unit项目计划的第二阶段的功能之一。'