Showing
15 changed files
with
700 additions
and
75 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, | ||
90 | + ), | ||
91 | + ), | ||
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 | + ), | ||
81 | ), | 109 | ), |
82 | ), | 110 | ), |
83 | - ), | 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