Showing
12 changed files
with
377 additions
and
540 deletions
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | -import 'package:flutter/cupertino.dart'; | ||
3 | - | ||
4 | import 'package:one_poem/extension/int_extension.dart'; | 2 | import 'package:one_poem/extension/int_extension.dart'; |
5 | import 'package:one_poem/widgets/my_app_bar.dart'; | 3 | import 'package:one_poem/widgets/my_app_bar.dart'; |
6 | import 'package:flutter_gen/gen_l10n/one_poem_localizations.dart'; | 4 | import 'package:flutter_gen/gen_l10n/one_poem_localizations.dart'; | ... | ... |
1 | import 'dart:ui'; | 1 | import 'dart:ui'; |
2 | 2 | ||
3 | -import 'package:flutter/cupertino.dart'; | ||
4 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
5 | import 'package:one_poem/category/models/category_item_entity.dart'; | 4 | import 'package:one_poem/category/models/category_item_entity.dart'; |
6 | import 'package:one_poem/poem/poem_router.dart'; | 5 | import 'package:one_poem/poem/poem_router.dart'; | ... | ... |
... | @@ -4,11 +4,8 @@ | ... | @@ -4,11 +4,8 @@ |
4 | 4 | ||
5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. | 5 | // This file is automatically generated. DO NOT EDIT, all your changes would be lost. |
6 | import 'package:one_poem/account/models/user_entity.dart'; | 6 | import 'package:one_poem/account/models/user_entity.dart'; |
7 | -import 'package:one_poem/generated/json/user_entity.g.dart'; | ||
8 | import 'package:one_poem/category/models/category_item_entity.dart'; | 7 | import 'package:one_poem/category/models/category_item_entity.dart'; |
9 | -import 'package:one_poem/generated/json/category_item_entity.g.dart'; | ||
10 | import 'package:one_poem/timeline/models/friend_entity.dart'; | 8 | import 'package:one_poem/timeline/models/friend_entity.dart'; |
11 | -import 'package:one_poem/generated/json/friend_entity.g.dart'; | ||
12 | 9 | ||
13 | JsonConvert jsonConvert = JsonConvert(); | 10 | JsonConvert jsonConvert = JsonConvert(); |
14 | 11 | ... | ... |
... | @@ -71,7 +71,9 @@ class _LoginPageState extends State<LoginPage> | ... | @@ -71,7 +71,9 @@ class _LoginPageState extends State<LoginPage> |
71 | "其他错误" | 71 | "其他错误" |
72 | ]; | 72 | ]; |
73 | 73 | ||
74 | - Future.delayed(Duration.zero, () { | 74 | + Future.delayed( |
75 | + Duration.zero, | ||
76 | + () { | ||
75 | NavigatorUtils.pushPageByFade( | 77 | NavigatorUtils.pushPageByFade( |
76 | context: context, | 78 | context: context, |
77 | //目标页面 | 79 | //目标页面 |
... | @@ -86,8 +88,10 @@ class _LoginPageState extends State<LoginPage> | ... | @@ -86,8 +88,10 @@ class _LoginPageState extends State<LoginPage> |
86 | //权限申请结果 | 88 | //权限申请结果 |
87 | dismissCallBack: (value) { | 89 | dismissCallBack: (value) { |
88 | showPrivacyPage(); | 90 | showPrivacyPage(); |
89 | - }); | 91 | + }, |
90 | - }); | 92 | + ); |
93 | + }, | ||
94 | + ); | ||
91 | } | 95 | } |
92 | 96 | ||
93 | void showPrivacyPage() async { | 97 | void showPrivacyPage() async { | ... | ... |
... | @@ -2,18 +2,24 @@ import 'dart:ui'; | ... | @@ -2,18 +2,24 @@ import 'dart:ui'; |
2 | 2 | ||
3 | import 'package:flutter/cupertino.dart'; | 3 | import 'package:flutter/cupertino.dart'; |
4 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
5 | +import 'package:flutter_sound/flutter_sound.dart'; | ||
5 | import 'package:one_poem/poem/widgets/poem_content.dart'; | 6 | import 'package:one_poem/poem/widgets/poem_content.dart'; |
6 | -import 'package:one_poem/recorder/audio/widgets/poem_voice_widget.dart'; | ||
7 | import 'package:one_poem/routers/fluro_navigator.dart'; | 7 | import 'package:one_poem/routers/fluro_navigator.dart'; |
8 | -import 'package:one_poem/util/toast_utils.dart'; | ||
9 | import 'package:one_poem/widgets/bars/home_action_bar.dart'; | 8 | import 'package:one_poem/widgets/bars/home_action_bar.dart'; |
10 | import 'package:one_poem/widgets/bars/home_menu_bar.dart'; | 9 | import 'package:one_poem/widgets/bars/home_menu_bar.dart'; |
11 | import 'package:one_poem/widgets/my_app_bar.dart'; | 10 | import 'package:one_poem/widgets/my_app_bar.dart'; |
12 | 11 | ||
13 | import 'package:one_poem/extension/int_extension.dart'; | 12 | import 'package:one_poem/extension/int_extension.dart'; |
13 | +import 'package:path_provider/path_provider.dart'; | ||
14 | +import 'package:pausable_timer/pausable_timer.dart'; | ||
15 | +import 'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart'; | ||
16 | +import 'package:flutter/foundation.dart' show kIsWeb; | ||
17 | +import 'package:permission_handler/permission_handler.dart'; | ||
14 | 18 | ||
15 | import '../poem_router.dart'; | 19 | import '../poem_router.dart'; |
16 | 20 | ||
21 | +const theSource = AudioSource.microphone; | ||
22 | + | ||
17 | class PoemRecordAudioPage extends StatefulWidget { | 23 | class PoemRecordAudioPage extends StatefulWidget { |
18 | @override | 24 | @override |
19 | State<StatefulWidget> createState() => _PoemRecordAudioPageState(); | 25 | State<StatefulWidget> createState() => _PoemRecordAudioPageState(); |
... | @@ -29,20 +35,33 @@ class PoemRecordAudioPage extends StatefulWidget { | ... | @@ -29,20 +35,33 @@ class PoemRecordAudioPage extends StatefulWidget { |
29 | } | 35 | } |
30 | 36 | ||
31 | class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { | 37 | class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { |
32 | - startRecord() { | 38 | + bool _isGetPoemInProgress = false; |
33 | - print("开始录制"); | 39 | + String poemStr = ''; |
40 | + | ||
41 | + @override | ||
42 | + void initState() { | ||
43 | + super.initState(); | ||
44 | + getPoem(); | ||
34 | } | 45 | } |
35 | 46 | ||
36 | - stopRecord(String path, double audioTimeLength) { | 47 | + Future<void> getPoem() async { |
37 | - print("结束束录制"); | 48 | + // TODO 等待套入正式接口发布临境 |
38 | - print("音频文件位置" + path); | 49 | + _isGetPoemInProgress = true; |
39 | - print("音频录制时长" + audioTimeLength.toString()); | 50 | + await Future.delayed(const Duration(seconds: 2), () { |
51 | + poemStr = | ||
52 | + "qīng chén rù gǔ sì\n清晨入古寺,\nchū rì zhào gāo lín\n初日照高林。\nzhú jìng tōng yōu chù\n竹径通幽处,\nchán fáng huā mù shēn\n禅房花木深。\nshān guāng yuè niǎo xìng\n山光悦鸟性,\ntán yǐng kōng rén xīn\n潭影空人心。\nwàn lài cǐ dōu jì\n万籁此都寂,\ndàn yú zhōng qìng yīn\n但余钟磬音。"; | ||
53 | + _isGetPoemInProgress = false; | ||
54 | + setState(() {}); | ||
55 | + }); | ||
56 | + } | ||
57 | + | ||
58 | + @override | ||
59 | + void dispose() { | ||
60 | + super.dispose(); | ||
40 | } | 61 | } |
41 | 62 | ||
42 | @override | 63 | @override |
43 | Widget build(BuildContext context) { | 64 | Widget build(BuildContext context) { |
44 | - const poemStr = | ||
45 | - "qīng chén rù gǔ sì\n清晨入古寺,\nchū rì zhào gāo lín\n初日照高林。\nzhú jìng tōng yōu chù\n竹径通幽处,\nchán fáng huā mù shēn\n禅房花木深。\nshān guāng yuè niǎo xìng\n山光悦鸟性,\ntán yǐng kōng rén xīn\n潭影空人心。\nwàn lài cǐ dōu jì\n万籁此都寂,\ndàn yú zhōng qìng yīn\n但余钟磬音。"; | ||
46 | return Scaffold( | 65 | return Scaffold( |
47 | appBar: MyAppBar( | 66 | appBar: MyAppBar( |
48 | isBack: true, | 67 | isBack: true, |
... | @@ -71,20 +90,28 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { | ... | @@ -71,20 +90,28 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { |
71 | ), | 90 | ), |
72 | ), | 91 | ), |
73 | child: SafeArea( | 92 | child: SafeArea( |
74 | - child: Column( | 93 | + child: _isGetPoemInProgress |
94 | + ? const Center( | ||
95 | + child: CupertinoActivityIndicator( | ||
96 | + radius: 16.0, | ||
97 | + ), | ||
98 | + ) | ||
99 | + : Column( | ||
75 | crossAxisAlignment: CrossAxisAlignment.start, | 100 | crossAxisAlignment: CrossAxisAlignment.start, |
76 | children: [ | 101 | children: [ |
77 | Container( | 102 | Container( |
78 | - margin: | 103 | + margin: EdgeInsets.symmetric( |
79 | - EdgeInsets.symmetric(vertical: 20.px, horizontal: 20.px), | 104 | + vertical: 20.px, horizontal: 20.px), |
80 | height: MediaQuery.of(context).size.height - | 105 | height: MediaQuery.of(context).size.height - |
81 | - 125.px - | 106 | + 100.px - |
82 | widget.poemPanelHeight, | 107 | widget.poemPanelHeight, |
83 | width: double.infinity, | 108 | width: double.infinity, |
84 | decoration: BoxDecoration( | 109 | decoration: BoxDecoration( |
85 | color: Colors.grey.shade200.withOpacity(0.1), | 110 | color: Colors.grey.shade200.withOpacity(0.1), |
86 | border: Border.all( | 111 | border: Border.all( |
87 | - color: Colors.grey.shade50, width: 0.5), // 边色与边宽度 | 112 | + color: Colors.grey.shade50, |
113 | + width: 0.5, | ||
114 | + ), // 边色与边宽度 | ||
88 | ), | 115 | ), |
89 | child: ClipRect( | 116 | child: ClipRect( |
90 | child: BackdropFilter( | 117 | child: BackdropFilter( |
... | @@ -108,68 +135,303 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { | ... | @@ -108,68 +135,303 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> { |
108 | poemStr: poemStr, | 135 | poemStr: poemStr, |
109 | fontSize: 22.px, | 136 | fontSize: 22.px, |
110 | ), | 137 | ), |
111 | - Stack( | 138 | + const AudioToolBar(), |
112 | - alignment: Alignment.center, | 139 | + ], |
113 | - children: [ | 140 | + ), |
114 | - Positioned( | 141 | + ), |
115 | - left: 10.px, | ||
116 | - child: IconButton( | ||
117 | - icon: Icon( | ||
118 | - Icons.camera_alt_outlined, | ||
119 | - size: 28.px, | ||
120 | ), | 142 | ), |
121 | - onPressed: () { | ||
122 | - Toast.show("不要着急吖,正在开发ing...."); | ||
123 | - }, | ||
124 | ), | 143 | ), |
125 | ), | 144 | ), |
126 | - SizedBox( | ||
127 | - width: double.infinity, | ||
128 | - height: 80.px, | ||
129 | - child: PoemVoiceWidget( | ||
130 | - startRecord: startRecord, | ||
131 | - stopRecord: stopRecord, | ||
132 | - // 加入定制化Container的相关属性 | ||
133 | - height: 40.px, | ||
134 | ), | 145 | ), |
135 | ), | 146 | ), |
136 | ], | 147 | ], |
137 | ), | 148 | ), |
138 | - Container( | ||
139 | - padding: const EdgeInsets.all(10.0), | ||
140 | - alignment: Alignment.centerRight, | ||
141 | - height: 54.0, | ||
142 | - width: double.infinity, | ||
143 | - child: TextButton( | ||
144 | - style: ButtonStyle( | ||
145 | - side: MaterialStateProperty.all( | ||
146 | - const BorderSide( | ||
147 | - color: Colors.black54, width: 1), | ||
148 | ), | 149 | ), |
149 | ), | 150 | ), |
150 | - onPressed: () { | 151 | + ); |
152 | + } | ||
153 | +} | ||
154 | + | ||
155 | +class AudioToolBar extends StatefulWidget { | ||
156 | + const AudioToolBar({ | ||
157 | + Key? key, | ||
158 | + }) : super(key: key); | ||
159 | + | ||
160 | + @override | ||
161 | + _AudioToolBarState createState() => _AudioToolBarState(); | ||
162 | +} | ||
163 | + | ||
164 | +class _AudioToolBarState extends State<AudioToolBar> { | ||
165 | + late final PausableTimer _timer; | ||
166 | + int currentTimer = 0; | ||
167 | + int duration = 10 * 1000; //TODO 60 * 1000; | ||
168 | + | ||
169 | + Codec _codec = Codec.aacMP4; | ||
170 | + String _mPath = 'tau_file.mp4'; | ||
171 | + FlutterSoundPlayer? _mPlayer = FlutterSoundPlayer(); | ||
172 | + FlutterSoundRecorder? _mRecorder = FlutterSoundRecorder(); | ||
173 | + bool _mPlayerIsInited = false; | ||
174 | + bool _mRecorderIsInited = false; | ||
175 | + bool _mPlaybackReady = false; | ||
176 | + bool _mRecorderIsRecording = false; | ||
177 | + bool _mRecorderIsPaused = false; | ||
178 | + | ||
179 | + @override | ||
180 | + void initState() { | ||
181 | + super.initState(); | ||
182 | + | ||
183 | + _mPlayer!.openAudioSession().then((value) { | ||
184 | + setState(() { | ||
185 | + _mPlayerIsInited = true; | ||
186 | + }); | ||
187 | + }); | ||
188 | + | ||
189 | + openTheRecorder().then((value) { | ||
190 | + setState(() { | ||
191 | + _mRecorderIsInited = true; | ||
192 | + }); | ||
193 | + }); | ||
194 | + | ||
195 | + _timer = PausableTimer( | ||
196 | + const Duration(milliseconds: 100), | ||
197 | + () { | ||
198 | + currentTimer += 100; | ||
199 | + _timer | ||
200 | + ..reset() | ||
201 | + ..start(); | ||
202 | + if (currentTimer >= duration) { | ||
203 | + _mRecorderIsRecording = false; | ||
204 | + stopRecorder(); | ||
205 | + } | ||
206 | + setState(() {}); | ||
207 | + }, | ||
208 | + ); | ||
209 | + } | ||
210 | + | ||
211 | + @override | ||
212 | + void dispose() { | ||
213 | + _mPlayer!.closeAudioSession(); | ||
214 | + _mPlayer = null; | ||
215 | + | ||
216 | + _mRecorder!.closeAudioSession(); | ||
217 | + _mRecorder = null; | ||
218 | + super.dispose(); | ||
219 | + } | ||
220 | + | ||
221 | + Future<void> openTheRecorder() async { | ||
222 | + if (!kIsWeb) { | ||
223 | + var status = await Permission.microphone.request(); | ||
224 | + if (status != PermissionStatus.granted) { | ||
225 | + //TODO 弹出授权提示框 | ||
226 | + throw RecordingPermissionException('Microphone permission not granted'); | ||
227 | + } | ||
228 | + } | ||
229 | + await _mRecorder!.openAudioSession(); | ||
230 | + if (!await _mRecorder!.isEncoderSupported(_codec) && kIsWeb) { | ||
231 | + final directory = await getApplicationDocumentsDirectory(); | ||
232 | + int currentUnix = DateTime.now().millisecondsSinceEpoch; | ||
233 | + _codec = Codec.opusWebM; //TODO 音频保存格式,mp3? | ||
234 | + _mPath = '${directory.path}/$currentUnix.webm'; | ||
235 | + if (!await _mRecorder!.isEncoderSupported(_codec) && kIsWeb) { | ||
236 | + _mRecorderIsInited = true; | ||
237 | + return; | ||
238 | + } | ||
239 | + } | ||
240 | + _mRecorderIsInited = true; | ||
241 | + } | ||
242 | + | ||
243 | + void record() { | ||
244 | + if (_mRecorderIsInited && _mPlayer!.isStopped) { | ||
245 | + currentTimer = 0; | ||
246 | + _timer | ||
247 | + ..reset() | ||
248 | + ..start(); | ||
249 | + _mRecorderIsRecording = true; | ||
250 | + _mRecorder! | ||
251 | + .startRecorder( | ||
252 | + toFile: _mPath, | ||
253 | + codec: _codec, | ||
254 | + audioSource: theSource, | ||
255 | + ) | ||
256 | + .then((value) { | ||
257 | + setState(() {}); | ||
258 | + }); | ||
259 | + } | ||
260 | + } | ||
261 | + | ||
262 | + void pauseRecorder() async { | ||
263 | + if (_mRecorderIsInited && _mPlayer!.isStopped) { | ||
264 | + _timer.pause(); | ||
265 | + _mRecorderIsPaused = true; | ||
266 | + await _mRecorder!.pauseRecorder().then((value) { | ||
267 | + setState(() {}); | ||
268 | + }); | ||
269 | + } | ||
270 | + } | ||
271 | + | ||
272 | + void resumeRecorder() async { | ||
273 | + if (_mRecorderIsInited && _mPlayer!.isStopped) { | ||
274 | + _timer.start(); | ||
275 | + await _mRecorder!.resumeRecorder().then((value) { | ||
276 | + _mRecorderIsPaused = false; | ||
277 | + setState(() {}); | ||
278 | + }); | ||
279 | + } | ||
280 | + } | ||
281 | + | ||
282 | + void stopRecorder() async { | ||
283 | + if (_mRecorderIsInited && _mPlayer!.isStopped) { | ||
284 | + print("### stop record"); | ||
285 | + | ||
286 | + _timer.pause(); | ||
287 | + await _mRecorder!.stopRecorder().then((value) { | ||
288 | + _mRecorderIsRecording = false; | ||
289 | + setState(() { | ||
290 | + _mPlaybackReady = true; | ||
291 | + }); | ||
292 | + }); | ||
293 | + } | ||
294 | + } | ||
295 | + | ||
296 | + void play() { | ||
297 | + if (_mPlayerIsInited && _mPlaybackReady && _mRecorder!.isStopped) { | ||
298 | + _mPlayer! | ||
299 | + .startPlayer( | ||
300 | + fromURI: _mPath, | ||
301 | + whenFinished: () { | ||
302 | + setState(() {}); | ||
303 | + }) | ||
304 | + .then((value) { | ||
305 | + setState(() {}); | ||
306 | + }); | ||
307 | + } | ||
308 | + } | ||
309 | + | ||
310 | + void stopPlayer() { | ||
311 | + if (_mPlayerIsInited && _mPlaybackReady && _mRecorder!.isStopped) { | ||
312 | + _mPlayer!.stopPlayer().then((value) { | ||
313 | + setState(() {}); | ||
314 | + }); | ||
315 | + } | ||
316 | + } | ||
317 | + | ||
318 | + @override | ||
319 | + Widget build(BuildContext context) { | ||
320 | + return Padding( | ||
321 | + padding: EdgeInsets.fromLTRB( | ||
322 | + 16.px, | ||
323 | + 8.px, | ||
324 | + 16.px, | ||
325 | + 8.px, | ||
326 | + ), | ||
327 | + child: Row( | ||
328 | + mainAxisAlignment: MainAxisAlignment.spaceBetween, | ||
329 | + crossAxisAlignment: CrossAxisAlignment.end, | ||
330 | + children: [ | ||
331 | + InkWell( | ||
332 | + onTap: () { | ||
333 | + if (_mRecorderIsRecording) { | ||
334 | + _mRecorderIsPaused ? resumeRecorder() : pauseRecorder(); | ||
335 | + } else { | ||
151 | NavigatorUtils.push( | 336 | NavigatorUtils.push( |
152 | context, | 337 | context, |
153 | - '${PoemRouter.poemPublish}?data=100', | 338 | + '${PoemRouter.poemRecordVideoPage}?id=100', |
154 | ); | 339 | ); |
340 | + } | ||
155 | }, | 341 | }, |
156 | - child: const Text( | 342 | + child: Stack( |
157 | - "下一步", | 343 | + alignment: Alignment.center, |
158 | - style: TextStyle(color: Colors.white), | 344 | + children: [ |
159 | - ), | 345 | + Icon( |
346 | + Icons.circle, | ||
347 | + color: Colors.black38, | ||
348 | + size: 60.px, | ||
160 | ), | 349 | ), |
350 | + _mRecorderIsRecording | ||
351 | + ? _mRecorderIsPaused | ||
352 | + ? Icon( | ||
353 | + Icons.play_arrow, | ||
354 | + color: Colors.white, | ||
355 | + size: 30.px, | ||
356 | + ) | ||
357 | + : Icon( | ||
358 | + Icons.pause, | ||
359 | + color: Colors.white, | ||
360 | + size: 30.px, | ||
361 | + ) | ||
362 | + : Icon( | ||
363 | + Icons.camera_alt_outlined, | ||
364 | + color: Colors.white, | ||
365 | + size: 30.px, | ||
161 | ), | 366 | ), |
162 | ], | 367 | ], |
163 | ), | 368 | ), |
164 | ), | 369 | ), |
370 | + InkWell( | ||
371 | + onTap: () { | ||
372 | + _mRecorderIsRecording ? stopRecorder() : record(); | ||
373 | + }, | ||
374 | + child: Stack( | ||
375 | + alignment: Alignment.center, | ||
376 | + children: [ | ||
377 | + Icon( | ||
378 | + Icons.circle, | ||
379 | + color: Colors.white, | ||
380 | + size: 80.px, | ||
381 | + ), | ||
382 | + _mRecorderIsRecording | ||
383 | + ? SizedBox( | ||
384 | + width: 60.px, | ||
385 | + height: 60.px, | ||
386 | + child: CircularProgressIndicator( | ||
387 | + strokeWidth: 5.px, | ||
388 | + value: currentTimer / duration, | ||
389 | + ), | ||
390 | + ) | ||
391 | + : Container(), | ||
392 | + Icon( | ||
393 | + Icons.circle, | ||
394 | + color: Colors.red, | ||
395 | + size: 65.px, | ||
165 | ), | 396 | ), |
397 | + _mRecorderIsRecording | ||
398 | + ? Container() | ||
399 | + : Text( | ||
400 | + "60s", | ||
401 | + style: TextStyle( | ||
402 | + fontSize: 12.px, | ||
403 | + color: Colors.white, | ||
166 | ), | 404 | ), |
167 | ), | 405 | ), |
406 | + _mRecorderIsRecording | ||
407 | + ? Icon( | ||
408 | + Icons.stop_rounded, | ||
409 | + color: Colors.white, | ||
410 | + size: 32.px, | ||
411 | + ) | ||
412 | + : Container(), | ||
413 | + ], | ||
414 | + ), | ||
415 | + ), | ||
416 | + InkWell( | ||
417 | + onTap: () {}, | ||
418 | + child: Stack( | ||
419 | + alignment: Alignment.center, | ||
420 | + children: [ | ||
421 | + Icon( | ||
422 | + Icons.circle, | ||
423 | + color: Colors.black38, | ||
424 | + size: 60.px, | ||
168 | ), | 425 | ), |
426 | + Icon( | ||
427 | + Icons.arrow_right_alt, | ||
428 | + color: Colors.white, | ||
429 | + size: 30.px, | ||
169 | ), | 430 | ), |
170 | ], | 431 | ], |
171 | ), | 432 | ), |
172 | ), | 433 | ), |
434 | + ], | ||
173 | ), | 435 | ), |
174 | ); | 436 | ); |
175 | } | 437 | } | ... | ... |
... | @@ -42,10 +42,7 @@ class _PoemRecordVideoPageState extends State<PoemRecordVideoPage> | ... | @@ -42,10 +42,7 @@ class _PoemRecordVideoPageState extends State<PoemRecordVideoPage> |
42 | 42 | ||
43 | List<CameraDescription>? cameras = []; | 43 | List<CameraDescription>? cameras = []; |
44 | 44 | ||
45 | - ///声明变量 | ||
46 | late final PausableTimer _timer; | 45 | late final PausableTimer _timer; |
47 | - | ||
48 | - ///记录当前的时间 | ||
49 | int currentTimer = 0; | 46 | int currentTimer = 0; |
50 | int duration = 10 * 1000; //TODO 60 * 1000; | 47 | int duration = 10 * 1000; //TODO 60 * 1000; |
51 | 48 | ... | ... |
1 | -import 'package:flutter/material.dart'; | ||
2 | - | ||
3 | -class CustomOverlay extends StatelessWidget { | ||
4 | - final Widget? icon; | ||
5 | - final BoxDecoration decoration; | ||
6 | - final double width; | ||
7 | - final double height; | ||
8 | - const CustomOverlay({ | ||
9 | - Key? key, | ||
10 | - this.icon, | ||
11 | - this.decoration = const BoxDecoration( | ||
12 | - color: Color(0xff77797A), | ||
13 | - borderRadius: BorderRadius.all(Radius.circular(20.0)), | ||
14 | - ), | ||
15 | - this.width = 160, | ||
16 | - this.height = 160, | ||
17 | - }) : super(key: key); | ||
18 | - | ||
19 | - @override | ||
20 | - Widget build(BuildContext context) { | ||
21 | - return Positioned( | ||
22 | - top: MediaQuery.of(context).size.height * 0.5 - width / 2, | ||
23 | - left: MediaQuery.of(context).size.width * 0.5 - height / 2, | ||
24 | - child: Material( | ||
25 | - type: MaterialType.transparency, | ||
26 | - child: Center( | ||
27 | - child: Opacity( | ||
28 | - opacity: 0.8, | ||
29 | - child: Container( | ||
30 | - width: width, | ||
31 | - height: height, | ||
32 | - decoration: decoration, | ||
33 | - child: icon, | ||
34 | - ), | ||
35 | - ), | ||
36 | - ), | ||
37 | - ), | ||
38 | - ); | ||
39 | - } | ||
40 | -} |
1 | -import 'dart:async'; | ||
2 | - | ||
3 | -import 'package:flutter/material.dart'; | ||
4 | -import 'package:flutter_plugin_record/flutter_plugin_record.dart'; | ||
5 | -import 'package:flutter_plugin_record/utils/common_toast.dart'; | ||
6 | - | ||
7 | -import 'custom_overlay.dart'; | ||
8 | - | ||
9 | -import 'package:one_poem/extension/int_extension.dart'; | ||
10 | - | ||
11 | -typedef StartRecord = Future Function(); | ||
12 | -typedef StopRecord = Future Function(); | ||
13 | - | ||
14 | -class PoemVoiceWidget extends StatefulWidget { | ||
15 | - final Function? startRecord; | ||
16 | - final Function? stopRecord; | ||
17 | - final double? height; | ||
18 | - final EdgeInsets? margin; | ||
19 | - final Decoration? decoration; | ||
20 | - | ||
21 | - /// startRecord 开始录制回调 stopRecord回调 | ||
22 | - const PoemVoiceWidget( | ||
23 | - {Key? key, | ||
24 | - this.startRecord, | ||
25 | - this.stopRecord, | ||
26 | - this.height, | ||
27 | - this.decoration, | ||
28 | - this.margin}) | ||
29 | - : super(key: key); | ||
30 | - | ||
31 | - @override | ||
32 | - _PoemVoiceWidgetState createState() => _PoemVoiceWidgetState(); | ||
33 | -} | ||
34 | - | ||
35 | -class _PoemVoiceWidgetState extends State<PoemVoiceWidget> { | ||
36 | - // 倒计时总时长 | ||
37 | - final int _countTotal = 12; | ||
38 | - double startY = 0.0; | ||
39 | - double offset = 0.0; | ||
40 | - bool isUp = false; | ||
41 | - String textShow = "按住说话"; | ||
42 | - String toastShow = "手指上滑,取消发送"; | ||
43 | - String voiceIco = "images/voice_volume_1.png"; | ||
44 | - | ||
45 | - ///默认隐藏状态 | ||
46 | - bool voiceState = true; | ||
47 | - FlutterPluginRecord? recordPlugin; | ||
48 | - Timer? _timer; | ||
49 | - int _count = 0; | ||
50 | - OverlayEntry? overlayEntry; | ||
51 | - | ||
52 | - String audioFilePath = ""; | ||
53 | - | ||
54 | - @override | ||
55 | - void initState() { | ||
56 | - super.initState(); | ||
57 | - recordPlugin = FlutterPluginRecord(); | ||
58 | - | ||
59 | - _init(); | ||
60 | - | ||
61 | - ///初始化方法的监听 | ||
62 | - recordPlugin?.responseFromInit.listen((data) { | ||
63 | - // if (data) { | ||
64 | - // print("初始化成功"); | ||
65 | - // } else { | ||
66 | - // print("初始化失败"); | ||
67 | - // } | ||
68 | - }); | ||
69 | - | ||
70 | - /// 开始录制或结束录制的监听 | ||
71 | - recordPlugin?.response.listen((data) { | ||
72 | - if (data.msg == "onStop") { | ||
73 | - ///结束录制时会返回录制文件的地址方便上传服务器 | ||
74 | - if (widget.stopRecord != null) { | ||
75 | - audioFilePath = data.path!; | ||
76 | - widget.stopRecord!(data.path, data.audioTimeLength); | ||
77 | - } | ||
78 | - } else if (data.msg == "onStart") { | ||
79 | - if (widget.startRecord != null) widget.startRecord!(); | ||
80 | - } | ||
81 | - }); | ||
82 | - | ||
83 | - ///录制过程监听录制的声音的大小 方便做语音动画显示图片的样式 | ||
84 | - recordPlugin!.responseFromAmplitude.listen((data) { | ||
85 | - var voiceData = double.parse(data.msg ?? ''); | ||
86 | - setState(() { | ||
87 | - if (voiceData > 0 && voiceData < 0.1) { | ||
88 | - voiceIco = "images/voice_volume_2.png"; | ||
89 | - } else if (voiceData > 0.2 && voiceData < 0.3) { | ||
90 | - voiceIco = "images/voice_volume_3.png"; | ||
91 | - } else if (voiceData > 0.3 && voiceData < 0.4) { | ||
92 | - voiceIco = "images/voice_volume_4.png"; | ||
93 | - } else if (voiceData > 0.4 && voiceData < 0.5) { | ||
94 | - voiceIco = "images/voice_volume_5.png"; | ||
95 | - } else if (voiceData > 0.5 && voiceData < 0.6) { | ||
96 | - voiceIco = "images/voice_volume_6.png"; | ||
97 | - } else if (voiceData > 0.6 && voiceData < 0.7) { | ||
98 | - voiceIco = "images/voice_volume_7.png"; | ||
99 | - } else if (voiceData > 0.7 && voiceData < 1) { | ||
100 | - voiceIco = "images/voice_volume_7.png"; | ||
101 | - } else { | ||
102 | - voiceIco = "images/voice_volume_1.png"; | ||
103 | - } | ||
104 | - if (overlayEntry != null) { | ||
105 | - overlayEntry!.markNeedsBuild(); | ||
106 | - } | ||
107 | - }); | ||
108 | - }); | ||
109 | - } | ||
110 | - | ||
111 | - ///显示录音悬浮布局 | ||
112 | - buildOverLayView(BuildContext context) { | ||
113 | - if (overlayEntry == null) { | ||
114 | - overlayEntry = OverlayEntry(builder: (content) { | ||
115 | - return CustomOverlay( | ||
116 | - icon: Column( | ||
117 | - children: <Widget>[ | ||
118 | - Container( | ||
119 | - margin: EdgeInsets.only(top: 10.px), | ||
120 | - child: _countTotal - _count < 11 | ||
121 | - ? Center( | ||
122 | - child: Padding( | ||
123 | - padding: EdgeInsets.only(bottom: 15.px), | ||
124 | - child: Text( | ||
125 | - (_countTotal - _count).toString(), | ||
126 | - style: TextStyle( | ||
127 | - fontSize: 70.px, | ||
128 | - color: Colors.white, | ||
129 | - ), | ||
130 | - ), | ||
131 | - ), | ||
132 | - ) | ||
133 | - : Image.asset( | ||
134 | - voiceIco, | ||
135 | - width: 100.px, | ||
136 | - height: 100.px, | ||
137 | - package: 'flutter_plugin_record', | ||
138 | - ), | ||
139 | - ), | ||
140 | - Text( | ||
141 | - toastShow, | ||
142 | - style: TextStyle( | ||
143 | - fontStyle: FontStyle.normal, | ||
144 | - color: Colors.white, | ||
145 | - fontSize: 14.px, | ||
146 | - ), | ||
147 | - ) | ||
148 | - ], | ||
149 | - ), | ||
150 | - ); | ||
151 | - }); | ||
152 | - Overlay.of(context)!.insert(overlayEntry!); | ||
153 | - } | ||
154 | - } | ||
155 | - | ||
156 | - showVoiceView() { | ||
157 | - setState(() { | ||
158 | - textShow = "松开结束"; | ||
159 | - voiceState = false; | ||
160 | - }); | ||
161 | - | ||
162 | - ///显示录音悬浮布局 | ||
163 | - buildOverLayView(context); | ||
164 | - | ||
165 | - start(); | ||
166 | - } | ||
167 | - | ||
168 | - hideVoiceView() { | ||
169 | - if (_timer!.isActive) { | ||
170 | - if (_count < 1) { | ||
171 | - CommonToast.showView( | ||
172 | - context: context, | ||
173 | - msg: '说话时间太短', | ||
174 | - icon: Text( | ||
175 | - '!', | ||
176 | - style: TextStyle(fontSize: 80.px, color: Colors.white), | ||
177 | - )); | ||
178 | - isUp = true; | ||
179 | - } | ||
180 | - _timer?.cancel(); | ||
181 | - _count = 0; | ||
182 | - } | ||
183 | - | ||
184 | - setState(() { | ||
185 | - textShow = "按住说话"; | ||
186 | - voiceState = true; | ||
187 | - }); | ||
188 | - | ||
189 | - stop(); | ||
190 | - if (overlayEntry != null) { | ||
191 | - overlayEntry?.remove(); | ||
192 | - overlayEntry = null; | ||
193 | - } | ||
194 | - | ||
195 | - // if (isUp) { | ||
196 | - // print("取消发送"); | ||
197 | - // } else { | ||
198 | - // print("进行发送"); | ||
199 | - // } | ||
200 | - } | ||
201 | - | ||
202 | - moveVoiceView() { | ||
203 | - setState(() { | ||
204 | - isUp = startY - offset > 100 ? true : false; | ||
205 | - if (isUp) { | ||
206 | - textShow = "松开手指,取消发送"; | ||
207 | - toastShow = textShow; | ||
208 | - } else { | ||
209 | - textShow = "松开结束"; | ||
210 | - toastShow = "手指上滑,取消发送"; | ||
211 | - } | ||
212 | - }); | ||
213 | - } | ||
214 | - | ||
215 | - ///初始化语音录制的方法 | ||
216 | - void _init() async { | ||
217 | - recordPlugin?.initRecordMp3(); | ||
218 | - } | ||
219 | - | ||
220 | - ///开始语音录制的方法 | ||
221 | - void start() async { | ||
222 | - recordPlugin?.start(); | ||
223 | - } | ||
224 | - | ||
225 | - ///停止语音录制的方法 | ||
226 | - void stop() { | ||
227 | - recordPlugin?.stop(); | ||
228 | - } | ||
229 | - | ||
230 | - @override | ||
231 | - Widget build(BuildContext context) { | ||
232 | - return Padding( | ||
233 | - padding: EdgeInsets.only(right: 10.px), | ||
234 | - child: Row( | ||
235 | - crossAxisAlignment: CrossAxisAlignment.center, | ||
236 | - mainAxisAlignment: MainAxisAlignment.end, | ||
237 | - children: [ | ||
238 | - GestureDetector( | ||
239 | - onLongPressStart: (details) { | ||
240 | - startY = details.globalPosition.dy; | ||
241 | - _timer = Timer.periodic(const Duration(milliseconds: 1000), (t) { | ||
242 | - _count++; | ||
243 | - if (_count == _countTotal) { | ||
244 | - hideVoiceView(); | ||
245 | - } | ||
246 | - }); | ||
247 | - showVoiceView(); | ||
248 | - }, | ||
249 | - onLongPressEnd: (details) { | ||
250 | - hideVoiceView(); | ||
251 | - }, | ||
252 | - onLongPressMoveUpdate: (details) { | ||
253 | - offset = details.globalPosition.dy; | ||
254 | - moveVoiceView(); | ||
255 | - }, | ||
256 | - child: Container( | ||
257 | - height: widget.height ?? 60.px, | ||
258 | - margin: | ||
259 | - widget.margin ?? EdgeInsets.fromLTRB(50.px, 0, 50.px, 20.px), | ||
260 | - child: Icon( | ||
261 | - Icons.mic_none, | ||
262 | - size: 70.px, | ||
263 | - color: Colors.black45.withOpacity(0.6), | ||
264 | - ), | ||
265 | - ), | ||
266 | - ), | ||
267 | - IconButton( | ||
268 | - icon: Icon( | ||
269 | - Icons.play_circle_outline, | ||
270 | - size: 28.px, | ||
271 | - ), | ||
272 | - onPressed: () { | ||
273 | - print("######:" + audioFilePath); | ||
274 | - recordPlugin!.playByPath(audioFilePath, "file"); | ||
275 | - }, | ||
276 | - ), | ||
277 | - ], | ||
278 | - ), | ||
279 | - ); | ||
280 | - } | ||
281 | - | ||
282 | - @override | ||
283 | - void dispose() { | ||
284 | - recordPlugin?.dispose(); | ||
285 | - _timer?.cancel(); | ||
286 | - super.dispose(); | ||
287 | - } | ||
288 | -} |
1 | -import 'dart:io'; | ||
2 | - | ||
3 | -import 'package:flutter/material.dart'; | ||
4 | -import 'preview_screen.dart'; | ||
5 | - | ||
6 | -class CapturesScreen extends StatelessWidget { | ||
7 | - final List<File> imageFileList; | ||
8 | - | ||
9 | - const CapturesScreen({ | ||
10 | - Key? key, | ||
11 | - required this.imageFileList, | ||
12 | - }) : super(key: key); | ||
13 | - | ||
14 | - @override | ||
15 | - Widget build(BuildContext context) { | ||
16 | - return Scaffold( | ||
17 | - backgroundColor: Colors.black, | ||
18 | - body: SingleChildScrollView( | ||
19 | - physics: const BouncingScrollPhysics(), | ||
20 | - child: Column( | ||
21 | - crossAxisAlignment: CrossAxisAlignment.start, | ||
22 | - children: [ | ||
23 | - const Padding( | ||
24 | - padding: EdgeInsets.all(16.0), | ||
25 | - child: Text( | ||
26 | - 'Captures', | ||
27 | - style: TextStyle( | ||
28 | - fontSize: 32.0, | ||
29 | - color: Colors.white, | ||
30 | - ), | ||
31 | - ), | ||
32 | - ), | ||
33 | - GridView.count( | ||
34 | - shrinkWrap: true, | ||
35 | - physics: const NeverScrollableScrollPhysics(), | ||
36 | - crossAxisCount: 2, | ||
37 | - children: [ | ||
38 | - for (File imageFile in imageFileList) | ||
39 | - Container( | ||
40 | - decoration: BoxDecoration( | ||
41 | - border: Border.all( | ||
42 | - color: Colors.black, | ||
43 | - width: 2, | ||
44 | - ), | ||
45 | - ), | ||
46 | - child: InkWell( | ||
47 | - onTap: () { | ||
48 | - Navigator.of(context).pushReplacement( | ||
49 | - MaterialPageRoute( | ||
50 | - builder: (context) => PreviewScreen( | ||
51 | - fileList: imageFileList, | ||
52 | - imageFile: imageFile, | ||
53 | - ), | ||
54 | - ), | ||
55 | - ); | ||
56 | - }, | ||
57 | - child: Image.file( | ||
58 | - imageFile, | ||
59 | - fit: BoxFit.cover, | ||
60 | - ), | ||
61 | - ), | ||
62 | - ), | ||
63 | - ], | ||
64 | - ), | ||
65 | - ], | ||
66 | - ), | ||
67 | - ), | ||
68 | - ); | ||
69 | - } | ||
70 | -} |
1 | -import 'dart:io'; | ||
2 | - | ||
3 | -import 'package:flutter/material.dart'; | ||
4 | - | ||
5 | -import 'captures_screen.dart'; | ||
6 | - | ||
7 | -class PreviewScreen extends StatelessWidget { | ||
8 | - final File imageFile; | ||
9 | - final List<File> fileList; | ||
10 | - | ||
11 | - const PreviewScreen({ | ||
12 | - Key? key, | ||
13 | - required this.imageFile, | ||
14 | - required this.fileList, | ||
15 | - }) : super(key: key); | ||
16 | - | ||
17 | - @override | ||
18 | - Widget build(BuildContext context) { | ||
19 | - return Scaffold( | ||
20 | - backgroundColor: Colors.black, | ||
21 | - body: Column( | ||
22 | - crossAxisAlignment: CrossAxisAlignment.start, | ||
23 | - children: [ | ||
24 | - Padding( | ||
25 | - padding: const EdgeInsets.all(8.0), | ||
26 | - child: TextButton( | ||
27 | - onPressed: () { | ||
28 | - Navigator.of(context).pushReplacement( | ||
29 | - MaterialPageRoute( | ||
30 | - builder: (context) => CapturesScreen( | ||
31 | - imageFileList: fileList, | ||
32 | - ), | ||
33 | - ), | ||
34 | - ); | ||
35 | - }, | ||
36 | - child: const Text('打开全部视频'), | ||
37 | - style: TextButton.styleFrom( | ||
38 | - primary: Colors.black, | ||
39 | - backgroundColor: Colors.white, | ||
40 | - ), | ||
41 | - ), | ||
42 | - ), | ||
43 | - Expanded( | ||
44 | - child: Image.file(imageFile), | ||
45 | - ), | ||
46 | - ], | ||
47 | - ), | ||
48 | - ); | ||
49 | - } | ||
50 | -} |
... | @@ -21,7 +21,7 @@ packages: | ... | @@ -21,7 +21,7 @@ packages: |
21 | name: archive | 21 | name: archive |
22 | url: "https://pub.dartlang.org" | 22 | url: "https://pub.dartlang.org" |
23 | source: hosted | 23 | source: hosted |
24 | - version: "3.1.2" | 24 | + version: "3.1.6" |
25 | args: | 25 | args: |
26 | dependency: transitive | 26 | dependency: transitive |
27 | description: | 27 | description: |
... | @@ -35,7 +35,7 @@ packages: | ... | @@ -35,7 +35,7 @@ packages: |
35 | name: async | 35 | name: async |
36 | url: "https://pub.dartlang.org" | 36 | url: "https://pub.dartlang.org" |
37 | source: hosted | 37 | source: hosted |
38 | - version: "2.8.1" | 38 | + version: "2.8.2" |
39 | boolean_selector: | 39 | boolean_selector: |
40 | dependency: transitive | 40 | dependency: transitive |
41 | description: | 41 | description: |
... | @@ -126,14 +126,14 @@ packages: | ... | @@ -126,14 +126,14 @@ packages: |
126 | name: camera | 126 | name: camera |
127 | url: "https://pub.dartlang.org" | 127 | url: "https://pub.dartlang.org" |
128 | source: hosted | 128 | source: hosted |
129 | - version: "0.9.4+6" | 129 | + version: "0.9.4+7" |
130 | camera_platform_interface: | 130 | camera_platform_interface: |
131 | dependency: transitive | 131 | dependency: transitive |
132 | description: | 132 | description: |
133 | name: camera_platform_interface | 133 | name: camera_platform_interface |
134 | url: "https://pub.dartlang.org" | 134 | url: "https://pub.dartlang.org" |
135 | source: hosted | 135 | source: hosted |
136 | - version: "2.1.4" | 136 | + version: "2.1.5" |
137 | camera_web: | 137 | camera_web: |
138 | dependency: transitive | 138 | dependency: transitive |
139 | description: | 139 | description: |
... | @@ -147,7 +147,7 @@ packages: | ... | @@ -147,7 +147,7 @@ packages: |
147 | name: characters | 147 | name: characters |
148 | url: "https://pub.dartlang.org" | 148 | url: "https://pub.dartlang.org" |
149 | source: hosted | 149 | source: hosted |
150 | - version: "1.1.0" | 150 | + version: "1.2.0" |
151 | charcode: | 151 | charcode: |
152 | dependency: transitive | 152 | dependency: transitive |
153 | description: | 153 | description: |
... | @@ -400,7 +400,7 @@ packages: | ... | @@ -400,7 +400,7 @@ packages: |
400 | name: flutter_native_splash | 400 | name: flutter_native_splash |
401 | url: "https://pub.dartlang.org" | 401 | url: "https://pub.dartlang.org" |
402 | source: hosted | 402 | source: hosted |
403 | - version: "1.3.2" | 403 | + version: "1.3.3" |
404 | flutter_plugin_android_lifecycle: | 404 | flutter_plugin_android_lifecycle: |
405 | dependency: transitive | 405 | dependency: transitive |
406 | description: | 406 | description: |
... | @@ -408,20 +408,34 @@ packages: | ... | @@ -408,20 +408,34 @@ packages: |
408 | url: "https://pub.dartlang.org" | 408 | url: "https://pub.dartlang.org" |
409 | source: hosted | 409 | source: hosted |
410 | version: "2.0.5" | 410 | version: "2.0.5" |
411 | - flutter_plugin_record: | 411 | + flutter_slidable: |
412 | dependency: "direct main" | 412 | dependency: "direct main" |
413 | description: | 413 | description: |
414 | - name: flutter_plugin_record | 414 | + name: flutter_slidable |
415 | url: "https://pub.dartlang.org" | 415 | url: "https://pub.dartlang.org" |
416 | source: hosted | 416 | source: hosted |
417 | - version: "1.0.1" | 417 | + version: "1.2.0" |
418 | - flutter_slidable: | 418 | + flutter_sound: |
419 | dependency: "direct main" | 419 | dependency: "direct main" |
420 | description: | 420 | description: |
421 | - name: flutter_slidable | 421 | + name: flutter_sound |
422 | url: "https://pub.dartlang.org" | 422 | url: "https://pub.dartlang.org" |
423 | source: hosted | 423 | source: hosted |
424 | - version: "1.2.0" | 424 | + version: "8.5.0" |
425 | + flutter_sound_platform_interface: | ||
426 | + dependency: transitive | ||
427 | + description: | ||
428 | + name: flutter_sound_platform_interface | ||
429 | + url: "https://pub.dartlang.org" | ||
430 | + source: hosted | ||
431 | + version: "8.5.0" | ||
432 | + flutter_sound_web: | ||
433 | + dependency: transitive | ||
434 | + description: | ||
435 | + name: flutter_sound_web | ||
436 | + url: "https://pub.dartlang.org" | ||
437 | + source: hosted | ||
438 | + version: "8.5.0" | ||
425 | flutter_spinkit: | 439 | flutter_spinkit: |
426 | dependency: "direct main" | 440 | dependency: "direct main" |
427 | description: | 441 | description: |
... | @@ -513,7 +527,7 @@ packages: | ... | @@ -513,7 +527,7 @@ packages: |
513 | name: image_picker | 527 | name: image_picker |
514 | url: "https://pub.dartlang.org" | 528 | url: "https://pub.dartlang.org" |
515 | source: hosted | 529 | source: hosted |
516 | - version: "0.8.4+4" | 530 | + version: "0.8.4+5" |
517 | image_picker_for_web: | 531 | image_picker_for_web: |
518 | dependency: transitive | 532 | dependency: transitive |
519 | description: | 533 | description: |
... | @@ -582,6 +596,13 @@ packages: | ... | @@ -582,6 +596,13 @@ packages: |
582 | url: "https://pub.dartlang.org" | 596 | url: "https://pub.dartlang.org" |
583 | source: hosted | 597 | source: hosted |
584 | version: "1.0.1" | 598 | version: "1.0.1" |
599 | + logger: | ||
600 | + dependency: transitive | ||
601 | + description: | ||
602 | + name: logger | ||
603 | + url: "https://pub.dartlang.org" | ||
604 | + source: hosted | ||
605 | + version: "1.1.0" | ||
585 | logging: | 606 | logging: |
586 | dependency: transitive | 607 | dependency: transitive |
587 | description: | 608 | description: |
... | @@ -595,7 +616,7 @@ packages: | ... | @@ -595,7 +616,7 @@ packages: |
595 | name: matcher | 616 | name: matcher |
596 | url: "https://pub.dartlang.org" | 617 | url: "https://pub.dartlang.org" |
597 | source: hosted | 618 | source: hosted |
598 | - version: "0.12.10" | 619 | + version: "0.12.11" |
599 | meta: | 620 | meta: |
600 | dependency: transitive | 621 | dependency: transitive |
601 | description: | 622 | description: |
... | @@ -742,7 +763,7 @@ packages: | ... | @@ -742,7 +763,7 @@ packages: |
742 | name: platform | 763 | name: platform |
743 | url: "https://pub.dartlang.org" | 764 | url: "https://pub.dartlang.org" |
744 | source: hosted | 765 | source: hosted |
745 | - version: "3.0.0" | 766 | + version: "3.0.2" |
746 | plugin_platform_interface: | 767 | plugin_platform_interface: |
747 | dependency: transitive | 768 | dependency: transitive |
748 | description: | 769 | description: |
... | @@ -763,7 +784,7 @@ packages: | ... | @@ -763,7 +784,7 @@ packages: |
763 | name: process | 784 | name: process |
764 | url: "https://pub.dartlang.org" | 785 | url: "https://pub.dartlang.org" |
765 | source: hosted | 786 | source: hosted |
766 | - version: "4.2.3" | 787 | + version: "4.2.4" |
767 | provider: | 788 | provider: |
768 | dependency: "direct main" | 789 | dependency: "direct main" |
769 | description: | 790 | description: |
... | @@ -820,6 +841,13 @@ packages: | ... | @@ -820,6 +841,13 @@ packages: |
820 | url: "https://pub.dartlang.org" | 841 | url: "https://pub.dartlang.org" |
821 | source: hosted | 842 | source: hosted |
822 | version: "1.2.1" | 843 | version: "1.2.1" |
844 | + recase: | ||
845 | + dependency: transitive | ||
846 | + description: | ||
847 | + name: recase | ||
848 | + url: "https://pub.dartlang.org" | ||
849 | + source: hosted | ||
850 | + version: "4.0.0" | ||
823 | rxdart: | 851 | rxdart: |
824 | dependency: "direct main" | 852 | dependency: "direct main" |
825 | description: | 853 | description: |
... | @@ -985,7 +1013,7 @@ packages: | ... | @@ -985,7 +1013,7 @@ packages: |
985 | name: sqflite_common | 1013 | name: sqflite_common |
986 | url: "https://pub.dartlang.org" | 1014 | url: "https://pub.dartlang.org" |
987 | source: hosted | 1015 | source: hosted |
988 | - version: "2.0.1+1" | 1016 | + version: "2.2.0" |
989 | stack_trace: | 1017 | stack_trace: |
990 | dependency: transitive | 1018 | dependency: transitive |
991 | description: | 1019 | description: |
... | @@ -1055,21 +1083,21 @@ packages: | ... | @@ -1055,21 +1083,21 @@ packages: |
1055 | name: test | 1083 | name: test |
1056 | url: "https://pub.dartlang.org" | 1084 | url: "https://pub.dartlang.org" |
1057 | source: hosted | 1085 | source: hosted |
1058 | - version: "1.17.10" | 1086 | + version: "1.17.12" |
1059 | test_api: | 1087 | test_api: |
1060 | dependency: transitive | 1088 | dependency: transitive |
1061 | description: | 1089 | description: |
1062 | name: test_api | 1090 | name: test_api |
1063 | url: "https://pub.dartlang.org" | 1091 | url: "https://pub.dartlang.org" |
1064 | source: hosted | 1092 | source: hosted |
1065 | - version: "0.4.2" | 1093 | + version: "0.4.3" |
1066 | test_core: | 1094 | test_core: |
1067 | dependency: transitive | 1095 | dependency: transitive |
1068 | description: | 1096 | description: |
1069 | name: test_core | 1097 | name: test_core |
1070 | url: "https://pub.dartlang.org" | 1098 | url: "https://pub.dartlang.org" |
1071 | source: hosted | 1099 | source: hosted |
1072 | - version: "0.4.0" | 1100 | + version: "0.4.2" |
1073 | timing: | 1101 | timing: |
1074 | dependency: transitive | 1102 | dependency: transitive |
1075 | description: | 1103 | description: |
... | @@ -1097,7 +1125,7 @@ packages: | ... | @@ -1097,7 +1125,7 @@ packages: |
1097 | name: url_launcher | 1125 | name: url_launcher |
1098 | url: "https://pub.dartlang.org" | 1126 | url: "https://pub.dartlang.org" |
1099 | source: hosted | 1127 | source: hosted |
1100 | - version: "6.0.17" | 1128 | + version: "6.0.18" |
1101 | url_launcher_android: | 1129 | url_launcher_android: |
1102 | dependency: transitive | 1130 | dependency: transitive |
1103 | description: | 1131 | description: |
... | @@ -1167,7 +1195,7 @@ packages: | ... | @@ -1167,7 +1195,7 @@ packages: |
1167 | name: vector_math | 1195 | name: vector_math |
1168 | url: "https://pub.dartlang.org" | 1196 | url: "https://pub.dartlang.org" |
1169 | source: hosted | 1197 | source: hosted |
1170 | - version: "2.1.0" | 1198 | + version: "2.1.1" |
1171 | vibration: | 1199 | vibration: |
1172 | dependency: "direct main" | 1200 | dependency: "direct main" |
1173 | description: | 1201 | description: |
... | @@ -1209,7 +1237,7 @@ packages: | ... | @@ -1209,7 +1237,7 @@ packages: |
1209 | name: vm_service | 1237 | name: vm_service |
1210 | url: "https://pub.dartlang.org" | 1238 | url: "https://pub.dartlang.org" |
1211 | source: hosted | 1239 | source: hosted |
1212 | - version: "7.1.1" | 1240 | + version: "7.3.0" |
1213 | watcher: | 1241 | watcher: |
1214 | dependency: transitive | 1242 | dependency: transitive |
1215 | description: | 1243 | description: |
... | @@ -1272,7 +1300,7 @@ packages: | ... | @@ -1272,7 +1300,7 @@ packages: |
1272 | name: win32 | 1300 | name: win32 |
1273 | url: "https://pub.dartlang.org" | 1301 | url: "https://pub.dartlang.org" |
1274 | source: hosted | 1302 | source: hosted |
1275 | - version: "2.3.6" | 1303 | + version: "2.3.8" |
1276 | xdg_directories: | 1304 | xdg_directories: |
1277 | dependency: transitive | 1305 | dependency: transitive |
1278 | description: | 1306 | description: |
... | @@ -1295,5 +1323,5 @@ packages: | ... | @@ -1295,5 +1323,5 @@ packages: |
1295 | source: hosted | 1323 | source: hosted |
1296 | version: "3.1.0" | 1324 | version: "3.1.0" |
1297 | sdks: | 1325 | sdks: |
1298 | - dart: ">=2.14.0 <3.0.0" | 1326 | + dart: ">=2.15.1 <3.0.0" |
1299 | flutter: ">=2.5.0" | 1327 | flutter: ">=2.5.0" | ... | ... |
... | @@ -50,9 +50,9 @@ dependencies: | ... | @@ -50,9 +50,9 @@ dependencies: |
50 | # Flutter 轮播图 https://github.com/lianyagang/flutter_swiper_null_safety | 50 | # Flutter 轮播图 https://github.com/lianyagang/flutter_swiper_null_safety |
51 | flutter_swiper_null_safety: ^1.0.2 # flutter_swiper很久不维护,可以使用空安全版本:flutter_swiper_null_safety | 51 | flutter_swiper_null_safety: ^1.0.2 # flutter_swiper很久不维护,可以使用空安全版本:flutter_swiper_null_safety |
52 | # 启动URL的插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/url_launcher | 52 | # 启动URL的插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/url_launcher |
53 | - url_launcher: 6.0.17 | 53 | + url_launcher: ^6.0.18 |
54 | # 图片选择插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/image_picker | 54 | # 图片选择插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/image_picker |
55 | - image_picker: 0.8.4+4 | 55 | + image_picker: ^0.8.4+5 |
56 | # 侧滑删除 https://github.com/letsar/flutter_slidable | 56 | # 侧滑删除 https://github.com/letsar/flutter_slidable |
57 | flutter_slidable: ^1.1.0 | 57 | flutter_slidable: ^1.1.0 |
58 | # WebView插件 https://github.com/flutter/plugins/tree/master/packages/webview_flutter | 58 | # WebView插件 https://github.com/flutter/plugins/tree/master/packages/webview_flutter |
... | @@ -91,12 +91,12 @@ dependencies: | ... | @@ -91,12 +91,12 @@ dependencies: |
91 | flutter_spinkit: ^5.0.0 | 91 | flutter_spinkit: ^5.0.0 |
92 | 92 | ||
93 | json_annotation: ^4.4.0 | 93 | json_annotation: ^4.4.0 |
94 | - flutter_plugin_record: ^1.0.1 | 94 | + flutter_sound: ^8.5.0 |
95 | 95 | ||
96 | # fijkplayer (Video player plugin for Flutter) Flutter 媒体播放器 | 96 | # fijkplayer (Video player plugin for Flutter) Flutter 媒体播放器 |
97 | fijkplayer: ^0.10.1 | 97 | fijkplayer: ^0.10.1 |
98 | 98 | ||
99 | - camera: ^0.9.4+5 | 99 | + camera: ^0.9.4+7 |
100 | path_provider: ^2.0.8 | 100 | path_provider: ^2.0.8 |
101 | 101 | ||
102 | # A Dart timer that can be paused, resumed and reset. | 102 | # A Dart timer that can be paused, resumed and reset. | ... | ... |
-
Please register or login to post a comment