Showing
7 changed files
with
279 additions
and
254 deletions
| ... | @@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary { | ... | @@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary { |
| 22 | 22 | ||
| 23 | final messages = _notInlinedMessages(_notInlinedMessages); | 23 | final messages = _notInlinedMessages(_notInlinedMessages); |
| 24 | static Map<String, Function> _notInlinedMessages(_) => <String, Function>{ | 24 | static Map<String, Function> _notInlinedMessages(_) => <String, Function>{ |
| 25 | + "categoryBottomNavigationBarItemTitle": | ||
| 26 | + MessageLookupByLibrary.simpleMessage("category"), | ||
| 25 | "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), | 27 | "confirm": MessageLookupByLibrary.simpleMessage("Confirm"), |
| 26 | "forgotPasswordLink": | 28 | "forgotPasswordLink": |
| 27 | MessageLookupByLibrary.simpleMessage("Forgot Password"), | 29 | MessageLookupByLibrary.simpleMessage("Forgot Password"), |
| ... | @@ -40,14 +42,20 @@ class MessageLookup extends MessageLookupByLibrary { | ... | @@ -40,14 +42,20 @@ class MessageLookup extends MessageLookupByLibrary { |
| 40 | "login": MessageLookupByLibrary.simpleMessage("Login"), | 42 | "login": MessageLookupByLibrary.simpleMessage("Login"), |
| 41 | "noAccountRegisterLink": MessageLookupByLibrary.simpleMessage( | 43 | "noAccountRegisterLink": MessageLookupByLibrary.simpleMessage( |
| 42 | "No account yet? Register now"), | 44 | "No account yet? Register now"), |
| 45 | + "onePoemBottomNavigationBarItemTitle": | ||
| 46 | + MessageLookupByLibrary.simpleMessage("Poem"), | ||
| 43 | "openYourAccount": | 47 | "openYourAccount": |
| 44 | MessageLookupByLibrary.simpleMessage("Open your account"), | 48 | MessageLookupByLibrary.simpleMessage("Open your account"), |
| 45 | "passwordLogin": MessageLookupByLibrary.simpleMessage("Password Login"), | 49 | "passwordLogin": MessageLookupByLibrary.simpleMessage("Password Login"), |
| 50 | + "profileBottomNavigationBarItemTitle": | ||
| 51 | + MessageLookupByLibrary.simpleMessage("profile"), | ||
| 46 | "register": MessageLookupByLibrary.simpleMessage("Register"), | 52 | "register": MessageLookupByLibrary.simpleMessage("Register"), |
| 47 | "registeredTips": MessageLookupByLibrary.simpleMessage( | 53 | "registeredTips": MessageLookupByLibrary.simpleMessage( |
| 48 | "Unregistered mobile phone number, please "), | 54 | "Unregistered mobile phone number, please "), |
| 49 | "resetLoginPassword": | 55 | "resetLoginPassword": |
| 50 | MessageLookupByLibrary.simpleMessage("Reset Login Password"), | 56 | MessageLookupByLibrary.simpleMessage("Reset Login Password"), |
| 57 | + "timelineBottomNavigationBarItemTitle": | ||
| 58 | + MessageLookupByLibrary.simpleMessage("timeline"), | ||
| 51 | "title": MessageLookupByLibrary.simpleMessage("One Poem"), | 59 | "title": MessageLookupByLibrary.simpleMessage("One Poem"), |
| 52 | "verificationButton": MessageLookupByLibrary.simpleMessage( | 60 | "verificationButton": MessageLookupByLibrary.simpleMessage( |
| 53 | "Not really sent, just log in!"), | 61 | "Not really sent, just log in!"), | ... | ... |
| ... | @@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary { | ... | @@ -22,6 +22,8 @@ class MessageLookup extends MessageLookupByLibrary { |
| 22 | 22 | ||
| 23 | final messages = _notInlinedMessages(_notInlinedMessages); | 23 | final messages = _notInlinedMessages(_notInlinedMessages); |
| 24 | static Map<String, Function> _notInlinedMessages(_) => <String, Function>{ | 24 | static Map<String, Function> _notInlinedMessages(_) => <String, Function>{ |
| 25 | + "categoryBottomNavigationBarItemTitle": | ||
| 26 | + MessageLookupByLibrary.simpleMessage("众妙"), | ||
| 25 | "confirm": MessageLookupByLibrary.simpleMessage("确认"), | 27 | "confirm": MessageLookupByLibrary.simpleMessage("确认"), |
| 26 | "forgotPasswordLink": MessageLookupByLibrary.simpleMessage("忘记密码"), | 28 | "forgotPasswordLink": MessageLookupByLibrary.simpleMessage("忘记密码"), |
| 27 | "getVerificationCode": MessageLookupByLibrary.simpleMessage("获取验证码"), | 29 | "getVerificationCode": MessageLookupByLibrary.simpleMessage("获取验证码"), |
| ... | @@ -34,12 +36,18 @@ class MessageLookup extends MessageLookupByLibrary { | ... | @@ -34,12 +36,18 @@ class MessageLookup extends MessageLookupByLibrary { |
| 34 | "login": MessageLookupByLibrary.simpleMessage("登录"), | 36 | "login": MessageLookupByLibrary.simpleMessage("登录"), |
| 35 | "noAccountRegisterLink": | 37 | "noAccountRegisterLink": |
| 36 | MessageLookupByLibrary.simpleMessage("还没账号?快去注册"), | 38 | MessageLookupByLibrary.simpleMessage("还没账号?快去注册"), |
| 39 | + "onePoemBottomNavigationBarItemTitle": | ||
| 40 | + MessageLookupByLibrary.simpleMessage("一言"), | ||
| 37 | "openYourAccount": MessageLookupByLibrary.simpleMessage("开启你的账号"), | 41 | "openYourAccount": MessageLookupByLibrary.simpleMessage("开启你的账号"), |
| 38 | "passwordLogin": MessageLookupByLibrary.simpleMessage("密码登录"), | 42 | "passwordLogin": MessageLookupByLibrary.simpleMessage("密码登录"), |
| 43 | + "profileBottomNavigationBarItemTitle": | ||
| 44 | + MessageLookupByLibrary.simpleMessage("我在"), | ||
| 39 | "register": MessageLookupByLibrary.simpleMessage("注册"), | 45 | "register": MessageLookupByLibrary.simpleMessage("注册"), |
| 40 | "registeredTips": | 46 | "registeredTips": |
| 41 | MessageLookupByLibrary.simpleMessage("提示:未注册账号的手机号,请先"), | 47 | MessageLookupByLibrary.simpleMessage("提示:未注册账号的手机号,请先"), |
| 42 | "resetLoginPassword": MessageLookupByLibrary.simpleMessage("重置登录密码"), | 48 | "resetLoginPassword": MessageLookupByLibrary.simpleMessage("重置登录密码"), |
| 49 | + "timelineBottomNavigationBarItemTitle": | ||
| 50 | + MessageLookupByLibrary.simpleMessage("临境"), | ||
| 43 | "title": MessageLookupByLibrary.simpleMessage("一言"), | 51 | "title": MessageLookupByLibrary.simpleMessage("一言"), |
| 44 | "verificationButton": | 52 | "verificationButton": |
| 45 | MessageLookupByLibrary.simpleMessage("并没有真正发送哦,直接登录吧!"), | 53 | MessageLookupByLibrary.simpleMessage("并没有真正发送哦,直接登录吧!"), | ... | ... |
| ... | @@ -229,6 +229,46 @@ class S { | ... | @@ -229,6 +229,46 @@ class S { |
| 229 | args: [], | 229 | args: [], |
| 230 | ); | 230 | ); |
| 231 | } | 231 | } |
| 232 | + | ||
| 233 | + /// `Poem` | ||
| 234 | + String get onePoemBottomNavigationBarItemTitle { | ||
| 235 | + return Intl.message( | ||
| 236 | + 'Poem', | ||
| 237 | + name: 'onePoemBottomNavigationBarItemTitle', | ||
| 238 | + desc: 'One Poem', | ||
| 239 | + args: [], | ||
| 240 | + ); | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + /// `timeline` | ||
| 244 | + String get timelineBottomNavigationBarItemTitle { | ||
| 245 | + return Intl.message( | ||
| 246 | + 'timeline', | ||
| 247 | + name: 'timelineBottomNavigationBarItemTitle', | ||
| 248 | + desc: 'One Poem', | ||
| 249 | + args: [], | ||
| 250 | + ); | ||
| 251 | + } | ||
| 252 | + | ||
| 253 | + /// `category` | ||
| 254 | + String get categoryBottomNavigationBarItemTitle { | ||
| 255 | + return Intl.message( | ||
| 256 | + 'category', | ||
| 257 | + name: 'categoryBottomNavigationBarItemTitle', | ||
| 258 | + desc: 'One Poem', | ||
| 259 | + args: [], | ||
| 260 | + ); | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + /// `profile` | ||
| 264 | + String get profileBottomNavigationBarItemTitle { | ||
| 265 | + return Intl.message( | ||
| 266 | + 'profile', | ||
| 267 | + name: 'profileBottomNavigationBarItemTitle', | ||
| 268 | + desc: 'One Poem', | ||
| 269 | + args: [], | ||
| 270 | + ); | ||
| 271 | + } | ||
| 232 | } | 272 | } |
| 233 | 273 | ||
| 234 | class AppLocalizationDelegate extends LocalizationsDelegate<S> { | 274 | class AppLocalizationDelegate extends LocalizationsDelegate<S> { | ... | ... |
| ... | @@ -106,5 +106,29 @@ | ... | @@ -106,5 +106,29 @@ |
| 106 | "description": "Registered Tips", | 106 | "description": "Registered Tips", |
| 107 | "type": "text", | 107 | "type": "text", |
| 108 | "placeholders": {} | 108 | "placeholders": {} |
| 109 | + }, | ||
| 110 | + "onePoemBottomNavigationBarItemTitle": "Poem", | ||
| 111 | + "@onePoemBottomNavigationBarItemTitle": { | ||
| 112 | + "description": "One Poem", | ||
| 113 | + "type": "text", | ||
| 114 | + "placeholders": {} | ||
| 115 | + }, | ||
| 116 | + "timelineBottomNavigationBarItemTitle": "timeline", | ||
| 117 | + "@timelineBottomNavigationBarItemTitle": { | ||
| 118 | + "description": "One Poem", | ||
| 119 | + "type": "text", | ||
| 120 | + "placeholders": {} | ||
| 121 | + }, | ||
| 122 | + "categoryBottomNavigationBarItemTitle": "category", | ||
| 123 | + "@categoryBottomNavigationBarItemTitle": { | ||
| 124 | + "description": "One Poem", | ||
| 125 | + "type": "text", | ||
| 126 | + "placeholders": {} | ||
| 127 | + }, | ||
| 128 | + "profileBottomNavigationBarItemTitle": "profile", | ||
| 129 | + "@profileBottomNavigationBarItemTitle": { | ||
| 130 | + "description": "One Poem", | ||
| 131 | + "type": "text", | ||
| 132 | + "placeholders": {} | ||
| 109 | } | 133 | } |
| 110 | } | 134 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -16,5 +16,9 @@ | ... | @@ -16,5 +16,9 @@ |
| 16 | "getVerificationCode": "获取验证码", | 16 | "getVerificationCode": "获取验证码", |
| 17 | "confirm": "确认", | 17 | "confirm": "确认", |
| 18 | "resetLoginPassword": "重置登录密码", | 18 | "resetLoginPassword": "重置登录密码", |
| 19 | - "registeredTips": "提示:未注册账号的手机号,请先" | 19 | + "registeredTips": "提示:未注册账号的手机号,请先", |
| 20 | + "onePoemBottomNavigationBarItemTitle" : "一言", | ||
| 21 | + "timelineBottomNavigationBarItemTitle" : "临境", | ||
| 22 | + "categoryBottomNavigationBarItemTitle" : "众妙", | ||
| 23 | + "profileBottomNavigationBarItemTitle" : "我在" | ||
| 20 | } | 24 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| 1 | - | ||
| 2 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 3 | import 'package:one_poem/res/resources.dart'; | 2 | import 'package:one_poem/res/resources.dart'; |
| 4 | import 'package:one_poem/routers/fluro_navigator.dart'; | 3 | import 'package:one_poem/routers/fluro_navigator.dart'; | ... | ... |
| 1 | - | 1 | +import 'package:flutter/cupertino.dart'; |
| 2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
| 3 | -import 'package:flutter/services.dart'; | ||
| 4 | -import 'package:one_poem/order/provider/order_page_provider.dart'; | ||
| 5 | -import 'package:one_poem/res/resources.dart'; | ||
| 6 | -import 'package:one_poem/routers/fluro_navigator.dart'; | ||
| 7 | -import 'package:one_poem/util/image_utils.dart'; | ||
| 8 | -import 'package:one_poem/util/theme_utils.dart'; | ||
| 9 | -import 'package:one_poem/util/screen_utils.dart'; | ||
| 10 | -import 'package:one_poem/widgets/load_image.dart'; | ||
| 11 | -import 'package:one_poem/widgets/my_card.dart'; | ||
| 12 | -import 'package:one_poem/widgets/my_flexible_space_bar.dart'; | ||
| 13 | -import 'package:provider/provider.dart'; | ||
| 14 | - | ||
| 15 | -import '../order_router.dart'; | ||
| 16 | -import 'order_list_page.dart'; | ||
| 17 | 3 | ||
| 18 | - | ||
| 19 | -/// design/3订单/index.html | ||
| 20 | class OrderPage extends StatefulWidget { | 4 | class OrderPage extends StatefulWidget { |
| 21 | - | ||
| 22 | const OrderPage({Key? key}) : super(key: key); | 5 | const OrderPage({Key? key}) : super(key: key); |
| 23 | 6 | ||
| 24 | @override | 7 | @override |
| 25 | _OrderPageState createState() => _OrderPageState(); | 8 | _OrderPageState createState() => _OrderPageState(); |
| 26 | } | 9 | } |
| 27 | 10 | ||
| 28 | -class _OrderPageState extends State<OrderPage> with AutomaticKeepAliveClientMixin<OrderPage>, SingleTickerProviderStateMixin { | 11 | +class _OrderPageState extends State<OrderPage> with WidgetsBindingObserver { |
| 12 | + TikTokPageTag tabBarType = TikTokPageTag.home; | ||
| 29 | 13 | ||
| 30 | - @override | 14 | + TikTokScaffoldController tkController = TikTokScaffoldController(); |
| 31 | - bool get wantKeepAlive => true; | 15 | + |
| 16 | + PageController _pageController = PageController(); | ||
| 17 | + | ||
| 18 | + TikTokVideoListController _videoListController = TikTokVideoListController(); | ||
| 32 | 19 | ||
| 33 | - TabController? _tabController; | 20 | + /// 记录点赞 |
| 34 | - OrderPageProvider provider = OrderPageProvider(); | 21 | + Map<int, bool> favoriteMap = {}; |
| 35 | 22 | ||
| 36 | - int _lastReportedPage = 0; | 23 | + List<UserVideo> videoDataList = []; |
| 37 | 24 | ||
| 38 | @override | 25 | @override |
| 39 | - void initState() { | 26 | + void didChangeAppLifecycleState(AppLifecycleState state) async { |
| 40 | - super.initState(); | 27 | + if (state != AppLifecycleState.resumed) { |
| 41 | - _tabController = TabController(vsync: this, length: 5); | 28 | + _videoListController.currentPlayer.pause(); |
| 42 | - WidgetsBinding.instance!.addPostFrameCallback((_) { | ||
| 43 | - /// 预先缓存剩余切换图片 | ||
| 44 | - _preCacheImage(); | ||
| 45 | - }); | ||
| 46 | } | 29 | } |
| 47 | - | ||
| 48 | - void _preCacheImage() { | ||
| 49 | - precacheImage(ImageUtils.getAssetImage('order/xdd_n'), context); | ||
| 50 | - precacheImage(ImageUtils.getAssetImage('order/dps_s'), context); | ||
| 51 | - precacheImage(ImageUtils.getAssetImage('order/dwc_s'), context); | ||
| 52 | - precacheImage(ImageUtils.getAssetImage('order/ywc_s'), context); | ||
| 53 | - precacheImage(ImageUtils.getAssetImage('order/yqx_s'), context); | ||
| 54 | } | 30 | } |
| 55 | 31 | ||
| 56 | @override | 32 | @override |
| 57 | void dispose() { | 33 | void dispose() { |
| 58 | - _tabController?.dispose(); | 34 | + WidgetsBinding.instance!.removeObserver(this); |
| 35 | + _videoListController.currentPlayer.pause(); | ||
| 59 | super.dispose(); | 36 | super.dispose(); |
| 60 | } | 37 | } |
| 61 | 38 | ||
| 62 | - bool isDark = false; | ||
| 63 | - | ||
| 64 | @override | 39 | @override |
| 65 | - Widget build(BuildContext context) { | 40 | + void initState() { |
| 66 | - super.build(context); | 41 | + videoDataList = UserVideo.fetchVideo(); |
| 67 | - isDark = context.isDark; | 42 | + WidgetsBinding.instance!.addObserver(this); |
| 68 | - return ChangeNotifierProvider<OrderPageProvider>( | 43 | + _videoListController.init( |
| 69 | - create: (_) => provider, | 44 | + pageController: _pageController, |
| 70 | - child: Scaffold( | 45 | + initialList: videoDataList |
| 71 | - body: Stack( | 46 | + .map( |
| 72 | - children: <Widget>[ | 47 | + (e) => VPVideoController( |
| 73 | - /// 像素对齐问题的临时解决方法 | 48 | + videoInfo: e, |
| 74 | - SafeArea( | 49 | + builder: () => VideoPlayerController.network(e.url), |
| 75 | - child: SizedBox( | ||
| 76 | - height: 105, | ||
| 77 | - width: double.infinity, | ||
| 78 | - child: isDark ? null : const DecoratedBox( | ||
| 79 | - decoration: BoxDecoration( | ||
| 80 | - gradient: LinearGradient(colors: [Colours.gradient_blue, Color(0xFF4647FA)]), | ||
| 81 | - ), | ||
| 82 | - ), | ||
| 83 | ), | 50 | ), |
| 51 | + ) | ||
| 52 | + .toList(), | ||
| 53 | + videoProvider: (int index, List<VPVideoController> list) async { | ||
| 54 | + return videoDataList | ||
| 55 | + .map( | ||
| 56 | + (e) => VPVideoController( | ||
| 57 | + videoInfo: e, | ||
| 58 | + builder: () => VideoPlayerController.network(e.url), | ||
| 84 | ), | 59 | ), |
| 85 | - NestedScrollView( | 60 | + ) |
| 86 | - key: const Key('order_list'), | 61 | + .toList(); |
| 87 | - physics: const ClampingScrollPhysics(), | ||
| 88 | - headerSliverBuilder: (context, innerBoxIsScrolled) => _sliverBuilder(context), | ||
| 89 | - body: NotificationListener<ScrollNotification>( | ||
| 90 | - onNotification: (ScrollNotification notification) { | ||
| 91 | - /// PageView的onPageChanged是监听ScrollUpdateNotification,会造成滑动中卡顿。这里修改为监听滚动结束再更新、 | ||
| 92 | - if (notification.depth == 0 && notification is ScrollEndNotification) { | ||
| 93 | - final PageMetrics metrics = notification.metrics as PageMetrics; | ||
| 94 | - final int currentPage = (metrics.page ?? 0).round(); | ||
| 95 | - if (currentPage != _lastReportedPage) { | ||
| 96 | - _lastReportedPage = currentPage; | ||
| 97 | - _onPageChange(currentPage); | ||
| 98 | - } | ||
| 99 | - } | ||
| 100 | - return false; | ||
| 101 | }, | 62 | }, |
| 102 | - child: PageView.builder( | ||
| 103 | - key: const Key('pageView'), | ||
| 104 | - itemCount: 5, | ||
| 105 | - controller: _pageController, | ||
| 106 | - itemBuilder: (_, index) => OrderListPage(index: index), | ||
| 107 | - ), | ||
| 108 | - ), | ||
| 109 | - ), | ||
| 110 | - ], | ||
| 111 | - ), | ||
| 112 | - ), | ||
| 113 | ); | 63 | ); |
| 64 | + _videoListController.addListener(() { | ||
| 65 | + setState(() {}); | ||
| 66 | + }); | ||
| 67 | + tkController.addListener( | ||
| 68 | + () { | ||
| 69 | + if (tkController.value == TikTokPagePositon.middle) { | ||
| 70 | + _videoListController.currentPlayer.play(); | ||
| 71 | + } else { | ||
| 72 | + _videoListController.currentPlayer.pause(); | ||
| 114 | } | 73 | } |
| 115 | - | ||
| 116 | - List<Widget> _sliverBuilder(BuildContext context) { | ||
| 117 | - return <Widget>[ | ||
| 118 | - SliverOverlapAbsorber( | ||
| 119 | - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), | ||
| 120 | - sliver: SliverAppBar( | ||
| 121 | - systemOverlayStyle: SystemUiOverlayStyle.light, | ||
| 122 | - actions: <Widget>[ | ||
| 123 | - IconButton( | ||
| 124 | - onPressed: () { | ||
| 125 | - NavigatorUtils.push(context, OrderRouter.orderSearchPage); | ||
| 126 | - }, | ||
| 127 | - tooltip: '搜索', | ||
| 128 | - icon: LoadAssetImage('order/icon_search', | ||
| 129 | - width: 22.0, | ||
| 130 | - height: 22.0, | ||
| 131 | - color: ThemeUtils.getIconColor(context), | ||
| 132 | - ), | ||
| 133 | - ) | ||
| 134 | - ], | ||
| 135 | - backgroundColor: Colors.transparent, | ||
| 136 | - elevation: 0.0, | ||
| 137 | - centerTitle: true, | ||
| 138 | - expandedHeight: 100.0, // 不随着滑动隐藏标题 | ||
| 139 | - pinned: true, // 固定在顶部 | ||
| 140 | - flexibleSpace: MyFlexibleSpaceBar( | ||
| 141 | - background: isDark ? Container(height: 113.0, color: Colours.dark_bg_color,) : LoadAssetImage('order/order_bg', | ||
| 142 | - width: context.width, | ||
| 143 | - height: 113.0, | ||
| 144 | - fit: BoxFit.fill, | ||
| 145 | - ), | ||
| 146 | - centerTitle: true, | ||
| 147 | - titlePadding: const EdgeInsetsDirectional.only(start: 16.0, bottom: 14.0), | ||
| 148 | - collapseMode: CollapseMode.pin, | ||
| 149 | - title: Text('订单', style: TextStyle(color: ThemeUtils.getIconColor(context)),), | ||
| 150 | - ), | ||
| 151 | - ), | ||
| 152 | - ), | ||
| 153 | - SliverPersistentHeader( | ||
| 154 | - pinned: true, | ||
| 155 | - delegate: SliverAppBarDelegate( | ||
| 156 | - DecoratedBox( | ||
| 157 | - decoration: BoxDecoration( | ||
| 158 | - color: isDark ? Colours.dark_bg_color : null, | ||
| 159 | - image: isDark ? null : DecorationImage( | ||
| 160 | - image: ImageUtils.getAssetImage('order/order_bg1'), | ||
| 161 | - fit: BoxFit.fill, | ||
| 162 | - ), | ||
| 163 | - ), | ||
| 164 | - child: Padding( | ||
| 165 | - padding: const EdgeInsets.symmetric(horizontal: 16.0), | ||
| 166 | - child: MyCard( | ||
| 167 | - child: Container( | ||
| 168 | - height: 80.0, | ||
| 169 | - padding: const EdgeInsets.only(top: 8.0), | ||
| 170 | - child: TabBar( | ||
| 171 | - labelPadding: EdgeInsets.zero, | ||
| 172 | - controller: _tabController, | ||
| 173 | - labelColor: context.isDark ? Colours.dark_text : Colours.text, | ||
| 174 | - unselectedLabelColor: context.isDark ? Colours.dark_text_gray : Colours.text, | ||
| 175 | - labelStyle: TextStyles.textBold14, | ||
| 176 | - unselectedLabelStyle: const TextStyle( | ||
| 177 | - fontSize: Dimens.font_sp14, | ||
| 178 | - ), | ||
| 179 | - indicatorColor: Colors.transparent, | ||
| 180 | - tabs: const <Widget>[ | ||
| 181 | - _TabView(0, '新订单'), | ||
| 182 | - _TabView(1, '待配送'), | ||
| 183 | - _TabView(2, '待完成'), | ||
| 184 | - _TabView(3, '已完成'), | ||
| 185 | - _TabView(4, '已取消'), | ||
| 186 | - ], | ||
| 187 | - onTap: (index) { | ||
| 188 | - if (!mounted) { | ||
| 189 | - return; | ||
| 190 | - } | ||
| 191 | - _pageController.jumpToPage(index); | ||
| 192 | }, | 74 | }, |
| 193 | - ), | 75 | + ); |
| 194 | - ), | ||
| 195 | - ), | ||
| 196 | - ), | ||
| 197 | - ), 80.0, | ||
| 198 | - ), | ||
| 199 | - ), | ||
| 200 | - ]; | ||
| 201 | - } | ||
| 202 | 76 | ||
| 203 | - final PageController _pageController = PageController(); | 77 | + super.initState(); |
| 204 | - Future<void> _onPageChange(int index) async { | ||
| 205 | - provider.setIndex(index); | ||
| 206 | - /// 这里没有指示器,所以缩短过渡动画时间,减少不必要的刷新 | ||
| 207 | - _tabController?.animateTo(index, duration: Duration.zero); | ||
| 208 | } | 78 | } |
| 209 | -} | ||
| 210 | - | ||
| 211 | -List<List<String>> img = [ | ||
| 212 | - ['order/xdd_s', 'order/xdd_n'], | ||
| 213 | - ['order/dps_s', 'order/dps_n'], | ||
| 214 | - ['order/dwc_s', 'order/dwc_n'], | ||
| 215 | - ['order/ywc_s', 'order/ywc_n'], | ||
| 216 | - ['order/yqx_s', 'order/yqx_n'] | ||
| 217 | -]; | ||
| 218 | - | ||
| 219 | -List<List<String>> darkImg = [ | ||
| 220 | - ['order/dark/icon_xdd_s', 'order/dark/icon_xdd_n'], | ||
| 221 | - ['order/dark/icon_dps_s', 'order/dark/icon_dps_n'], | ||
| 222 | - ['order/dark/icon_dwc_s', 'order/dark/icon_dwc_n'], | ||
| 223 | - ['order/dark/icon_ywc_s', 'order/dark/icon_ywc_n'], | ||
| 224 | - ['order/dark/icon_yqx_s', 'order/dark/icon_yqx_n'] | ||
| 225 | -]; | ||
| 226 | - | ||
| 227 | -class _TabView extends StatelessWidget { | ||
| 228 | - | ||
| 229 | - const _TabView(this.index, this.text); | ||
| 230 | - | ||
| 231 | - final int index; | ||
| 232 | - final String text; | ||
| 233 | 79 | ||
| 234 | @override | 80 | @override |
| 235 | Widget build(BuildContext context) { | 81 | Widget build(BuildContext context) { |
| 236 | - final List<List<String>> imgList = context.isDark ? darkImg : img; | 82 | + Widget? currentPage; |
| 237 | - return Stack( | 83 | + |
| 238 | - children: <Widget>[ | 84 | + switch (tabBarType) { |
| 239 | - Container( | 85 | + case TikTokPageTag.home: |
| 240 | - width: 46.0, | 86 | + break; |
| 241 | - padding: const EdgeInsets.symmetric(vertical: 8.0), | 87 | + case TikTokPageTag.follow: |
| 242 | - child: Column( | 88 | + currentPage = FollowPage(); |
| 243 | - children: <Widget>[ | 89 | + break; |
| 244 | - /// 使用context.select替代Consumer | 90 | + case TikTokPageTag.msg: |
| 245 | - LoadAssetImage(context.select<OrderPageProvider, int>((value) => value.index) == index ? | 91 | + currentPage = MsgPage(); |
| 246 | - imgList[index][0] : | 92 | + break; |
| 247 | - imgList[index][1], width: 24.0, height: 24.0,), | 93 | + case TikTokPageTag.me: |
| 248 | - Gaps.vGap4, | 94 | + currentPage = UserPage(isSelfPage: true); |
| 249 | - Text(text), | 95 | + break; |
| 250 | - ], | ||
| 251 | - ), | ||
| 252 | - ), | ||
| 253 | - Positioned( | ||
| 254 | - right: 0.0, | ||
| 255 | - child: index < 3 ? DecoratedBox( | ||
| 256 | - decoration: BoxDecoration( | ||
| 257 | - color: Theme.of(context).errorColor, | ||
| 258 | - borderRadius: BorderRadius.circular(11.0), | ||
| 259 | - ), | ||
| 260 | - child: const Padding( | ||
| 261 | - padding: EdgeInsets.symmetric(horizontal: 5.5, vertical: 2.0), | ||
| 262 | - child: Text('10', style: TextStyle(color: Colors.white, fontSize: Dimens.font_sp12),), | ||
| 263 | - ), | ||
| 264 | - ) : Gaps.empty, | ||
| 265 | - ) | ||
| 266 | - ], | ||
| 267 | - ); | ||
| 268 | } | 96 | } |
| 269 | -} | 97 | + double a = MediaQuery.of(context).size.aspectRatio; |
| 270 | - | 98 | + bool hasBottomPadding = a < 0.55; |
| 271 | -class SliverAppBarDelegate extends SliverPersistentHeaderDelegate { | ||
| 272 | 99 | ||
| 273 | - SliverAppBarDelegate(this.widget, this.height); | 100 | + bool hasBackground = hasBottomPadding; |
| 274 | - | 101 | + hasBackground = tabBarType != TikTokPageTag.home; |
| 275 | - final Widget widget; | 102 | + if (hasBottomPadding) { |
| 276 | - final double height; | 103 | + hasBackground = true; |
| 104 | + } | ||
| 105 | + Widget tikTokTabBar = TikTokTabBar( | ||
| 106 | + hasBackground: hasBackground, | ||
| 107 | + current: tabBarType, | ||
| 108 | + onTabSwitch: (type) async { | ||
| 109 | + setState(() { | ||
| 110 | + tabBarType = type; | ||
| 111 | + if (type == TikTokPageTag.home) { | ||
| 112 | + _videoListController.currentPlayer.play(); | ||
| 113 | + } else { | ||
| 114 | + _videoListController.currentPlayer.pause(); | ||
| 115 | + } | ||
| 116 | + }); | ||
| 117 | + }, | ||
| 118 | + onAddButton: () { | ||
| 119 | + Navigator.of(context).push( | ||
| 120 | + MaterialPageRoute( | ||
| 121 | + fullscreenDialog: true, | ||
| 122 | + builder: (context) => CameraPage(), | ||
| 123 | + ), | ||
| 124 | + ); | ||
| 125 | + }, | ||
| 126 | + ); | ||
| 277 | 127 | ||
| 278 | - // minHeight 和 maxHeight 的值设置为相同时,header就不会收缩了 | 128 | + var userPage = UserPage( |
| 279 | - @override | 129 | + isSelfPage: false, |
| 280 | - double get minExtent => height; | 130 | + canPop: true, |
| 131 | + onPop: () { | ||
| 132 | + tkController.animateToMiddle(); | ||
| 133 | + }, | ||
| 134 | + ); | ||
| 135 | + var searchPage = SearchPage( | ||
| 136 | + onPop: tkController.animateToMiddle, | ||
| 137 | + ); | ||
| 281 | 138 | ||
| 282 | - @override | 139 | + var header = tabBarType == TikTokPageTag.home |
| 283 | - double get maxExtent => height; | 140 | + ? TikTokHeader( |
| 141 | + onSearch: () { | ||
| 142 | + tkController.animateToLeft(); | ||
| 143 | + }, | ||
| 144 | + ) | ||
| 145 | + : Container(); | ||
| 146 | + | ||
| 147 | + // 组合 | ||
| 148 | + return TikTokScaffold( | ||
| 149 | + controller: tkController, | ||
| 150 | + hasBottomPadding: hasBackground, | ||
| 151 | + tabBar: tikTokTabBar, | ||
| 152 | + header: header, | ||
| 153 | + leftPage: searchPage, | ||
| 154 | + rightPage: userPage, | ||
| 155 | + enableGesture: tabBarType == TikTokPageTag.home, | ||
| 156 | + // onPullDownRefresh: _fetchData, | ||
| 157 | + page: Stack( | ||
| 158 | + // index: currentPage == null ? 0 : 1, | ||
| 159 | + children: <Widget>[ | ||
| 160 | + PageView.builder( | ||
| 161 | + key: Key('home'), | ||
| 162 | + physics: QuickerScrollPhysics(), | ||
| 163 | + controller: _pageController, | ||
| 164 | + scrollDirection: Axis.vertical, | ||
| 165 | + itemCount: _videoListController.videoCount, | ||
| 166 | + itemBuilder: (context, i) { | ||
| 167 | + // 拼一个视频组件出来 | ||
| 168 | + bool isF = SafeMap(favoriteMap)[i].boolean ?? false; | ||
| 169 | + var player = _videoListController.playerOfIndex(i)!; | ||
| 170 | + var data = player.videoInfo!; | ||
| 171 | + // 右侧按钮列 | ||
| 172 | + Widget buttons = TikTokButtonColumn( | ||
| 173 | + isFavorite: isF, | ||
| 174 | + onAvatar: () { | ||
| 175 | + tkController.animateToPage(TikTokPagePositon.right); | ||
| 176 | + }, | ||
| 177 | + onFavorite: () { | ||
| 178 | + setState(() { | ||
| 179 | + favoriteMap[i] = !isF; | ||
| 180 | + }); | ||
| 181 | + // showAboutDialog(context: context); | ||
| 182 | + }, | ||
| 183 | + onComment: () { | ||
| 184 | + CustomBottomSheet.showModalBottomSheet( | ||
| 185 | + backgroundColor: Colors.white.withOpacity(0), | ||
| 186 | + context: context, | ||
| 187 | + builder: (BuildContext context) => | ||
| 188 | + TikTokCommentBottomSheet(), | ||
| 189 | + ); | ||
| 190 | + }, | ||
| 191 | + onShare: () {}, | ||
| 192 | + ); | ||
| 193 | + // video | ||
| 194 | + Widget currentVideo = Center( | ||
| 195 | + child: AspectRatio( | ||
| 196 | + aspectRatio: player.controller.value.aspectRatio, | ||
| 197 | + child: VideoPlayer(player.controller), | ||
| 198 | + ), | ||
| 199 | + ); | ||
| 284 | 200 | ||
| 285 | - @override | 201 | + currentVideo = TikTokVideoPage( |
| 286 | - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { | 202 | + // 手势播放与自然播放都会产生暂停按钮状态变化,待处理 |
| 287 | - return widget; | 203 | + hidePauseIcon: !player.showPauseIcon.value, |
| 204 | + aspectRatio: 9 / 16.0, | ||
| 205 | + key: Key(data.url + '$i'), | ||
| 206 | + tag: data.url, | ||
| 207 | + bottomPadding: hasBottomPadding ? 16.0 : 16.0, | ||
| 208 | + userInfoWidget: VideoUserInfo( | ||
| 209 | + desc: data.desc, | ||
| 210 | + bottomPadding: hasBottomPadding ? 16.0 : 50.0, | ||
| 211 | + ), | ||
| 212 | + onSingleTap: () async { | ||
| 213 | + if (player.controller.value.isPlaying) { | ||
| 214 | + await player.pause(); | ||
| 215 | + } else { | ||
| 216 | + await player.play(); | ||
| 288 | } | 217 | } |
| 289 | - | 218 | + setState(() {}); |
| 290 | - @override | 219 | + }, |
| 291 | - bool shouldRebuild(SliverAppBarDelegate oldDelegate) { | 220 | + onAddFavorite: () { |
| 292 | - return true; | 221 | + setState(() { |
| 222 | + favoriteMap[i] = true; | ||
| 223 | + }); | ||
| 224 | + }, | ||
| 225 | + rightButtonColumn: buttons, | ||
| 226 | + video: currentVideo, | ||
| 227 | + ); | ||
| 228 | + return currentVideo; | ||
| 229 | + }, | ||
| 230 | + ), | ||
| 231 | + currentPage ?? Container(), | ||
| 232 | + ], | ||
| 233 | + ), | ||
| 234 | + ); | ||
| 293 | } | 235 | } |
| 294 | } | 236 | } | ... | ... |
-
Please register or login to post a comment