Showing
15 changed files
with
699 additions
and
74 deletions
| ... | @@ -6,7 +6,7 @@ buildscript { | ... | @@ -6,7 +6,7 @@ buildscript { |
| 6 | } | 6 | } |
| 7 | 7 | ||
| 8 | dependencies { | 8 | dependencies { |
| 9 | - classpath 'com.android.tools.build:gradle:7.0.2' | 9 | + classpath 'com.android.tools.build:gradle:7.0.4' |
| 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" |
| 11 | classpath "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" | 11 | classpath "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" |
| 12 | } | 12 | } | ... | ... |
| ... | @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME | ... | @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME |
| 3 | distributionPath=wrapper/dists | 3 | distributionPath=wrapper/dists |
| 4 | zipStoreBase=GRADLE_USER_HOME | 4 | zipStoreBase=GRADLE_USER_HOME |
| 5 | zipStorePath=wrapper/dists | 5 | zipStorePath=wrapper/dists |
| 6 | -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 6 | +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
assets/video/1656599376238999.mp4
0 → 100644
No preview for this file type
| 1 | -import 'package:Parlando/common/permission_request_widget.dart'; | 1 | +import 'package:Parlando/poem/components/video_slides.dart'; |
| 2 | -import 'package:Parlando/routers/fluro_navigator.dart'; | ||
| 3 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
| 4 | -import 'package:Parlando/account/page/account_page.dart'; | ||
| 5 | -import 'package:Parlando/poem/page/poem_page.dart'; | ||
| 6 | -import 'package:Parlando/widgets/double_tap_back_exit_app.dart'; | ||
| 7 | -import 'package:provider/provider.dart'; | ||
| 8 | -import 'provider/home_provider.dart'; | ||
| 9 | -import 'package:permission_handler/permission_handler.dart'; | ||
| 10 | 3 | ||
| 11 | class Home extends StatefulWidget { | 4 | class Home extends StatefulWidget { |
| 12 | const Home({Key? key}) : super(key: key); | 5 | const Home({Key? key}) : super(key: key); |
| 13 | 6 | ||
| 14 | @override | 7 | @override |
| 15 | - _HomeState createState() => _HomeState(); | 8 | + HomeState createState() => HomeState(); |
| 16 | } | 9 | } |
| 17 | 10 | ||
| 18 | -class _HomeState extends State<Home> with RestorationMixin { | 11 | +class HomeState extends State<Home> { |
| 19 | - late List<Widget> _pageList; | 12 | + final PageController _controller = PageController(); |
| 20 | - final PageController _pageController = PageController(); | ||
| 21 | - | ||
| 22 | - HomeProvider provider = HomeProvider(); | ||
| 23 | 13 | ||
| 24 | @override | 14 | @override |
| 25 | void initState() { | 15 | void initState() { |
| 26 | super.initState(); | 16 | super.initState(); |
| 27 | - initData(); | 17 | + //设置pageView 滑动监听 |
| 28 | - List<String> list = [ | 18 | + _controller.addListener(() { |
| 29 | - "为您更好的体验应用,所以需要获取您的手机摄像头权限,以保存您的一些偏好设置", | 19 | + if (_controller.position.pixels == _controller.position.maxScrollExtent) { |
| 30 | - "您已拒绝权限,所以无法保存您的一些偏好设置,将无法使用APP", | 20 | + print('滑动到了最底部'); |
| 31 | - "您已拒绝权限,请在设置中心中同意APP的权限请求", | 21 | + _getMore(); |
| 32 | - "其他错误" | 22 | + } |
| 33 | - ]; | 23 | + }); |
| 34 | - | ||
| 35 | - Future.delayed( | ||
| 36 | - Duration.zero, | ||
| 37 | - () { | ||
| 38 | - NavigatorUtils.pushPageByFade( | ||
| 39 | - context: context, | ||
| 40 | - //目标页面 | ||
| 41 | - targetPage: PermissionRequestWidget( | ||
| 42 | - //所需要申请的权限 | ||
| 43 | - permission: Permission.camera, | ||
| 44 | - //显示关闭应用按钮 | ||
| 45 | - isCloseApp: true, | ||
| 46 | - //提示文案 | ||
| 47 | - permissionList: list, | ||
| 48 | - ), | ||
| 49 | - //权限申请结果 | ||
| 50 | - dismissCallBack: (value) {}, | ||
| 51 | - ); | ||
| 52 | - }, | ||
| 53 | - ); | ||
| 54 | } | 24 | } |
| 55 | 25 | ||
| 56 | - @override | 26 | + /// 下拉刷新方法,为list重新赋值 |
| 57 | - void dispose() { | 27 | + Future<void> _onRefresh() async { |
| 58 | - _pageController.dispose(); | 28 | + await Future.delayed(const Duration(seconds: 1), () { |
| 59 | - super.dispose(); | 29 | + print('refresh'); |
| 30 | + setState(() {}); | ||
| 31 | + }); | ||
| 60 | } | 32 | } |
| 61 | 33 | ||
| 62 | - void initData() { | 34 | + /// 上拉加载更多 |
| 63 | - _pageList = [ | 35 | + Future<void> _getMore() async { |
| 64 | - const PoemPage(), | 36 | + await Future.delayed(const Duration(seconds: 1), () { |
| 65 | - const AccountPage(), | 37 | + print('_getMore'); |
| 66 | - ]; | 38 | + setState(() {}); |
| 39 | + }); | ||
| 67 | } | 40 | } |
| 68 | 41 | ||
| 69 | @override | 42 | @override |
| 70 | Widget build(BuildContext context) { | 43 | Widget build(BuildContext context) { |
| 71 | - return ChangeNotifierProvider<HomeProvider>( | 44 | + return Stack( |
| 72 | - create: (_) => provider, | 45 | + children: [ |
| 73 | - child: DoubleTapBackExitApp( | 46 | + RefreshIndicator( |
| 74 | - child: Scaffold( | 47 | + //下拉刷新触发方法 |
| 75 | - // 使用PageView的原因参看 https://zhuanlan.zhihu.com/p/58582876 | 48 | + onRefresh: _onRefresh, |
| 76 | - body: PageView( | 49 | + //设置listView |
| 77 | - physics: const NeverScrollableScrollPhysics(), // 禁止滑动 | 50 | + child: PageView( |
| 78 | - controller: _pageController, | 51 | + controller: _controller, |
| 79 | - onPageChanged: (int index) => provider.value = index, | 52 | + //设置滑动方向 |
| 80 | - children: _pageList, | 53 | + scrollDirection: Axis.vertical, |
| 54 | + children: const [ | ||
| 55 | + VideoSlides(), | ||
| 56 | + VideoSlides(), | ||
| 57 | + VideoSlides(), | ||
| 58 | + ], | ||
| 59 | + ), | ||
| 60 | + ), | ||
| 61 | + Positioned( | ||
| 62 | + top: 18.0, | ||
| 63 | + left: 10.0, | ||
| 64 | + right: 10.0, | ||
| 65 | + child: Center( | ||
| 66 | + child: Row( | ||
| 67 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 68 | + children: [ | ||
| 69 | + TextButton( | ||
| 70 | + onPressed: () {}, | ||
| 71 | + child: const Text( | ||
| 72 | + "临境", | ||
| 73 | + style: TextStyle( | ||
| 74 | + color: Colors.white, | ||
| 75 | + fontSize: 15, | ||
| 76 | + ), | ||
| 77 | + ), | ||
| 78 | + ), | ||
| 79 | + const Text( | ||
| 80 | + "|", | ||
| 81 | + style: TextStyle(color: Colors.white), | ||
| 82 | + ), | ||
| 83 | + TextButton( | ||
| 84 | + onPressed: () {}, | ||
| 85 | + child: const Text( | ||
| 86 | + "妙众", | ||
| 87 | + style: TextStyle( | ||
| 88 | + color: Colors.white, | ||
| 89 | + fontSize: 15, | ||
| 81 | ), | 90 | ), |
| 82 | ), | 91 | ), |
| 83 | ), | 92 | ), |
| 93 | + const Text( | ||
| 94 | + "|", | ||
| 95 | + style: TextStyle(color: Colors.white), | ||
| 96 | + ), | ||
| 97 | + TextButton( | ||
| 98 | + onPressed: () => {}, | ||
| 99 | + child: const Text( | ||
| 100 | + "新鲜", | ||
| 101 | + style: TextStyle( | ||
| 102 | + color: Colors.white, | ||
| 103 | + fontSize: 15, | ||
| 104 | + ), | ||
| 105 | + ), | ||
| 106 | + ), | ||
| 107 | + ], | ||
| 108 | + ), | ||
| 109 | + ), | ||
| 110 | + ), | ||
| 111 | + ], | ||
| 84 | ); | 112 | ); |
| 85 | } | 113 | } |
| 86 | - | ||
| 87 | - @override | ||
| 88 | - String? get restorationId => 'home'; | ||
| 89 | - | ||
| 90 | - @override | ||
| 91 | - void restoreState(RestorationBucket? oldBucket, bool initialRestore) { | ||
| 92 | - registerForRestoration(provider, 'BottomNavigationBarCurrentIndex'); | ||
| 93 | - } | ||
| 94 | } | 114 | } | ... | ... |
| ... | @@ -115,7 +115,7 @@ class _SplashPageState extends State<SplashPage> { | ... | @@ -115,7 +115,7 @@ class _SplashPageState extends State<SplashPage> { |
| 115 | 115 | ||
| 116 | void _goLogin() { | 116 | void _goLogin() { |
| 117 | if (SpUtil.containsKey(Constant.userToken)!) { | 117 | if (SpUtil.containsKey(Constant.userToken)!) { |
| 118 | - NavigatorUtils.push(context, Routes.home, clearStack: true); | 118 | + NavigatorUtils.push(context, Routes.navBarPage, clearStack: true); |
| 119 | } else { | 119 | } else { |
| 120 | NavigatorUtils.push(context, LoginRouter.loginPage, replace: true); | 120 | NavigatorUtils.push(context, LoginRouter.loginPage, replace: true); |
| 121 | } | 121 | } | ... | ... |
| ... | @@ -113,7 +113,7 @@ class _LoginPageState extends State<LoginPage> | ... | @@ -113,7 +113,7 @@ class _LoginPageState extends State<LoginPage> |
| 113 | params: params, | 113 | params: params, |
| 114 | onSuccess: (data) { | 114 | onSuccess: (data) { |
| 115 | SpUtil.putString(Constant.userToken, data!.data!.token!); | 115 | SpUtil.putString(Constant.userToken, data!.data!.token!); |
| 116 | - NavigatorUtils.push(context, Routes.home, clearStack: true); | 116 | + NavigatorUtils.push(context, Routes.navBarPage, clearStack: true); |
| 117 | _isLoading = false; | 117 | _isLoading = false; |
| 118 | }, | 118 | }, |
| 119 | onError: (code, msg) { | 119 | onError: (code, msg) { | ... | ... |
| ... | @@ -90,7 +90,7 @@ class _RegisterPageState extends State<RegisterPage> | ... | @@ -90,7 +90,7 @@ class _RegisterPageState extends State<RegisterPage> |
| 90 | params: params, | 90 | params: params, |
| 91 | onSuccess: (data) { | 91 | onSuccess: (data) { |
| 92 | SpUtil.putString(Constant.userToken, data!.data!.token!); | 92 | SpUtil.putString(Constant.userToken, data!.data!.token!); |
| 93 | - NavigatorUtils.push(context, Routes.home, clearStack: true); | 93 | + NavigatorUtils.push(context, Routes.navBarPage, clearStack: true); |
| 94 | _isLoading = false; | 94 | _isLoading = false; |
| 95 | }, | 95 | }, |
| 96 | onError: (code, msg) { | 96 | onError: (code, msg) { | ... | ... |
lib/poem/components/nav_bar_page.dart
0 → 100644
| 1 | +import 'package:Parlando/account/page/account_page.dart'; | ||
| 2 | +import 'package:Parlando/home/home_page.dart'; | ||
| 3 | +import 'package:Parlando/poem/theme/tik_theme.dart'; | ||
| 4 | +import 'package:flutter/material.dart'; | ||
| 5 | + | ||
| 6 | +class NavBarPage extends StatefulWidget { | ||
| 7 | + const NavBarPage({Key? key, required this.initialPage}) : super(key: key); | ||
| 8 | + | ||
| 9 | + final String initialPage; | ||
| 10 | + | ||
| 11 | + @override | ||
| 12 | + NavBarPageState createState() => NavBarPageState(); | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +/// This is the private State class that goes with NavBarPage. | ||
| 16 | +class NavBarPageState extends State<NavBarPage> { | ||
| 17 | + String _currentPage = 'HomePage'; | ||
| 18 | + | ||
| 19 | + @override | ||
| 20 | + void initState() { | ||
| 21 | + super.initState(); | ||
| 22 | + _currentPage = widget.initialPage; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + @override | ||
| 26 | + Widget build(BuildContext context) { | ||
| 27 | + final tabs = { | ||
| 28 | + 'HomePage': const Home(), | ||
| 29 | + 'UploadStatusPage': const AccountPage(), | ||
| 30 | + 'UserProfile': const AccountPage(), | ||
| 31 | + }; | ||
| 32 | + return Scaffold( | ||
| 33 | + body: tabs[_currentPage], | ||
| 34 | + bottomNavigationBar: BottomNavigationBar( | ||
| 35 | + items: const <BottomNavigationBarItem>[ | ||
| 36 | + BottomNavigationBarItem( | ||
| 37 | + icon: Icon( | ||
| 38 | + Icons.home_filled, | ||
| 39 | + size: 24, | ||
| 40 | + ), | ||
| 41 | + label: 'Home', | ||
| 42 | + tooltip: '', | ||
| 43 | + ), | ||
| 44 | + BottomNavigationBarItem( | ||
| 45 | + icon: Icon( | ||
| 46 | + Icons.add_circle_outline_rounded, | ||
| 47 | + size: 50, | ||
| 48 | + ), | ||
| 49 | + activeIcon: Icon( | ||
| 50 | + Icons.add_circle_rounded, | ||
| 51 | + size: 50, | ||
| 52 | + ), | ||
| 53 | + label: '', | ||
| 54 | + tooltip: '', | ||
| 55 | + ), | ||
| 56 | + BottomNavigationBarItem( | ||
| 57 | + icon: Icon( | ||
| 58 | + Icons.person_rounded, | ||
| 59 | + size: 26, | ||
| 60 | + ), | ||
| 61 | + label: 'Profile', | ||
| 62 | + tooltip: '', | ||
| 63 | + ) | ||
| 64 | + ], | ||
| 65 | + backgroundColor: TikTheme.tertiaryColor, | ||
| 66 | + currentIndex: tabs.keys.toList().indexOf(_currentPage), | ||
| 67 | + selectedItemColor: TikTheme.primaryColor, | ||
| 68 | + unselectedItemColor: const Color(0x53FFFFFF), | ||
| 69 | + onTap: (i) => setState(() => _currentPage = tabs.keys.toList()[i]), | ||
| 70 | + showSelectedLabels: true, | ||
| 71 | + showUnselectedLabels: true, | ||
| 72 | + type: BottomNavigationBarType.fixed, | ||
| 73 | + ), | ||
| 74 | + ); | ||
| 75 | + } | ||
| 76 | +} |
lib/poem/components/video_slides.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | +import 'package:share_plus/share_plus.dart'; | ||
| 3 | + | ||
| 4 | +import '../theme/tik_theme.dart'; | ||
| 5 | +import '../theme/tik_video_player.dart'; | ||
| 6 | + | ||
| 7 | +class VideoSlides extends StatefulWidget { | ||
| 8 | + const VideoSlides({Key? key}) : super(key: key); | ||
| 9 | + | ||
| 10 | + @override | ||
| 11 | + VideoSlidesState createState() => VideoSlidesState(); | ||
| 12 | +} | ||
| 13 | + | ||
| 14 | +class VideoSlidesState extends State<VideoSlides> { | ||
| 15 | + bool isSharing = false; | ||
| 16 | + | ||
| 17 | + @override | ||
| 18 | + Widget build(BuildContext context) { | ||
| 19 | + return Stack( | ||
| 20 | + children: [ | ||
| 21 | + Container( | ||
| 22 | + width: double.infinity, | ||
| 23 | + height: double.infinity, | ||
| 24 | + constraints: const BoxConstraints( | ||
| 25 | + maxWidth: double.infinity, | ||
| 26 | + maxHeight: double.infinity, | ||
| 27 | + ), | ||
| 28 | + decoration: const BoxDecoration( | ||
| 29 | + color: Colors.black, | ||
| 30 | + ), | ||
| 31 | + child: TikVideoPlayer( | ||
| 32 | + path: 'assets/video/1656599376238999.mp4', | ||
| 33 | + videoType: VideoType.asset, | ||
| 34 | + width: MediaQuery.of(context).size.width, | ||
| 35 | + height: MediaQuery.of(context).size.height * 1, | ||
| 36 | + autoPlay: true, | ||
| 37 | + looping: true, | ||
| 38 | + showControls: false, | ||
| 39 | + allowFullScreen: false, | ||
| 40 | + allowPlaybackSpeedMenu: false, | ||
| 41 | + ), | ||
| 42 | + ), | ||
| 43 | + Row( | ||
| 44 | + mainAxisSize: MainAxisSize.max, | ||
| 45 | + mainAxisAlignment: MainAxisAlignment.end, | ||
| 46 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 47 | + children: [ | ||
| 48 | + Column( | ||
| 49 | + mainAxisSize: MainAxisSize.max, | ||
| 50 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 51 | + children: [ | ||
| 52 | + Container( | ||
| 53 | + width: 70, | ||
| 54 | + height: 330, | ||
| 55 | + decoration: const BoxDecoration( | ||
| 56 | + color: Color(0x4DC4C4C4), | ||
| 57 | + borderRadius: BorderRadius.only( | ||
| 58 | + bottomLeft: Radius.circular(40), | ||
| 59 | + bottomRight: Radius.circular(0), | ||
| 60 | + topLeft: Radius.circular(40), | ||
| 61 | + topRight: Radius.circular(0), | ||
| 62 | + ), | ||
| 63 | + shape: BoxShape.rectangle, | ||
| 64 | + ), | ||
| 65 | + child: Column( | ||
| 66 | + crossAxisAlignment: CrossAxisAlignment.center, | ||
| 67 | + children: [ | ||
| 68 | + Padding( | ||
| 69 | + padding: | ||
| 70 | + const EdgeInsetsDirectional.fromSTEB(0, 10, 0, 0), | ||
| 71 | + child: Row( | ||
| 72 | + mainAxisSize: MainAxisSize.max, | ||
| 73 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 74 | + crossAxisAlignment: CrossAxisAlignment.start, | ||
| 75 | + children: [ | ||
| 76 | + Column( | ||
| 77 | + mainAxisSize: MainAxisSize.max, | ||
| 78 | + children: [ | ||
| 79 | + Padding( | ||
| 80 | + padding: const EdgeInsetsDirectional.fromSTEB( | ||
| 81 | + 0, 20, 0, 0), | ||
| 82 | + child: Container( | ||
| 83 | + width: 50, | ||
| 84 | + height: 50, | ||
| 85 | + decoration: const BoxDecoration( | ||
| 86 | + color: Color(0x69EEEEEE), | ||
| 87 | + shape: BoxShape.circle, | ||
| 88 | + ), | ||
| 89 | + child: const Icon( | ||
| 90 | + Icons.favorite_rounded, | ||
| 91 | + color: Colors.white, | ||
| 92 | + size: 24, | ||
| 93 | + ), | ||
| 94 | + ), | ||
| 95 | + ), | ||
| 96 | + Text( | ||
| 97 | + '121.9k', | ||
| 98 | + style: TikTheme.bodyText1.override( | ||
| 99 | + fontFamily: 'Poppins', | ||
| 100 | + color: Colors.white, | ||
| 101 | + fontSize: 16, | ||
| 102 | + fontWeight: FontWeight.w300, | ||
| 103 | + ), | ||
| 104 | + ), | ||
| 105 | + ], | ||
| 106 | + ), | ||
| 107 | + ], | ||
| 108 | + ), | ||
| 109 | + ), | ||
| 110 | + Padding( | ||
| 111 | + padding: | ||
| 112 | + const EdgeInsetsDirectional.fromSTEB(0, 10, 0, 0), | ||
| 113 | + child: Row( | ||
| 114 | + mainAxisSize: MainAxisSize.max, | ||
| 115 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 116 | + crossAxisAlignment: CrossAxisAlignment.start, | ||
| 117 | + children: [ | ||
| 118 | + Column( | ||
| 119 | + mainAxisSize: MainAxisSize.max, | ||
| 120 | + children: [ | ||
| 121 | + Padding( | ||
| 122 | + padding: const EdgeInsetsDirectional.fromSTEB( | ||
| 123 | + 0, 20, 0, 0), | ||
| 124 | + child: InkWell( | ||
| 125 | + onTap: () async {}, | ||
| 126 | + child: Container( | ||
| 127 | + width: 50, | ||
| 128 | + height: 50, | ||
| 129 | + decoration: const BoxDecoration( | ||
| 130 | + color: Color(0x69EEEEEE), | ||
| 131 | + shape: BoxShape.circle, | ||
| 132 | + ), | ||
| 133 | + child: const Icon( | ||
| 134 | + Icons.star, | ||
| 135 | + color: Colors.white, | ||
| 136 | + size: 34, | ||
| 137 | + ), | ||
| 138 | + ), | ||
| 139 | + ), | ||
| 140 | + ), | ||
| 141 | + Text( | ||
| 142 | + '+8.5', | ||
| 143 | + style: TikTheme.bodyText1.override( | ||
| 144 | + fontFamily: 'Poppins', | ||
| 145 | + color: Colors.white, | ||
| 146 | + fontSize: 16, | ||
| 147 | + fontWeight: FontWeight.w300, | ||
| 148 | + ), | ||
| 149 | + ), | ||
| 150 | + ], | ||
| 151 | + ), | ||
| 152 | + ], | ||
| 153 | + ), | ||
| 154 | + ), | ||
| 155 | + Padding( | ||
| 156 | + padding: | ||
| 157 | + const EdgeInsetsDirectional.fromSTEB(0, 10, 0, 0), | ||
| 158 | + child: Row( | ||
| 159 | + mainAxisSize: MainAxisSize.max, | ||
| 160 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 161 | + crossAxisAlignment: CrossAxisAlignment.start, | ||
| 162 | + children: [ | ||
| 163 | + Column( | ||
| 164 | + mainAxisSize: MainAxisSize.max, | ||
| 165 | + children: [ | ||
| 166 | + Padding( | ||
| 167 | + padding: const EdgeInsetsDirectional.fromSTEB( | ||
| 168 | + 0, 20, 0, 0), | ||
| 169 | + child: InkWell( | ||
| 170 | + onTap: () async { | ||
| 171 | + isSharing = true; | ||
| 172 | + setState(() {}); | ||
| 173 | + Future.delayed(const Duration(seconds: 3), | ||
| 174 | + () async { | ||
| 175 | + setState(() => isSharing = false); | ||
| 176 | + await Share.share('Share Me'); | ||
| 177 | + }); | ||
| 178 | + }, | ||
| 179 | + child: Container( | ||
| 180 | + width: 50, | ||
| 181 | + height: 50, | ||
| 182 | + decoration: const BoxDecoration( | ||
| 183 | + color: Color(0x69EEEEEE), | ||
| 184 | + shape: BoxShape.circle, | ||
| 185 | + ), | ||
| 186 | + child: isSharing | ||
| 187 | + ? const Text("I") | ||
| 188 | + : const Icon( | ||
| 189 | + Icons.share_rounded, | ||
| 190 | + color: Colors.white, | ||
| 191 | + size: 24, | ||
| 192 | + ), | ||
| 193 | + ), | ||
| 194 | + ), | ||
| 195 | + ), | ||
| 196 | + Text( | ||
| 197 | + '分享', | ||
| 198 | + style: TikTheme.bodyText1.override( | ||
| 199 | + fontFamily: 'Poppins', | ||
| 200 | + color: Colors.white, | ||
| 201 | + fontSize: 16, | ||
| 202 | + fontWeight: FontWeight.w300, | ||
| 203 | + ), | ||
| 204 | + ), | ||
| 205 | + ], | ||
| 206 | + ), | ||
| 207 | + ], | ||
| 208 | + ), | ||
| 209 | + ), | ||
| 210 | + ], | ||
| 211 | + ), | ||
| 212 | + ), | ||
| 213 | + ], | ||
| 214 | + ), | ||
| 215 | + ], | ||
| 216 | + ), | ||
| 217 | + ], | ||
| 218 | + ); | ||
| 219 | + } | ||
| 220 | +} |
lib/poem/theme/tik_icon_button.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +class TikIconButton extends StatelessWidget { | ||
| 4 | + const TikIconButton( | ||
| 5 | + {Key? key, | ||
| 6 | + this.borderColor, | ||
| 7 | + this.borderRadius, | ||
| 8 | + this.borderWidth, | ||
| 9 | + this.buttonSize, | ||
| 10 | + this.fillColor, | ||
| 11 | + this.icon, | ||
| 12 | + this.onPressed}) | ||
| 13 | + : super(key: key); | ||
| 14 | + | ||
| 15 | + final double? borderRadius; | ||
| 16 | + final double? buttonSize; | ||
| 17 | + final Color? fillColor; | ||
| 18 | + final Color? borderColor; | ||
| 19 | + final double? borderWidth; | ||
| 20 | + final Widget? icon; | ||
| 21 | + final void Function()? onPressed; | ||
| 22 | + | ||
| 23 | + @override | ||
| 24 | + Widget build(BuildContext context) => Material( | ||
| 25 | + borderRadius: | ||
| 26 | + borderRadius != null ? BorderRadius.circular(borderRadius!) : null, | ||
| 27 | + color: Colors.transparent, | ||
| 28 | + clipBehavior: Clip.antiAlias, | ||
| 29 | + child: Ink( | ||
| 30 | + width: buttonSize, | ||
| 31 | + height: buttonSize, | ||
| 32 | + decoration: BoxDecoration( | ||
| 33 | + color: fillColor, | ||
| 34 | + border: Border.all( | ||
| 35 | + color: borderColor ?? Colors.transparent, | ||
| 36 | + width: borderWidth ?? 0, | ||
| 37 | + ), | ||
| 38 | + borderRadius: borderRadius != null | ||
| 39 | + ? BorderRadius.circular(borderRadius!) | ||
| 40 | + : null, | ||
| 41 | + ), | ||
| 42 | + child: IconButton( | ||
| 43 | + icon: icon!, | ||
| 44 | + onPressed: onPressed, | ||
| 45 | + splashRadius: buttonSize, | ||
| 46 | + ), | ||
| 47 | + ), | ||
| 48 | + ); | ||
| 49 | +} |
lib/poem/theme/tik_theme.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | +import 'package:google_fonts/google_fonts.dart'; | ||
| 3 | + | ||
| 4 | +class TikTheme { | ||
| 5 | + static const Color primaryColor = Color(0xFFE48900); | ||
| 6 | + static const Color secondaryColor = Color(0xFF1C1C4F); | ||
| 7 | + static const Color tertiaryColor = Color(0xFF131B41); | ||
| 8 | + | ||
| 9 | + String primaryFontFamily = 'Poppins'; | ||
| 10 | + String secondaryFontFamily = 'Roboto'; | ||
| 11 | + | ||
| 12 | + static TextStyle get title1 => GoogleFonts.getFont( | ||
| 13 | + 'Poppins', | ||
| 14 | + color: const Color(0xFF303030), | ||
| 15 | + fontWeight: FontWeight.w600, | ||
| 16 | + fontSize: 24, | ||
| 17 | + ); | ||
| 18 | + | ||
| 19 | + static TextStyle get title2 => GoogleFonts.getFont( | ||
| 20 | + 'Poppins', | ||
| 21 | + color: const Color(0xFF303030), | ||
| 22 | + fontWeight: FontWeight.w500, | ||
| 23 | + fontSize: 22, | ||
| 24 | + ); | ||
| 25 | + | ||
| 26 | + static TextStyle get title3 => GoogleFonts.getFont( | ||
| 27 | + 'Poppins', | ||
| 28 | + color: const Color(0xFF303030), | ||
| 29 | + fontWeight: FontWeight.w500, | ||
| 30 | + fontSize: 20, | ||
| 31 | + ); | ||
| 32 | + | ||
| 33 | + static TextStyle get subtitle1 => GoogleFonts.getFont( | ||
| 34 | + 'Poppins', | ||
| 35 | + color: const Color(0xFF757575), | ||
| 36 | + fontWeight: FontWeight.w500, | ||
| 37 | + fontSize: 18, | ||
| 38 | + ); | ||
| 39 | + | ||
| 40 | + static TextStyle get subtitle2 => GoogleFonts.getFont( | ||
| 41 | + 'Poppins', | ||
| 42 | + color: const Color(0xFF616161), | ||
| 43 | + fontWeight: FontWeight.normal, | ||
| 44 | + fontSize: 16, | ||
| 45 | + ); | ||
| 46 | + | ||
| 47 | + static TextStyle get bodyText1 => GoogleFonts.getFont( | ||
| 48 | + 'Poppins', | ||
| 49 | + color: const Color(0xFF303030), | ||
| 50 | + fontWeight: FontWeight.normal, | ||
| 51 | + fontSize: 14, | ||
| 52 | + ); | ||
| 53 | + | ||
| 54 | + static TextStyle get bodyText2 => GoogleFonts.getFont( | ||
| 55 | + 'Poppins', | ||
| 56 | + color: const Color(0xFF424242), | ||
| 57 | + fontWeight: FontWeight.normal, | ||
| 58 | + fontSize: 14, | ||
| 59 | + ); | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +extension TextStyleHelper on TextStyle { | ||
| 63 | + TextStyle override({ | ||
| 64 | + required String fontFamily, | ||
| 65 | + required Color color, | ||
| 66 | + double? fontSize, | ||
| 67 | + FontWeight? fontWeight, | ||
| 68 | + FontStyle? fontStyle, | ||
| 69 | + bool useGoogleFonts = true, | ||
| 70 | + }) => | ||
| 71 | + useGoogleFonts | ||
| 72 | + ? GoogleFonts.getFont( | ||
| 73 | + fontFamily, | ||
| 74 | + color: this.color, | ||
| 75 | + fontSize: fontSize ?? this.fontSize, | ||
| 76 | + fontWeight: fontWeight ?? this.fontWeight, | ||
| 77 | + fontStyle: fontStyle ?? this.fontStyle, | ||
| 78 | + ) | ||
| 79 | + : copyWith( | ||
| 80 | + fontFamily: fontFamily, | ||
| 81 | + color: color, | ||
| 82 | + fontSize: fontSize, | ||
| 83 | + fontWeight: fontWeight, | ||
| 84 | + fontStyle: fontStyle, | ||
| 85 | + ); | ||
| 86 | +} |
lib/poem/theme/tik_video_player.dart
0 → 100644
| 1 | +import 'package:chewie/chewie.dart'; | ||
| 2 | +import 'package:flutter/material.dart'; | ||
| 3 | +import 'package:flutter/services.dart'; | ||
| 4 | +import 'package:video_player/video_player.dart'; | ||
| 5 | + | ||
| 6 | +const kDefaultAspectRatio = 16 / 9; | ||
| 7 | + | ||
| 8 | +enum VideoType { | ||
| 9 | + asset, | ||
| 10 | + network, | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | +class TikVideoPlayer extends StatefulWidget { | ||
| 14 | + const TikVideoPlayer({ | ||
| 15 | + Key? key, | ||
| 16 | + required this.path, | ||
| 17 | + this.videoType = VideoType.network, | ||
| 18 | + this.width, | ||
| 19 | + this.height, | ||
| 20 | + this.aspectRatio, | ||
| 21 | + this.autoPlay = false, | ||
| 22 | + this.looping = false, | ||
| 23 | + this.showControls = true, | ||
| 24 | + this.allowFullScreen = true, | ||
| 25 | + this.allowPlaybackSpeedMenu = false, | ||
| 26 | + }) : super(key: key); | ||
| 27 | + | ||
| 28 | + final String path; | ||
| 29 | + final VideoType videoType; | ||
| 30 | + final double? width; | ||
| 31 | + final double? height; | ||
| 32 | + final double? aspectRatio; | ||
| 33 | + final bool autoPlay; | ||
| 34 | + final bool looping; | ||
| 35 | + final bool showControls; | ||
| 36 | + final bool allowFullScreen; | ||
| 37 | + final bool allowPlaybackSpeedMenu; | ||
| 38 | + | ||
| 39 | + @override | ||
| 40 | + State<StatefulWidget> createState() => _TikVideoPlayerState(); | ||
| 41 | +} | ||
| 42 | + | ||
| 43 | +class _TikVideoPlayerState extends State<TikVideoPlayer> { | ||
| 44 | + late VideoPlayerController _videoPlayerController; | ||
| 45 | + late ChewieController _chewieController; | ||
| 46 | + | ||
| 47 | + @override | ||
| 48 | + void initState() { | ||
| 49 | + super.initState(); | ||
| 50 | + initializePlayer(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @override | ||
| 54 | + void dispose() { | ||
| 55 | + _videoPlayerController.dispose(); | ||
| 56 | + _chewieController.dispose(); | ||
| 57 | + super.dispose(); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + double? get width => widget.width == null || widget.width! >= double.infinity | ||
| 61 | + ? MediaQuery.of(context).size.width | ||
| 62 | + : widget.width; | ||
| 63 | + | ||
| 64 | + double? get height => | ||
| 65 | + widget.height == null || widget.height! >= double.infinity | ||
| 66 | + ? (width != null ? width! / aspectRatio : null) | ||
| 67 | + : widget.height; | ||
| 68 | + | ||
| 69 | + double get aspectRatio => | ||
| 70 | + _chewieController.videoPlayerController.value.aspectRatio; | ||
| 71 | + | ||
| 72 | + Future initializePlayer() async { | ||
| 73 | + _videoPlayerController = widget.videoType == VideoType.network | ||
| 74 | + ? VideoPlayerController.network(widget.path) | ||
| 75 | + : VideoPlayerController.asset(widget.path); | ||
| 76 | + await _videoPlayerController.initialize(); | ||
| 77 | + _chewieController = ChewieController( | ||
| 78 | + videoPlayerController: _videoPlayerController, | ||
| 79 | + deviceOrientationsOnEnterFullScreen: [ | ||
| 80 | + DeviceOrientation.landscapeLeft, | ||
| 81 | + DeviceOrientation.landscapeRight, | ||
| 82 | + ], | ||
| 83 | + deviceOrientationsAfterFullScreen: [DeviceOrientation.portraitUp], | ||
| 84 | + aspectRatio: widget.aspectRatio, | ||
| 85 | + autoPlay: widget.autoPlay, | ||
| 86 | + looping: widget.looping, | ||
| 87 | + showControls: widget.showControls, | ||
| 88 | + allowFullScreen: widget.allowFullScreen, | ||
| 89 | + allowPlaybackSpeedChanging: widget.allowPlaybackSpeedMenu, | ||
| 90 | + ); | ||
| 91 | + setState(() {}); | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + @override | ||
| 95 | + Widget build(BuildContext context) => FittedBox( | ||
| 96 | + fit: BoxFit.cover, | ||
| 97 | + child: SizedBox( | ||
| 98 | + height: height, | ||
| 99 | + width: width, | ||
| 100 | + child: _chewieController.videoPlayerController.value.isInitialized | ||
| 101 | + ? Chewie(controller: _chewieController) | ||
| 102 | + : Column( | ||
| 103 | + mainAxisAlignment: MainAxisAlignment.center, | ||
| 104 | + children: const [ | ||
| 105 | + CircularProgressIndicator(), | ||
| 106 | + SizedBox(height: 20), | ||
| 107 | + Text('Loading'), | ||
| 108 | + ], | ||
| 109 | + ), | ||
| 110 | + ), | ||
| 111 | + ); | ||
| 112 | +} |
| 1 | +import 'package:Parlando/poem/components/nav_bar_page.dart'; | ||
| 1 | import 'package:fluro/fluro.dart'; | 2 | import 'package:fluro/fluro.dart'; |
| 2 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
| 3 | import 'package:Parlando/account/account_router.dart'; | 4 | import 'package:Parlando/account/account_router.dart'; |
| ... | @@ -15,6 +16,7 @@ import 'i_router.dart'; | ... | @@ -15,6 +16,7 @@ import 'i_router.dart'; |
| 15 | import 'not_found_page.dart'; | 16 | import 'not_found_page.dart'; |
| 16 | 17 | ||
| 17 | class Routes { | 18 | class Routes { |
| 19 | + static String navBarPage = '/nav/bar/page'; | ||
| 18 | static String home = '/home'; | 20 | static String home = '/home'; |
| 19 | static String webViewPage = '/webView'; | 21 | static String webViewPage = '/webView'; |
| 20 | 22 | ||
| ... | @@ -30,6 +32,12 @@ class Routes { | ... | @@ -30,6 +32,12 @@ class Routes { |
| 30 | return const NotFoundPage(); | 32 | return const NotFoundPage(); |
| 31 | }); | 33 | }); |
| 32 | 34 | ||
| 35 | + router.define(navBarPage, | ||
| 36 | + handler: Handler( | ||
| 37 | + handlerFunc: | ||
| 38 | + (BuildContext? context, Map<String, List<String>> params) => | ||
| 39 | + const NavBarPage(initialPage: 'HomePage'))); | ||
| 40 | + | ||
| 33 | router.define(home, | 41 | router.define(home, |
| 34 | handler: Handler( | 42 | handler: Handler( |
| 35 | handlerFunc: | 43 | handlerFunc: | ... | ... |
| ... | @@ -183,6 +183,13 @@ packages: | ... | @@ -183,6 +183,13 @@ packages: |
| 183 | url: "https://pub.flutter-io.cn" | 183 | url: "https://pub.flutter-io.cn" |
| 184 | source: hosted | 184 | source: hosted |
| 185 | version: "2.0.1" | 185 | version: "2.0.1" |
| 186 | + chewie: | ||
| 187 | + dependency: "direct main" | ||
| 188 | + description: | ||
| 189 | + name: chewie | ||
| 190 | + url: "https://pub.flutter-io.cn" | ||
| 191 | + source: hosted | ||
| 192 | + version: "1.3.4" | ||
| 186 | clock: | 193 | clock: |
| 187 | dependency: transitive | 194 | dependency: transitive |
| 188 | description: | 195 | description: |
| ... | @@ -572,6 +579,13 @@ packages: | ... | @@ -572,6 +579,13 @@ packages: |
| 572 | url: "https://pub.flutter-io.cn" | 579 | url: "https://pub.flutter-io.cn" |
| 573 | source: hosted | 580 | source: hosted |
| 574 | version: "2.1.0" | 581 | version: "2.1.0" |
| 582 | + google_fonts: | ||
| 583 | + dependency: "direct main" | ||
| 584 | + description: | ||
| 585 | + name: google_fonts | ||
| 586 | + url: "https://pub.flutter-io.cn" | ||
| 587 | + source: hosted | ||
| 588 | + version: "3.0.1" | ||
| 575 | graphs: | 589 | graphs: |
| 576 | dependency: transitive | 590 | dependency: transitive |
| 577 | description: | 591 | description: |
| ... | @@ -1506,6 +1520,41 @@ packages: | ... | @@ -1506,6 +1520,41 @@ packages: |
| 1506 | url: "https://pub.flutter-io.cn" | 1520 | url: "https://pub.flutter-io.cn" |
| 1507 | source: hosted | 1521 | source: hosted |
| 1508 | version: "8.2.2" | 1522 | version: "8.2.2" |
| 1523 | + wakelock: | ||
| 1524 | + dependency: transitive | ||
| 1525 | + description: | ||
| 1526 | + name: wakelock | ||
| 1527 | + url: "https://pub.flutter-io.cn" | ||
| 1528 | + source: hosted | ||
| 1529 | + version: "0.6.1+2" | ||
| 1530 | + wakelock_macos: | ||
| 1531 | + dependency: transitive | ||
| 1532 | + description: | ||
| 1533 | + name: wakelock_macos | ||
| 1534 | + url: "https://pub.flutter-io.cn" | ||
| 1535 | + source: hosted | ||
| 1536 | + version: "0.4.0" | ||
| 1537 | + wakelock_platform_interface: | ||
| 1538 | + dependency: transitive | ||
| 1539 | + description: | ||
| 1540 | + name: wakelock_platform_interface | ||
| 1541 | + url: "https://pub.flutter-io.cn" | ||
| 1542 | + source: hosted | ||
| 1543 | + version: "0.3.0" | ||
| 1544 | + wakelock_web: | ||
| 1545 | + dependency: transitive | ||
| 1546 | + description: | ||
| 1547 | + name: wakelock_web | ||
| 1548 | + url: "https://pub.flutter-io.cn" | ||
| 1549 | + source: hosted | ||
| 1550 | + version: "0.4.0" | ||
| 1551 | + wakelock_windows: | ||
| 1552 | + dependency: transitive | ||
| 1553 | + description: | ||
| 1554 | + name: wakelock_windows | ||
| 1555 | + url: "https://pub.flutter-io.cn" | ||
| 1556 | + source: hosted | ||
| 1557 | + version: "0.2.0" | ||
| 1509 | watcher: | 1558 | watcher: |
| 1510 | dependency: transitive | 1559 | dependency: transitive |
| 1511 | description: | 1560 | description: | ... | ... |
| ... | @@ -86,7 +86,8 @@ dependencies: | ... | @@ -86,7 +86,8 @@ dependencies: |
| 86 | url: 'https://gitee.com/reasonpun/flutter_2d_amap.git' | 86 | url: 'https://gitee.com/reasonpun/flutter_2d_amap.git' |
| 87 | 87 | ||
| 88 | # tiktok | 88 | # tiktok |
| 89 | - video_player: ^2.2.10 | 89 | + video_player: ^2.4.5 |
| 90 | + chewie: ^1.3.4 | ||
| 90 | # map取值 | 91 | # map取值 |
| 91 | safemap: ^2.0.0-nullsafety.0 | 92 | safemap: ^2.0.0-nullsafety.0 |
| 92 | # 基础的点击 | 93 | # 基础的点击 |
| ... | @@ -123,6 +124,9 @@ dependencies: | ... | @@ -123,6 +124,9 @@ dependencies: |
| 123 | image_gallery_saver: ^1.7.1 | 124 | image_gallery_saver: ^1.7.1 |
| 124 | 125 | ||
| 125 | flutter_easy_permission: ^1.1.2 | 126 | flutter_easy_permission: ^1.1.2 |
| 127 | + | ||
| 128 | + google_fonts: ^3.0.1 | ||
| 129 | + | ||
| 126 | dependency_overrides: | 130 | dependency_overrides: |
| 127 | decimal: 1.5.0 | 131 | decimal: 1.5.0 |
| 128 | 132 | ||
| ... | @@ -206,6 +210,7 @@ flutter: | ... | @@ -206,6 +210,7 @@ flutter: |
| 206 | - assets/images/membership/ | 210 | - assets/images/membership/ |
| 207 | - assets/images/share/ | 211 | - assets/images/share/ |
| 208 | - assets/data/ | 212 | - assets/data/ |
| 213 | + - assets/video/ | ||
| 209 | - assets/data/Data.json | 214 | - assets/data/Data.json |
| 210 | - assets/data/friends/ | 215 | - assets/data/friends/ |
| 211 | 216 | ... | ... |
-
Please register or login to post a comment