reason

?

......@@ -3,7 +3,7 @@
// ignore_for_file: prefer_single_quotes
// This file is automatically generated. DO NOT EDIT, all your changes would be lost.
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/models/user_entity.dart';
JsonConvert jsonConvert = JsonConvert();
......
import 'package:one_poem/generated/json/base/json_convert_content.dart';
import 'package:one_poem/goods/models/goods_sort_entity.dart';
GoodsSortEntity $GoodsSortEntityFromJson(Map<String, dynamic> json) {
final GoodsSortEntity goodsSortEntity = GoodsSortEntity();
final String? id = jsonConvert.convert<String>(json['id']);
if (id != null) {
goodsSortEntity.id = id;
}
final String? name = jsonConvert.convert<String>(json['name']);
if (name != null) {
goodsSortEntity.name = name;
}
return goodsSortEntity;
}
Map<String, dynamic> $GoodsSortEntityToJson(GoodsSortEntity entity) {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = entity.id;
data['name'] = entity.name;
return data;
}
\ No newline at end of file
import 'package:one_poem/generated/json/base/json_convert_content.dart';
import 'package:one_poem/account/models/user_entity.dart';
UserEntity $UserEntityFromJson(Map<String, dynamic> json) {
final UserEntity userEntity = UserEntity();
final int? id = jsonConvert.convert<int>(json['id']);
if (id != null) {
userEntity.id = id;
}
final String? name = jsonConvert.convert<String>(json['name']);
if (name != null) {
userEntity.name = name;
}
final String? avatar = jsonConvert.convert<String>(json['avatar']);
if (avatar != null) {
userEntity.avatar = avatar;
}
return userEntity;
}
Map<String, dynamic> $UserEntityToJson(UserEntity entity) {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = entity.id;
data['name'] = entity.name;
data['avatar'] = entity.avatar;
return data;
}
\ No newline at end of file
import 'dart:convert';
import 'package:one_poem/generated/json/base/json_field.dart';
import 'package:one_poem/generated/json/friend_entity.g.dart';
@JsonSerializable()
class FriendEntity {
late List<FriendData> data;
FriendEntity();
factory FriendEntity.fromJson(Map<String, dynamic> json) => $FriendEntityFromJson(json);
Map<String, dynamic> toJson() => $FriendEntityToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
@JsonSerializable()
class FriendData {
late String head;
late String name;
late String desc;
late List<String> pics;
late String time;
FriendData();
factory FriendData.fromJson(Map<String, dynamic> json) => $FriendDataFromJson(json);
Map<String, dynamic> toJson() => $FriendDataToJson(this);
@override
String toString() {
return jsonEncode(this);
}
}
\ No newline at end of file
{
"data" : [
{
"head" : "logo.jpg",
"name" : "Sunnytu",
"desc" : "早上好中国的朋友们。宝宝们今天也很早开始一天。我好困\uD83D\uDCA4今天也我会努力",
"pics" : ["banner.jpg"],
"time" : "刚刚"
},
{
"head" : "wyf.jpg",
"name" : "吴亦凡",
"desc" : "作为歌手和音乐制作人,他才华出众; 作为演员和时尚领袖,他光芒闪耀。他有风格,有态度,更有魅力。今天,吴亦凡 @Mr_凡先生 成为首位兰蔻亚太区品牌代言人,为品牌注入更多奢华摩登的新活力,并呈现护肤、彩妆与香水的美丽精彩。不同\"\"响的幸福旅程即将开始!你,准备好了吗? \u200B\u200B\u200B\u200B",
"pics" : ["wyf1.jpg" ,"wyf2.jpg" , "wyf3.jpg"],
"time" : "3分钟前"
},
{
"head" : "lh.jpg",
"name" : "鹿晗",
"desc" : "海淀素材库的密码终于想起来了[笑cry][笑cry][笑cry] \u200B\u200B\u200B\u200B\n",
"pics" : ["lh1.jpg" ,"lh2.jpg" , "lh3.jpg" , "lh4.jpg"],
"time" : "20分钟前"
},
{
"head" : "cxk.jpg",
"name" : "🏀蔡徐坤🏀",
"desc" : "老哥们,看我篮球🏀打的好不好,赶紧点个赞👍",
"pics" : ["cxk1.jpg" ,"cxk2.jpg" ],
"time" : "1小时前"
},
{
"head" : "zyx.jpg",
"name" : "张艺兴",
"desc" : "透过所有非凡成就,预见更为璀璨的未来。\n歌手、音乐制作人、演员张艺兴@努力努力再努力x 从未停下前进的脚步,从亚洲流行乐坛引领M-POP走向世界。\n《VMAN》九月电子刊带你走进封面人物张艺兴的世界,即“兴”而为,涌动新潮。\n《VMAN》官网独家专访",
"pics" : ["zyx1.jpg" ,"zyx2.jpg" , "zyx3.jpg" , "zyx4.jpg","zyx5.jpg" ,"zyx6.jpg" , "zyx7.jpg" , "zyx8.jpg" , "zyx9.jpg"],
"time" : "2小时前"
},
{
"head" : "hsf.jpg",
"name" : "黄诗扶",
"desc" : "喝完大酒撑条船,说今生不靠岸。\n去天涯海角浪个遍,失意当尝鲜。\n神仙掐指算,此去少圆满。\n得来失,聚了散,千万莫求全。",
"pics" : ["hsf1.jpg" ,"hsf2.jpg"],
"time" : "3小时前"
},
{
"head" : "logo.jpg",
"name" : "Sunnytu",
"desc" : "早上好中国的朋友们。宝宝们今天也很早开始一天。我好困\uD83D\uDCA4今天也我会努力",
"pics" : ["banner.jpg"],
"time" : "刚刚"
},
{
"head" : "wyf.jpg",
"name" : "吴亦凡",
"desc" : "作为歌手和音乐制作人,他才华出众; 作为演员和时尚领袖,他光芒闪耀。他有风格,有态度,更有魅力。今天,吴亦凡 @Mr_凡先生 成为首位兰蔻亚太区品牌代言人,为品牌注入更多奢华摩登的新活力,并呈现护肤、彩妆与香水的美丽精彩。不同\"\"响的幸福旅程即将开始!你,准备好了吗? \u200B\u200B\u200B\u200B",
"pics" : ["wyf1.jpg" ,"wyf2.jpg" , "wyf3.jpg"],
"time" : "3分钟前"
},
{
"head" : "lh.jpg",
"name" : "鹿晗",
"desc" : "海淀素材库的密码终于想起来了[笑cry][笑cry][笑cry] \u200B\u200B\u200B\u200B\n",
"pics" : ["lh1.jpg" ,"lh2.jpg" , "lh3.jpg" , "lh4.jpg"],
"time" : "20分钟前"
},
{
"head" : "cxk.jpg",
"name" : "🏀蔡徐坤🏀",
"desc" : "老哥们,看我篮球🏀打的好不好,赶紧点个赞👍",
"pics" : ["cxk1.jpg" ,"cxk2.jpg" ],
"time" : "1小时前"
},
{
"head" : "zyx.jpg",
"name" : "张艺兴",
"desc" : "透过所有非凡成就,预见更为璀璨的未来。\n歌手、音乐制作人、演员张艺兴@努力努力再努力x 从未停下前进的脚步,从亚洲流行乐坛引领M-POP走向世界。\n《VMAN》九月电子刊带你走进封面人物张艺兴的世界,即“兴”而为,涌动新潮。\n《VMAN》官网独家专访",
"pics" : ["zyx1.jpg" ,"zyx2.jpg" , "zyx3.jpg" , "zyx4.jpg","zyx5.jpg" ,"zyx6.jpg" , "zyx7.jpg" , "zyx8.jpg" , "zyx9.jpg"],
"time" : "2小时前"
},
{
"head" : "hsf.jpg",
"name" : "黄诗扶",
"desc" : "喝完大酒撑条船,说今生不靠岸。\n去天涯海角浪个遍,失意当尝鲜。\n神仙掐指算,此去少圆满。\n得来失,聚了散,千万莫求全。",
"pics" : ["hsf1.jpg" ,"hsf2.jpg"],
"time" : "3小时前"
},
{
"head" : "logo.jpg",
"name" : "Sunnytu",
"desc" : "早上好中国的朋友们。宝宝们今天也很早开始一天。我好困\uD83D\uDCA4今天也我会努力",
"pics" : ["banner.jpg"],
"time" : "刚刚"
},
{
"head" : "wyf.jpg",
"name" : "吴亦凡",
"desc" : "作为歌手和音乐制作人,他才华出众; 作为演员和时尚领袖,他光芒闪耀。他有风格,有态度,更有魅力。今天,吴亦凡 @Mr_凡先生 成为首位兰蔻亚太区品牌代言人,为品牌注入更多奢华摩登的新活力,并呈现护肤、彩妆与香水的美丽精彩。不同\"\"响的幸福旅程即将开始!你,准备好了吗? \u200B\u200B\u200B\u200B",
"pics" : ["wyf1.jpg" ,"wyf2.jpg" , "wyf3.jpg"],
"time" : "3分钟前"
},
{
"head" : "lh.jpg",
"name" : "鹿晗",
"desc" : "海淀素材库的密码终于想起来了[笑cry][笑cry][笑cry] \u200B\u200B\u200B\u200B\n",
"pics" : ["lh1.jpg" ,"lh2.jpg" , "lh3.jpg" , "lh4.jpg"],
"time" : "20分钟前"
},
{
"head" : "cxk.jpg",
"name" : "🏀蔡徐坤🏀",
"desc" : "老哥们,看我篮球🏀打的好不好,赶紧点个赞👍",
"pics" : ["cxk1.jpg" ,"cxk2.jpg" ],
"time" : "1小时前"
},
{
"head" : "zyx.jpg",
"name" : "张艺兴",
"desc" : "透过所有非凡成就,预见更为璀璨的未来。\n歌手、音乐制作人、演员张艺兴@努力努力再努力x 从未停下前进的脚步,从亚洲流行乐坛引领M-POP走向世界。\n《VMAN》九月电子刊带你走进封面人物张艺兴的世界,即“兴”而为,涌动新潮。\n《VMAN》官网独家专访",
"pics" : ["zyx1.jpg" ,"zyx2.jpg" , "zyx3.jpg" , "zyx4.jpg","zyx5.jpg" ,"zyx6.jpg" , "zyx7.jpg" , "zyx8.jpg" , "zyx9.jpg"],
"time" : "2小时前"
},
{
"head" : "hsf.jpg",
"name" : "黄诗扶",
"desc" : "喝完大酒撑条船,说今生不靠岸。\n去天涯海角浪个遍,失意当尝鲜。\n神仙掐指算,此去少圆满。\n得来失,聚了散,千万莫求全。",
"pics" : ["hsf1.jpg" ,"hsf2.jpg"],
"time" : "3小时前"
},
{
"head" : "logo.jpg",
"name" : "Sunnytu",
"desc" : "早上好中国的朋友们。宝宝们今天也很早开始一天。我好困\uD83D\uDCA4今天也我会努力",
"pics" : ["banner.jpg"],
"time" : "刚刚"
},
{
"head" : "wyf.jpg",
"name" : "吴亦凡",
"desc" : "作为歌手和音乐制作人,他才华出众; 作为演员和时尚领袖,他光芒闪耀。他有风格,有态度,更有魅力。今天,吴亦凡 @Mr_凡先生 成为首位兰蔻亚太区品牌代言人,为品牌注入更多奢华摩登的新活力,并呈现护肤、彩妆与香水的美丽精彩。不同\"\"响的幸福旅程即将开始!你,准备好了吗? \u200B\u200B\u200B\u200B",
"pics" : ["wyf1.jpg" ,"wyf2.jpg" , "wyf3.jpg"],
"time" : "3分钟前"
},
{
"head" : "lh.jpg",
"name" : "鹿晗",
"desc" : "海淀素材库的密码终于想起来了[笑cry][笑cry][笑cry] \u200B\u200B\u200B\u200B\n",
"pics" : ["lh1.jpg" ,"lh2.jpg" , "lh3.jpg" , "lh4.jpg"],
"time" : "20分钟前"
},
{
"head" : "cxk.jpg",
"name" : "🏀蔡徐坤🏀",
"desc" : "老哥们,看我篮球🏀打的好不好,赶紧点个赞👍",
"pics" : ["cxk1.jpg" ,"cxk2.jpg" ],
"time" : "1小时前"
},
{
"head" : "zyx.jpg",
"name" : "张艺兴",
"desc" : "透过所有非凡成就,预见更为璀璨的未来。\n歌手、音乐制作人、演员张艺兴@努力努力再努力x 从未停下前进的脚步,从亚洲流行乐坛引领M-POP走向世界。\n《VMAN》九月电子刊带你走进封面人物张艺兴的世界,即“兴”而为,涌动新潮。\n《VMAN》官网独家专访",
"pics" : ["zyx1.jpg" ,"zyx2.jpg" , "zyx3.jpg" , "zyx4.jpg","zyx5.jpg" ,"zyx6.jpg" , "zyx7.jpg" , "zyx8.jpg" , "zyx9.jpg"],
"time" : "2小时前"
},
{
"head" : "hsf.jpg",
"name" : "黄诗扶",
"desc" : "喝完大酒撑条船,说今生不靠岸。\n去天涯海角浪个遍,失意当尝鲜。\n神仙掐指算,此去少圆满。\n得来失,聚了散,千万莫求全。",
"pics" : ["hsf1.jpg" ,"hsf2.jpg"],
"time" : "3小时前"
}
]
}
\ No newline at end of file
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/models/user_entity.dart';
import 'package:one_poem/mvp/mvps.dart';
abstract class ShopIMvpView implements IMvpView {
......
import 'package:flutter/material.dart';
import 'package:one_poem/account/account_router.dart';
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/models/user_entity.dart';
import 'package:one_poem/mvp/base_page.dart';
import 'package:one_poem/res/resources.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
......
import 'package:flutter/material.dart';
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/models/user_entity.dart';
import 'package:one_poem/mvp/base_page_presenter.dart';
import 'package:one_poem/net/dio_utils.dart';
import 'package:one_poem/net/http_api.dart';
......
import 'package:flutter/material.dart';
import 'package:one_poem/account/models/user_entity.dart';
import 'package:one_poem/models/user_entity.dart';
class UserProvider extends ChangeNotifier {
......
class TimelineItemEntity {
TimelineItemEntity({required this.icon, required this.title, required this.type});
TimelineItemEntity.fromJson(Map<String, dynamic> json) {
icon = json['icon'] as String;
title = json['title'] as String;
type = json['type'] as int;
}
late String icon;
late String title;
late int type;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['icon'] = icon;
data['title'] = title;
data['type'] = type;
return data;
}
}
import 'package:flutter/material.dart';
import 'package:one_poem/res/constant.dart';
import 'package:one_poem/timeline/models/timeline_item_entity.dart';
import 'package:one_poem/timeline/provider/timeline_page_provider.dart';
import 'package:one_poem/timeline/widgets/timeline_delete_bottom_sheet.dart';
import 'package:one_poem/timeline/widgets/timeline_item.dart';
import 'package:one_poem/util/toast_utils.dart';
import 'package:one_poem/widgets/my_refresh_list.dart';
import 'package:one_poem/widgets/state_layout.dart';
import 'package:provider/provider.dart';
class TimelineListPage extends StatefulWidget {
const TimelineListPage({Key? key, required this.index}) : super(key: key);
final int index;
@override
_TimelineListPageState createState() => _TimelineListPageState();
}
class _TimelineListPageState extends State<TimelineListPage>
with
AutomaticKeepAliveClientMixin<TimelineListPage>,
SingleTickerProviderStateMixin {
int _selectIndex = -1;
late Animation<double> _animation;
late AnimationController _controller;
List<TimelineItemEntity> _list = [];
AnimationStatus _animationStatus = AnimationStatus.dismissed;
@override
void initState() {
super.initState();
// 初始化动画控制
_controller = AnimationController(
duration: const Duration(milliseconds: 450), vsync: this);
// 动画曲线
final _curvedAnimation =
CurvedAnimation(parent: _controller, curve: Curves.easeOutSine);
_animation = Tween(begin: 0.0, end: 1.1).animate(_curvedAnimation)
..addStatusListener((status) {
_animationStatus = status;
});
//Item数量
_maxPage = widget.index == 0 ? 1 : (widget.index == 1 ? 2 : 3);
_onRefresh();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
final List<String> _imgList = [
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3130502839,1206722360&fm=26&gp=0.jpg',
if (Constant.isDriverTest)
'https://img2.baidu.com/it/u=3994371075,170872697&fm=26&fmt=auto&gp=0.jpg'
else
'https://xxx', // 可以使用一张无效链接,触发缺省、异常显示图片
'https://img0.baidu.com/it/u=4049693009,2577412121&fm=224&fmt=auto&gp=0.jpg',
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3659255919,3211745976&fm=26&gp=0.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2085939314,235211629&fm=26&gp=0.jpg',
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3659255919,3211745976&fm=26&gp=0.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2085939314,235211629&fm=26&gp=0.jpg',
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3659255919,3211745976&fm=26&gp=0.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2085939314,235211629&fm=26&gp=0.jpg',
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3659255919,3211745976&fm=26&gp=0.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2085939314,235211629&fm=26&gp=0.jpg',
'https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=3659255919,3211745976&fm=26&gp=0.jpg',
'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2085939314,235211629&fm=26&gp=0.jpg',
];
Future _onRefresh() async {
await Future.delayed(const Duration(seconds: 2), () {
setState(() {
_page = 1;
_list = List.generate(
widget.index == 0 ? 3 : 10,
(i) => TimelineItemEntity(
icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3));
});
_setTimelineCount(_list.length);
});
}
Future _loadMore() async {
await Future.delayed(const Duration(seconds: 2), () {
setState(() {
_list.addAll(List.generate(
10,
(i) => TimelineItemEntity(
icon: _imgList[i % 6], title: '八月十五中秋月饼礼盒', type: i % 3)));
_page++;
});
_setTimelineCount(_list.length);
});
}
void _setTimelineCount(int count) {
/// 与上方等价,provider 4.1.0添加的拓展方法
context.read<TimelinePageProvider>().setTimelineCount(count);
}
int _page = 1;
late int _maxPage;
StateType _stateType = StateType.loading;
@override
Widget build(BuildContext context) {
super.build(context);
return DeerListView(
itemCount: _list.length,
stateType: _stateType,
onRefresh: _onRefresh,
loadMore: _loadMore,
hasMore: _page < _maxPage,
itemBuilder: (_, index) {
final String heroTag = 'goodsImg${widget.index}-$index';
return TimelineItem(
index: index,
heroTag: heroTag,
selectIndex: _selectIndex,
item: _list[index],
animation: _animation,
onTapMenu: () {
/// 点击其他item时,重置状态
if (_selectIndex != index) {
_animationStatus = AnimationStatus.dismissed;
}
/// 避免动画中重复执行
if (_animationStatus == AnimationStatus.dismissed) {
// 开始执行动画
_controller.forward(from: 0.0);
}
setState(() {
_selectIndex = index;
});
},
onTapMenuClose: () {
if (_animationStatus == AnimationStatus.completed) {
_controller.reverse(from: 1.1);
}
_selectIndex = -1;
},
onTapEdit: () {
setState(() {
_selectIndex = -1;
});
},
onTapOperation: () {
Toast.show('下架');
},
onTapDelete: () {
_controller.reverse(from: 1.1);
_selectIndex = -1;
_showDeleteBottomSheet(index);
},
);
});
}
@override
bool get wantKeepAlive => true;
void _showDeleteBottomSheet(int index) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return TimelineDeleteBottomSheet(
onTapDelete: () {
setState(() {
_list.removeAt(index);
if (_list.isEmpty) {
_stateType = StateType.goods;
}
});
_setTimelineCount(_list.length);
},
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:one_poem/timeline/provider/timeline_page_provider.dart';
import 'package:one_poem/widgets/my_app_bar.dart';
import 'package:provider/provider.dart';
import 'dart:convert';
import 'timeline_list_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:one_poem/timeline/widgets/friend_cell.dart';
import 'package:one_poem/timeline/widgets/header_view.dart';
import 'package:one_poem/models/friend_entity.dart';
class TimelinesPage extends StatefulWidget {
const TimelinesPage({Key? key}) : super(key: key);
......@@ -12,48 +14,74 @@ class TimelinesPage extends StatefulWidget {
_TimelinesPageState createState() => _TimelinesPageState();
}
class _TimelinesPageState extends State<TimelinesPage>
with SingleTickerProviderStateMixin, AutomaticKeepAliveClientMixin {
final PageController _pageController = PageController();
class _TimelinesPageState extends State<TimelinesPage>{
final ScrollController _scrollController = ScrollController();
double _opacity = 0;
final GlobalKey _bodyKey = GlobalKey();
FriendEntity _friendmodelEntity = FriendEntity();
TimelinePageProvider provider = TimelinePageProvider();
Future<String> loadAsset() async {
return await rootBundle.loadString('lib/res/timeline/Data.json');
}
@override
void initState() {
super.initState();
loadAsset().then((value){
var json = jsonDecode(value);
_friendmodelEntity = FriendEntity.fromJson(json);
setState(() {});
});
_scrollController.addListener(() {
double alph = _scrollController.offset/200;
if (alph < 0) {
alph = 0;
} else if (alph > 1) {
alph = 1;
}
setState(() {
_opacity = alph;
});
});
}
@override
void dispose() {
super.dispose();
Widget _mainListViewBuidler(BuildContext context , int index) {
return FriendCell(model: _friendmodelEntity.data![index],);
}
@override
Widget build(BuildContext context) {
super.build(context);
return ChangeNotifierProvider<TimelinePageProvider>(
create: (_) => provider,
child: Scaffold(
appBar: const MyAppBar(),
body: Column(
key: _bodyKey,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
child: PageView.builder(
key: const Key('pageView'),
controller: _pageController,
itemBuilder: (_, int index) =>
TimelineListPage(index: index)),
)
],
),
return Scaffold(
body: Stack(
children: <Widget>[
ListView(
padding: const EdgeInsets.only(top: 0),
controller: _scrollController,
children: <Widget>[
const HeaderView(),
ListView.builder(padding: const EdgeInsets.only(top: 0), itemBuilder: _mainListViewBuidler , itemCount: _friendmodelEntity.data!.length, shrinkWrap: true, physics:NeverScrollableScrollPhysics(),)
],
),
Opacity(
opacity: _opacity,
child: const CupertinoNavigationBar(
middle: Text("朋友圈"),
),
)
],
),
);
}
@override
bool get wantKeepAlive => true;
}
......
import 'package:flutter/material.dart';
class TimelinePageProvider extends ChangeNotifier {
/// Tab的下标
int _index = 0;
int get index => _index;
/// 商品数量
final List<int> _timelineCountList = [0, 0, 0];
List<int> get timelineCountList => _timelineCountList;
/// 选中商品分类下标
int _sortIndex = 0;
int get sortIndex => _sortIndex;
void setSortIndex(int sortIndex) {
_sortIndex = sortIndex;
notifyListeners();
}
void setIndex(int index) {
_index = index;
notifyListeners();
}
void setTimelineCount(int count) {
_timelineCountList[index] = count;
notifyListeners();
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:one_poem/models/friend_entity.dart';
class FriendCell extends StatefulWidget {
FriendData model;
FriendCell({Key? key, required this.model}) : super(key: key);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return FriendCellState();
}
}
class FriendCellState extends State<FriendCell> {
Widget? makePictureCount(List<String> pics) {
if (pics.length == 1) {
return Container(
margin: EdgeInsets.fromLTRB(0, 10, 50, 10),
child: Image.asset("lib/Resourse/" + pics[0] , fit: BoxFit.fill,),
);
} else if (pics.length == 4 || pics.length == 2) {
return Container(
margin: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Wrap(
spacing: 5,
runSpacing: 5,
alignment: WrapAlignment.start,
children: pics.map((p) => Image.asset("lib/Resourse/" + p , width: 100 , height: 100 , fit: BoxFit.cover,)).toList()
)
);
} else if (pics.length == 3 || pics.length > 4) {
return Container(
margin: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Wrap(
spacing: 5,
runSpacing: 5,
alignment: WrapAlignment.start,
children: pics.map((p) => Image.asset("lib/Resourse/" + p , width: 70 , height: 70 , fit: BoxFit.cover,)).toList()
)
);
}
}
double _width = 0;
bool _isShow = false;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
color: Color(0XFFFEFFFE),
child: Column(
children: <Widget>[
Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 40,
height: 40,
margin: EdgeInsets.fromLTRB(15, 20, 15, 0),
child: ClipRRect(
child: Image.asset("lib/Resourse/" + widget.model.head , fit: BoxFit.fill,),
borderRadius: BorderRadius.circular(5),
),
),
Expanded(
child: Container(
margin: EdgeInsets.fromLTRB(0, 20, 70, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(widget.model.name , style: TextStyle(fontSize: 17 , color: Color(0XFF566B94) , fontWeight: FontWeight.w500),),
SizedBox(height: 5,),
Text(widget.model.desc , style: TextStyle(fontSize: 15),),
makePictureCount(widget.model.pics)!,
],
)
)
)
],
),
Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(left: 70),
child: Text(widget.model.time , style: TextStyle(fontSize: 12 , color: Color(0XFFB2B2B2)),),
),
),
Expanded(
flex: 2,
child: Container(
margin: EdgeInsets.only(right: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
AnimatedContainer(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Color(0XFF4C5154)
),
duration: Duration(milliseconds: 100),
width: _width,
height: 30,
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
Expanded(
flex : 1 ,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.favorite_border , color: Colors.white, size: 15,),
SizedBox(width: 5,),
InkWell(
onTap: (){
setState(() {
_starCount ++ ;
isShow();
});
},
child: Text("赞" ,style: TextStyle(color: Colors.white , fontSize: 12),)
)
],
)
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.sms , color: Colors.white, size: 15,),
SizedBox(width: 5,),
InkWell(
onTap: () {
setState(() {
_talkCount ++ ;
isShow();
});
},
child: Text("评论" ,style: TextStyle(color: Colors.white , fontSize: 12),)
)
],
)
)
],
)
),
SizedBox(width: 10,),
InkWell(
onTap: (){
isShow();
},
child: Image.asset("lib/Resourse/button.png" , width: 22, height: 18,)
),
],
),
)
)
],
),
Offstage(
offstage: _starCount == 0 ? true : false,
child: Container(
constraints: BoxConstraints(
minWidth: double.infinity
),
margin: EdgeInsets.fromLTRB(70, 10, 15, 0),
padding: EdgeInsets.all(5),
color: Color(0XFFF3F3F5),
child: Wrap(
alignment: WrapAlignment.start,
runSpacing: 5,
spacing: 5,
children:likeView(_starCount)
),
),
),
Offstage(
offstage: _talkCount == 0 ? true : false,
child: Container(
constraints: BoxConstraints(
minWidth: double.infinity
),
margin: EdgeInsets.fromLTRB(70, 0, 15, 0),
padding: EdgeInsets.all(5),
color: Color(0XFFF3F3F5),
child: Wrap(
alignment: WrapAlignment.start,
runSpacing: 5,
spacing: 5,
children:talkView(_talkCount)
),
),
),
SizedBox(height: 10,),
Container(height: 0.5, width: double.infinity, color: Colors.black26,)
],
)
);
}
void isShow() {
_isShow = !_isShow;
setState(() {
_width = _isShow ? 120 : 0;
});
}
var _starCount = 0;
var _talkCount = 0;
List<Widget> likeView(int count) {
List<Widget> result = [];
for (int i =0 ; i< count ; i ++) {
result.add(Container(
width: 70,
child: Row(
children: <Widget>[
Icon(Icons.favorite_border , size: 13, color: Color(0XFF566B94),),
SizedBox(width: 5,),
Text("sunnytu" ,style: TextStyle(color: Color(0XFF566B94) , fontSize: 15 , fontWeight: FontWeight.w500),)
],
),
));
}
return result;
}
List<Widget> talkView(int count) {
List<Widget> result = [];
for (int i =0 ; i< count ; i ++) {
result.add(Container(
child: Row(
children: <Widget>[
Expanded(
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "sunnytu:",
style: TextStyle(fontSize: 15 ,fontWeight: FontWeight.w500 , color: Color(0XFF566B94))
),
TextSpan(
text: "66666",
style: TextStyle(fontSize: 14),
)
]
),
textAlign: TextAlign.start,
)
),
],
),
));
}
return result;
}
}
\ No newline at end of file
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HeaderView extends StatelessWidget {
const HeaderView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
height: 320,
color: const Color(0XFFFEFFFE),
child: Stack(
children: <Widget>[
Positioned(
left: 0,
right: 0,
top: 0,
bottom: 40,
child: Image.asset("lib/Resourse/banner.jpg" , fit: BoxFit.fill,)
),
Positioned(
right: 15,
bottom: 20,
child: SizedBox(
width: 60,
height: 60,
child: ClipRRect(borderRadius:BorderRadius.circular(8) , child: Image.asset("lib/Resourse/logo.jpg" , fit: BoxFit.cover,))
),
),
const Positioned(
right: 100,
bottom: 50,
child: Text("sunnytu" , style: TextStyle(fontSize: 20 , fontWeight: FontWeight.w600 , color: Colors.white , shadows:[
Shadow(color: Colors.black, offset: Offset(1, 1))
] ),),
)
],
),
);
}
}
\ No newline at end of file
import 'dart:math';
import 'package:flutter/material.dart';
//https://github.com/alibaba/flutter-go/blob/master/lib/views/fourth_page/page_reveal.dart
class MenuReveal extends StatelessWidget {
const MenuReveal({
Key? key,
required this.revealPercent,
required this.child
}): super(key: key);
final double revealPercent;
final Widget child;
@override
Widget build(BuildContext context) {
return ClipOval(
clipper: CircleRevealClipper(revealPercent),
child: child,
);
}
}
class CircleRevealClipper extends CustomClipper<Rect> {
CircleRevealClipper(this.revealPercent);
final double revealPercent;
@override
Rect getClip(Size size) {
// 右上角的点击点为圆心
final Offset epicenter = Offset(size.width - 25.0, 25.0);
final double theta = atan(epicenter.dy / epicenter.dx);
final double distanceToCorner = (epicenter.dy) / sin(theta);
final double radius = distanceToCorner * revealPercent;
final double diameter = 2 * radius;
return Rect.fromLTWH(epicenter.dx - radius, epicenter.dy - radius, diameter, diameter);
}
@override
bool shouldReclip(CustomClipper<Rect> oldClipper) {
return true;
}
}
import 'package:flutter/material.dart';
import 'package:one_poem/res/resources.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
import 'package:one_poem/widgets/my_button.dart';
/// design/4商品/index.html#artboard2
class TimelineDeleteBottomSheet extends StatelessWidget {
const TimelineDeleteBottomSheet({
Key? key,
required this.onTapDelete,
}): super(key: key);
final VoidCallback onTapDelete;
@override
Widget build(BuildContext context) {
return Material(
child: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 52.0,
child: Center(
child: Text(
'是否确认删除,防止错误操作',
style: TextStyles.textSize16,
),
),
),
Gaps.line,
MyButton(
minHeight: 54.0,
textColor: Theme.of(context).errorColor,
text: '确认删除',
backgroundColor: Colors.transparent,
onPressed: () {
NavigatorUtils.goBack(context);
onTapDelete();
},
),
Gaps.line,
MyButton(
minHeight: 54.0,
textColor: Colours.text_gray,
text: '取消',
backgroundColor: Colors.transparent,
onPressed: () {
NavigatorUtils.goBack(context);
},
),
],
),
),
);
}
}
import 'package:common_utils/common_utils.dart';
import 'package:flutter/material.dart';
import 'package:one_poem/res/resources.dart';
import 'package:one_poem/timeline/models/timeline_item_entity.dart';
import 'package:one_poem/util/device_utils.dart';
import 'package:one_poem/util/other_utils.dart';
import 'package:one_poem/util/theme_utils.dart';
import 'package:one_poem/widgets/load_image.dart';
import 'package:one_poem/widgets/my_button.dart';
import 'menu_reveal.dart';
/// design/4商品/index.html#artboard1
class TimelineItem extends StatelessWidget {
const TimelineItem({
Key? key,
required this.item,
required this.index,
required this.selectIndex,
required this.onTapMenu,
required this.onTapEdit,
required this.onTapOperation,
required this.onTapDelete,
required this.onTapMenuClose,
required this.animation,
required this.heroTag,
}): super(key: key);
final TimelineItemEntity item;
final int index;
final int selectIndex;
final VoidCallback onTapMenu;
final VoidCallback onTapEdit;
final VoidCallback onTapOperation;
final VoidCallback onTapDelete;
final VoidCallback onTapMenuClose;
final Animation<double> animation;
final String heroTag;
@override
Widget build(BuildContext context) {
final Row child = Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ExcludeSemantics(
child: Hero(
tag: heroTag,
child: LoadImage(item.icon, width: 72.0, height: 72.0),
),
),
Gaps.hGap8,
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
item.type % 3 != 0 ? '八月十五中秋月饼礼盒' : '八月十五中秋月饼礼盒八月十五中秋月饼礼盒',
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
Gaps.vGap4,
Row(
children: <Widget>[
Visibility(
// 默认为占位替换,类似于gone
visible: item.type % 3 == 0,
child: _GoodsItemTag(
text: '立减',
color: Theme.of(context).errorColor,
),
),
Opacity(
// 修改透明度实现隐藏,类似于invisible
opacity: item.type % 2 != 0 ? 0.0 : 1.0,
child: _GoodsItemTag(
text: '金币抵扣',
color: Theme.of(context).primaryColor,
),
)
],
),
Gaps.vGap16,
Text(Utils.formatPrice('20.00', format: MoneyFormat.NORMAL))
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Semantics(
/// container属性为true,防止上方ExcludeSemantics去除此处语义
container: true,
label: '商品操作菜单',
child: GestureDetector(
onTap: onTapMenu,
child: Container(
key: Key('goods_menu_item_$index'),
width: 44.0,
height: 44.0,
color: Colors.transparent,
padding: const EdgeInsets.only(left: 28.0, bottom: 28.0),
child: const LoadAssetImage('goods/ellipsis'),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Text(
'特产美味',
style: Theme.of(context).textTheme.subtitle2,
),
)
],
)
],
);
return Stack(
children: <Widget>[
// item间的分隔线
Padding(
padding: const EdgeInsets.only(left: 16.0, top: 16.0),
child: DecoratedBox(
decoration: BoxDecoration(
border: Border(
bottom: Divider.createBorderSide(context, width: 0.8),
),
),
child: Padding(
padding: const EdgeInsets.only(right: 16.0, bottom: 16.0),
child: child,
),
),
),
if (selectIndex != index) Gaps.empty else _buildGoodsMenu(context),
],
);
}
Widget _buildGoodsMenu(BuildContext context) {
return Positioned.fill(
child: AnimatedBuilder(
animation: animation,
child: _buildGoodsMenuContent(context),
builder: (_, Widget? child) {
return MenuReveal(
revealPercent: animation.value,
child: child!
);
}
),
);
}
Widget _buildGoodsMenuContent(BuildContext context) {
final bool isDark = context.isDark;
final Color buttonColor = isDark ? Colours.dark_text : Colors.white;
return InkWell(
onTap: onTapMenuClose,
child: Container(
color: isDark ? const Color(0xB34D4D4D) : const Color(0x4D000000),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Gaps.hGap15,
MyButton(
key: Key('goods_edit_item_$index'),
text: '编辑',
fontSize: Dimens.font_sp16,
radius: 24.0,
minWidth: 56.0,
minHeight: 56.0,
padding: const EdgeInsets.symmetric(horizontal: 12.0),
textColor: isDark ? Colours.dark_button_text : Colors.white,
backgroundColor: isDark ? Colours.dark_app_main : Colours.app_main,
onPressed: onTapEdit,
),
MyButton(
key: Key('goods_operation_item_$index'),
text: '下架',
fontSize: Dimens.font_sp16,
radius: 24.0,
minWidth: 56.0,
minHeight: 56.0,
padding: const EdgeInsets.symmetric(horizontal: 12.0),
textColor: Colours.text,
backgroundColor: buttonColor,
onPressed: onTapOperation,
),
MyButton(
key: Key('goods_delete_item_$index'),
text: '删除',
fontSize: Dimens.font_sp16,
radius: 24.0,
minWidth: 56.0,
minHeight: 56.0,
padding: const EdgeInsets.symmetric(horizontal: 12.0),
textColor: Colours.text,
backgroundColor: buttonColor,
onPressed: onTapDelete,
),
Gaps.hGap15,
],
),
),
);
}
}
class _GoodsItemTag extends StatelessWidget {
const _GoodsItemTag({
Key? key,
required this.color,
required this.text,
}): super(key: key);
final Color? color;
final String text;
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
margin: const EdgeInsets.only(right: 4.0),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(2.0),
),
height: 16.0,
alignment: Alignment.center,
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: Dimens.font_sp10,
height: Device.isAndroid ? 1.1 : null,
),
),
);
}
}
......@@ -43,6 +43,62 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
build:
dependency: transitive
description:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.3"
built_collection:
dependency: transitive
description:
name: built_collection
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
built_value:
dependency: transitive
description:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.3"
cached_network_image:
dependency: "direct main"
description:
......@@ -78,6 +134,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
cli_util:
dependency: transitive
description:
......@@ -92,6 +155,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
collection:
dependency: transitive
description:
......@@ -148,6 +218,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
dart_style:
dependency: transitive
description:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
decimal:
dependency: "direct overridden"
description:
......@@ -225,6 +302,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.2"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
fluro:
dependency: "direct main"
description:
......@@ -332,6 +416,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
html:
dependency: transitive
description:
......@@ -407,13 +498,27 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.3"
json_annotation:
dependency: "direct main"
description:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.3"
keyboard_actions:
dependency: "direct main"
description:
name: keyboard_actions
url: "https://pub.dartlang.org"
source: hosted
version: "3.4.5"
version: "3.4.6"
lints:
dependency: transitive
description:
......@@ -589,6 +694,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
qr_code_scanner:
dependency: "direct main"
description:
......@@ -720,6 +832,20 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
source_gen:
dependency: transitive
description:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
source_map_stack_trace:
dependency: transitive
description:
......@@ -790,6 +916,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
stream_transform:
dependency: transitive
description:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
......@@ -846,6 +979,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
typed_data:
dependency: transitive
description:
......
......@@ -81,7 +81,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
# temp
# tiktok
video_player: ^2.1.6
# map取值
safemap: ^2.0.0-nullsafety.0
......@@ -90,6 +90,8 @@ dependencies:
# 加载动画库
flutter_spinkit: ^5.0.0
json_annotation: ^4.4.0
dependency_overrides:
decimal: 1.5.0
......@@ -114,6 +116,9 @@ dev_dependencies:
# rules and activating additional ones.
flutter_lints: ^1.0.0
json_serializable: ^6.1.3
build_runner: ^2.1.7
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
......