reason

clear

......@@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary {
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"categoryBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("category"),
"confirm": MessageLookupByLibrary.simpleMessage("Confirm"),
"forgotPasswordLink":
MessageLookupByLibrary.simpleMessage("Forgot Password"),
......@@ -40,14 +42,20 @@ class MessageLookup extends MessageLookupByLibrary {
"login": MessageLookupByLibrary.simpleMessage("Login"),
"noAccountRegisterLink": MessageLookupByLibrary.simpleMessage(
"No account yet? Register now"),
"onePoemBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("Poem"),
"openYourAccount":
MessageLookupByLibrary.simpleMessage("Open your account"),
"passwordLogin": MessageLookupByLibrary.simpleMessage("Password Login"),
"profileBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("profile"),
"register": MessageLookupByLibrary.simpleMessage("Register"),
"registeredTips": MessageLookupByLibrary.simpleMessage(
"Unregistered mobile phone number, please "),
"resetLoginPassword":
MessageLookupByLibrary.simpleMessage("Reset Login Password"),
"timelineBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("timeline"),
"title": MessageLookupByLibrary.simpleMessage("One Poem"),
"verificationButton": MessageLookupByLibrary.simpleMessage(
"Not really sent, just log in!"),
......
......@@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary {
final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
"categoryBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("众妙"),
"confirm": MessageLookupByLibrary.simpleMessage("确认"),
"forgotPasswordLink": MessageLookupByLibrary.simpleMessage("忘记密码"),
"getVerificationCode": MessageLookupByLibrary.simpleMessage("获取验证码"),
......@@ -34,12 +36,18 @@ class MessageLookup extends MessageLookupByLibrary {
"login": MessageLookupByLibrary.simpleMessage("登录"),
"noAccountRegisterLink":
MessageLookupByLibrary.simpleMessage("还没账号?快去注册"),
"onePoemBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("一言"),
"openYourAccount": MessageLookupByLibrary.simpleMessage("开启你的账号"),
"passwordLogin": MessageLookupByLibrary.simpleMessage("密码登录"),
"profileBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("我在"),
"register": MessageLookupByLibrary.simpleMessage("注册"),
"registeredTips":
MessageLookupByLibrary.simpleMessage("提示:未注册账号的手机号,请先"),
"resetLoginPassword": MessageLookupByLibrary.simpleMessage("重置登录密码"),
"timelineBottomNavigationBarItemTitle":
MessageLookupByLibrary.simpleMessage("临境"),
"title": MessageLookupByLibrary.simpleMessage("一言"),
"verificationButton":
MessageLookupByLibrary.simpleMessage("并没有真正发送哦,直接登录吧!"),
......
......@@ -229,6 +229,46 @@ class S {
args: [],
);
}
/// `Poem`
String get onePoemBottomNavigationBarItemTitle {
return Intl.message(
'Poem',
name: 'onePoemBottomNavigationBarItemTitle',
desc: 'One Poem',
args: [],
);
}
/// `timeline`
String get timelineBottomNavigationBarItemTitle {
return Intl.message(
'timeline',
name: 'timelineBottomNavigationBarItemTitle',
desc: 'One Poem',
args: [],
);
}
/// `category`
String get categoryBottomNavigationBarItemTitle {
return Intl.message(
'category',
name: 'categoryBottomNavigationBarItemTitle',
desc: 'One Poem',
args: [],
);
}
/// `profile`
String get profileBottomNavigationBarItemTitle {
return Intl.message(
'profile',
name: 'profileBottomNavigationBarItemTitle',
desc: 'One Poem',
args: [],
);
}
}
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
......
......@@ -106,5 +106,29 @@
"description": "Registered Tips",
"type": "text",
"placeholders": {}
},
"onePoemBottomNavigationBarItemTitle": "Poem",
"@onePoemBottomNavigationBarItemTitle": {
"description": "One Poem",
"type": "text",
"placeholders": {}
},
"timelineBottomNavigationBarItemTitle": "timeline",
"@timelineBottomNavigationBarItemTitle": {
"description": "One Poem",
"type": "text",
"placeholders": {}
},
"categoryBottomNavigationBarItemTitle": "category",
"@categoryBottomNavigationBarItemTitle": {
"description": "One Poem",
"type": "text",
"placeholders": {}
},
"profileBottomNavigationBarItemTitle": "profile",
"@profileBottomNavigationBarItemTitle": {
"description": "One Poem",
"type": "text",
"placeholders": {}
}
}
\ No newline at end of file
......
......@@ -16,5 +16,9 @@
"getVerificationCode": "获取验证码",
"confirm": "确认",
"resetLoginPassword": "重置登录密码",
"registeredTips": "提示:未注册账号的手机号,请先"
"registeredTips": "提示:未注册账号的手机号,请先",
"onePoemBottomNavigationBarItemTitle" : "一言",
"timelineBottomNavigationBarItemTitle" : "临境",
"categoryBottomNavigationBarItemTitle" : "众妙",
"profileBottomNavigationBarItemTitle" : "我在"
}
\ No newline at end of file
......
import 'package:flutter/material.dart';
import 'package:one_poem/res/resources.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
......
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:one_poem/order/provider/order_page_provider.dart';
import 'package:one_poem/res/resources.dart';
import 'package:one_poem/routers/fluro_navigator.dart';
import 'package:one_poem/util/image_utils.dart';
import 'package:one_poem/util/theme_utils.dart';
import 'package:one_poem/util/screen_utils.dart';
import 'package:one_poem/widgets/load_image.dart';
import 'package:one_poem/widgets/my_card.dart';
import 'package:one_poem/widgets/my_flexible_space_bar.dart';
import 'package:provider/provider.dart';
import '../order_router.dart';
import 'order_list_page.dart';
/// design/3订单/index.html
class OrderPage extends StatefulWidget {
const OrderPage({Key? key}) : super(key: key);
@override
_OrderPageState createState() => _OrderPageState();
}
class _OrderPageState extends State<OrderPage> with AutomaticKeepAliveClientMixin<OrderPage>, SingleTickerProviderStateMixin {
class _OrderPageState extends State<OrderPage> with WidgetsBindingObserver {
TikTokPageTag tabBarType = TikTokPageTag.home;
@override
bool get wantKeepAlive => true;
TabController? _tabController;
OrderPageProvider provider = OrderPageProvider();
TikTokScaffoldController tkController = TikTokScaffoldController();
int _lastReportedPage = 0;
@override
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 5);
WidgetsBinding.instance!.addPostFrameCallback((_) {
/// 预先缓存剩余切换图片
_preCacheImage();
});
}
PageController _pageController = PageController();
TikTokVideoListController _videoListController = TikTokVideoListController();
/// 记录点赞
Map<int, bool> favoriteMap = {};
List<UserVideo> videoDataList = [];
void _preCacheImage() {
precacheImage(ImageUtils.getAssetImage('order/xdd_n'), context);
precacheImage(ImageUtils.getAssetImage('order/dps_s'), context);
precacheImage(ImageUtils.getAssetImage('order/dwc_s'), context);
precacheImage(ImageUtils.getAssetImage('order/ywc_s'), context);
precacheImage(ImageUtils.getAssetImage('order/yqx_s'), context);
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
if (state != AppLifecycleState.resumed) {
_videoListController.currentPlayer.pause();
}
}
@override
void dispose() {
_tabController?.dispose();
WidgetsBinding.instance!.removeObserver(this);
_videoListController.currentPlayer.pause();
super.dispose();
}
bool isDark = false;
@override
Widget build(BuildContext context) {
super.build(context);
isDark = context.isDark;
return ChangeNotifierProvider<OrderPageProvider>(
create: (_) => provider,
child: Scaffold(
body: Stack(
children: <Widget>[
/// 像素对齐问题的临时解决方法
SafeArea(
child: SizedBox(
height: 105,
width: double.infinity,
child: isDark ? null : const DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colours.gradient_blue, Color(0xFF4647FA)]),
),
),
),
),
NestedScrollView(
key: const Key('order_list'),
physics: const ClampingScrollPhysics(),
headerSliverBuilder: (context, innerBoxIsScrolled) => _sliverBuilder(context),
body: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
/// PageView的onPageChanged是监听ScrollUpdateNotification,会造成滑动中卡顿。这里修改为监听滚动结束再更新、
if (notification.depth == 0 && notification is ScrollEndNotification) {
final PageMetrics metrics = notification.metrics as PageMetrics;
final int currentPage = (metrics.page ?? 0).round();
if (currentPage != _lastReportedPage) {
_lastReportedPage = currentPage;
_onPageChange(currentPage);
}
}
return false;
},
child: PageView.builder(
key: const Key('pageView'),
itemCount: 5,
controller: _pageController,
itemBuilder: (_, index) => OrderListPage(index: index),
),
),
),
],
void initState() {
videoDataList = UserVideo.fetchVideo();
WidgetsBinding.instance!.addObserver(this);
_videoListController.init(
pageController: _pageController,
initialList: videoDataList
.map(
(e) => VPVideoController(
videoInfo: e,
builder: () => VideoPlayerController.network(e.url),
),
),
);
}
List<Widget> _sliverBuilder(BuildContext context) {
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
systemOverlayStyle: SystemUiOverlayStyle.light,
actions: <Widget>[
IconButton(
onPressed: () {
NavigatorUtils.push(context, OrderRouter.orderSearchPage);
},
tooltip: '搜索',
icon: LoadAssetImage('order/icon_search',
width: 22.0,
height: 22.0,
color: ThemeUtils.getIconColor(context),
),
)
],
backgroundColor: Colors.transparent,
elevation: 0.0,
centerTitle: true,
expandedHeight: 100.0, // 不随着滑动隐藏标题
pinned: true, // 固定在顶部
flexibleSpace: MyFlexibleSpaceBar(
background: isDark ? Container(height: 113.0, color: Colours.dark_bg_color,) : LoadAssetImage('order/order_bg',
width: context.width,
height: 113.0,
fit: BoxFit.fill,
),
centerTitle: true,
titlePadding: const EdgeInsetsDirectional.only(start: 16.0, bottom: 14.0),
collapseMode: CollapseMode.pin,
title: Text('订单', style: TextStyle(color: ThemeUtils.getIconColor(context)),),
)
.toList(),
videoProvider: (int index, List<VPVideoController> list) async {
return videoDataList
.map(
(e) => VPVideoController(
videoInfo: e,
builder: () => VideoPlayerController.network(e.url),
),
),
),
SliverPersistentHeader(
pinned: true,
delegate: SliverAppBarDelegate(
DecoratedBox(
decoration: BoxDecoration(
color: isDark ? Colours.dark_bg_color : null,
image: isDark ? null : DecorationImage(
image: ImageUtils.getAssetImage('order/order_bg1'),
fit: BoxFit.fill,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: MyCard(
child: Container(
height: 80.0,
padding: const EdgeInsets.only(top: 8.0),
child: TabBar(
labelPadding: EdgeInsets.zero,
controller: _tabController,
labelColor: context.isDark ? Colours.dark_text : Colours.text,
unselectedLabelColor: context.isDark ? Colours.dark_text_gray : Colours.text,
labelStyle: TextStyles.textBold14,
unselectedLabelStyle: const TextStyle(
fontSize: Dimens.font_sp14,
),
indicatorColor: Colors.transparent,
tabs: const <Widget>[
_TabView(0, '新订单'),
_TabView(1, '待配送'),
_TabView(2, '待完成'),
_TabView(3, '已完成'),
_TabView(4, '已取消'),
],
onTap: (index) {
if (!mounted) {
return;
}
_pageController.jumpToPage(index);
},
),
),
),
),
), 80.0,
),
),
];
}
)
.toList();
},
);
_videoListController.addListener(() {
setState(() {});
});
tkController.addListener(
() {
if (tkController.value == TikTokPagePositon.middle) {
_videoListController.currentPlayer.play();
} else {
_videoListController.currentPlayer.pause();
}
},
);
final PageController _pageController = PageController();
Future<void> _onPageChange(int index) async {
provider.setIndex(index);
/// 这里没有指示器,所以缩短过渡动画时间,减少不必要的刷新
_tabController?.animateTo(index, duration: Duration.zero);
super.initState();
}
}
List<List<String>> img = [
['order/xdd_s', 'order/xdd_n'],
['order/dps_s', 'order/dps_n'],
['order/dwc_s', 'order/dwc_n'],
['order/ywc_s', 'order/ywc_n'],
['order/yqx_s', 'order/yqx_n']
];
List<List<String>> darkImg = [
['order/dark/icon_xdd_s', 'order/dark/icon_xdd_n'],
['order/dark/icon_dps_s', 'order/dark/icon_dps_n'],
['order/dark/icon_dwc_s', 'order/dark/icon_dwc_n'],
['order/dark/icon_ywc_s', 'order/dark/icon_ywc_n'],
['order/dark/icon_yqx_s', 'order/dark/icon_yqx_n']
];
class _TabView extends StatelessWidget {
const _TabView(this.index, this.text);
final int index;
final String text;
@override
Widget build(BuildContext context) {
final List<List<String>> imgList = context.isDark ? darkImg : img;
return Stack(
children: <Widget>[
Container(
width: 46.0,
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Column(
children: <Widget>[
/// 使用context.select替代Consumer
LoadAssetImage(context.select<OrderPageProvider, int>((value) => value.index) == index ?
imgList[index][0] :
imgList[index][1], width: 24.0, height: 24.0,),
Gaps.vGap4,
Text(text),
],
Widget? currentPage;
switch (tabBarType) {
case TikTokPageTag.home:
break;
case TikTokPageTag.follow:
currentPage = FollowPage();
break;
case TikTokPageTag.msg:
currentPage = MsgPage();
break;
case TikTokPageTag.me:
currentPage = UserPage(isSelfPage: true);
break;
}
double a = MediaQuery.of(context).size.aspectRatio;
bool hasBottomPadding = a < 0.55;
bool hasBackground = hasBottomPadding;
hasBackground = tabBarType != TikTokPageTag.home;
if (hasBottomPadding) {
hasBackground = true;
}
Widget tikTokTabBar = TikTokTabBar(
hasBackground: hasBackground,
current: tabBarType,
onTabSwitch: (type) async {
setState(() {
tabBarType = type;
if (type == TikTokPageTag.home) {
_videoListController.currentPlayer.play();
} else {
_videoListController.currentPlayer.pause();
}
});
},
onAddButton: () {
Navigator.of(context).push(
MaterialPageRoute(
fullscreenDialog: true,
builder: (context) => CameraPage(),
),
),
Positioned(
right: 0.0,
child: index < 3 ? DecoratedBox(
decoration: BoxDecoration(
color: Theme.of(context).errorColor,
borderRadius: BorderRadius.circular(11.0),
),
child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 5.5, vertical: 2.0),
child: Text('10', style: TextStyle(color: Colors.white, fontSize: Dimens.font_sp12),),
),
) : Gaps.empty,
)
],
);
},
);
}
}
class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
SliverAppBarDelegate(this.widget, this.height);
final Widget widget;
final double height;
// minHeight 和 maxHeight 的值设置为相同时,header就不会收缩了
@override
double get minExtent => height;
@override
double get maxExtent => height;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return widget;
}
var userPage = UserPage(
isSelfPage: false,
canPop: true,
onPop: () {
tkController.animateToMiddle();
},
);
var searchPage = SearchPage(
onPop: tkController.animateToMiddle,
);
@override
bool shouldRebuild(SliverAppBarDelegate oldDelegate) {
return true;
var header = tabBarType == TikTokPageTag.home
? TikTokHeader(
onSearch: () {
tkController.animateToLeft();
},
)
: Container();
// 组合
return TikTokScaffold(
controller: tkController,
hasBottomPadding: hasBackground,
tabBar: tikTokTabBar,
header: header,
leftPage: searchPage,
rightPage: userPage,
enableGesture: tabBarType == TikTokPageTag.home,
// onPullDownRefresh: _fetchData,
page: Stack(
// index: currentPage == null ? 0 : 1,
children: <Widget>[
PageView.builder(
key: Key('home'),
physics: QuickerScrollPhysics(),
controller: _pageController,
scrollDirection: Axis.vertical,
itemCount: _videoListController.videoCount,
itemBuilder: (context, i) {
// 拼一个视频组件出来
bool isF = SafeMap(favoriteMap)[i].boolean ?? false;
var player = _videoListController.playerOfIndex(i)!;
var data = player.videoInfo!;
// 右侧按钮列
Widget buttons = TikTokButtonColumn(
isFavorite: isF,
onAvatar: () {
tkController.animateToPage(TikTokPagePositon.right);
},
onFavorite: () {
setState(() {
favoriteMap[i] = !isF;
});
// showAboutDialog(context: context);
},
onComment: () {
CustomBottomSheet.showModalBottomSheet(
backgroundColor: Colors.white.withOpacity(0),
context: context,
builder: (BuildContext context) =>
TikTokCommentBottomSheet(),
);
},
onShare: () {},
);
// video
Widget currentVideo = Center(
child: AspectRatio(
aspectRatio: player.controller.value.aspectRatio,
child: VideoPlayer(player.controller),
),
);
currentVideo = TikTokVideoPage(
// 手势播放与自然播放都会产生暂停按钮状态变化,待处理
hidePauseIcon: !player.showPauseIcon.value,
aspectRatio: 9 / 16.0,
key: Key(data.url + '$i'),
tag: data.url,
bottomPadding: hasBottomPadding ? 16.0 : 16.0,
userInfoWidget: VideoUserInfo(
desc: data.desc,
bottomPadding: hasBottomPadding ? 16.0 : 50.0,
),
onSingleTap: () async {
if (player.controller.value.isPlaying) {
await player.pause();
} else {
await player.play();
}
setState(() {});
},
onAddFavorite: () {
setState(() {
favoriteMap[i] = true;
});
},
rightButtonColumn: buttons,
video: currentVideo,
);
return currentVideo;
},
),
currentPage ?? Container(),
],
),
);
}
}
......