Toggle navigation
Toggle navigation
This project
Loading...
Sign in
OnePoem
/
OnePoem-App
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
Reason Pun
2022-01-26 22:02:50 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
53d45ce26abec44b96741c79322858b2672f35fa
53d45ce2
1 parent
a0d883f9
重构了录音页面功能
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
424 additions
and
587 deletions
lib/account/page/account_edit_page.dart
lib/category/widgets/category_item.dart
lib/generated/json/base/json_convert_content.dart
lib/login/page/login_page.dart
lib/poem/page/poem_record_audio.dart
lib/poem/page/poem_record_video.dart
lib/recorder/audio/widgets/custom_overlay.dart
lib/recorder/audio/widgets/poem_voice_widget.dart
lib/recorder/video/captures_screen.dart
lib/recorder/video/preview_screen.dart
pubspec.lock
pubspec.yaml
lib/account/page/account_edit_page.dart
View file @
53d45ce
import
'package:flutter/material.dart'
;
import
'package:flutter/cupertino.dart'
;
import
'package:one_poem/extension/int_extension.dart'
;
import
'package:one_poem/widgets/my_app_bar.dart'
;
import
'package:flutter_gen/gen_l10n/one_poem_localizations.dart'
;
...
...
lib/category/widgets/category_item.dart
View file @
53d45ce
import
'dart:ui'
;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
import
'package:one_poem/category/models/category_item_entity.dart'
;
import
'package:one_poem/poem/poem_router.dart'
;
...
...
lib/generated/json/base/json_convert_content.dart
View file @
53d45ce
...
...
@@ -4,11 +4,8 @@
// This file is automatically generated. DO NOT EDIT, all your changes would be lost.
import
'package:one_poem/account/models/user_entity.dart'
;
import
'package:one_poem/generated/json/user_entity.g.dart'
;
import
'package:one_poem/category/models/category_item_entity.dart'
;
import
'package:one_poem/generated/json/category_item_entity.g.dart'
;
import
'package:one_poem/timeline/models/friend_entity.dart'
;
import
'package:one_poem/generated/json/friend_entity.g.dart'
;
JsonConvert
jsonConvert
=
JsonConvert
();
...
...
lib/login/page/login_page.dart
View file @
53d45ce
...
...
@@ -71,8 +71,10 @@ class _LoginPageState extends State<LoginPage>
"其他错误"
];
Future
.
delayed
(
Duration
.
zero
,
()
{
NavigatorUtils
.
pushPageByFade
(
Future
.
delayed
(
Duration
.
zero
,
()
{
NavigatorUtils
.
pushPageByFade
(
context:
context
,
//目标页面
targetPage:
PermissionRequestWidget
(
...
...
@@ -86,8 +88,10 @@ class _LoginPageState extends State<LoginPage>
//权限申请结果
dismissCallBack:
(
value
)
{
showPrivacyPage
();
});
});
},
);
},
);
}
void
showPrivacyPage
()
async
{
...
...
lib/poem/page/poem_record_audio.dart
View file @
53d45ce
...
...
@@ -2,18 +2,24 @@ import 'dart:ui';
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_sound/flutter_sound.dart'
;
import
'package:one_poem/poem/widgets/poem_content.dart'
;
import
'package:one_poem/recorder/audio/widgets/poem_voice_widget.dart'
;
import
'package:one_poem/routers/fluro_navigator.dart'
;
import
'package:one_poem/util/toast_utils.dart'
;
import
'package:one_poem/widgets/bars/home_action_bar.dart'
;
import
'package:one_poem/widgets/bars/home_menu_bar.dart'
;
import
'package:one_poem/widgets/my_app_bar.dart'
;
import
'package:one_poem/extension/int_extension.dart'
;
import
'package:path_provider/path_provider.dart'
;
import
'package:pausable_timer/pausable_timer.dart'
;
import
'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart'
;
import
'package:flutter/foundation.dart'
show
kIsWeb
;
import
'package:permission_handler/permission_handler.dart'
;
import
'../poem_router.dart'
;
const
theSource
=
AudioSource
.
microphone
;
class
PoemRecordAudioPage
extends
StatefulWidget
{
@override
State
<
StatefulWidget
>
createState
()
=>
_PoemRecordAudioPageState
();
...
...
@@ -29,20 +35,33 @@ class PoemRecordAudioPage extends StatefulWidget {
}
class
_PoemRecordAudioPageState
extends
State
<
PoemRecordAudioPage
>
{
startRecord
()
{
print
(
"开始录制"
);
bool
_isGetPoemInProgress
=
false
;
String
poemStr
=
''
;
@override
void
initState
()
{
super
.
initState
();
getPoem
();
}
stopRecord
(
String
path
,
double
audioTimeLength
)
{
print
(
"结束束录制"
);
print
(
"音频文件位置"
+
path
);
print
(
"音频录制时长"
+
audioTimeLength
.
toString
());
Future
<
void
>
getPoem
()
async
{
// TODO 等待套入正式接口发布临境
_isGetPoemInProgress
=
true
;
await
Future
.
delayed
(
const
Duration
(
seconds:
2
),
()
{
poemStr
=
"qīng chén rù gǔ sì
\n
清晨入古寺,
\n
chū rì zhào gāo lín
\n
初日照高林。
\n
zhú jìng tōng yōu chù
\n
竹径通幽处,
\n
chán fáng huā mù shēn
\n
禅房花木深。
\n
shān guāng yuè niǎo xìng
\n
山光悦鸟性,
\n
tán yǐng kōng rén xīn
\n
潭影空人心。
\n
wàn lài cǐ dōu jì
\n
万籁此都寂,
\n
dàn yú zhōng qìng yīn
\n
但余钟磬音。"
;
_isGetPoemInProgress
=
false
;
setState
(()
{});
});
}
@override
void
dispose
()
{
super
.
dispose
();
}
@override
Widget
build
(
BuildContext
context
)
{
const
poemStr
=
"qīng chén rù gǔ sì
\n
清晨入古寺,
\n
chū rì zhào gāo lín
\n
初日照高林。
\n
zhú jìng tōng yōu chù
\n
竹径通幽处,
\n
chán fáng huā mù shēn
\n
禅房花木深。
\n
shān guāng yuè niǎo xìng
\n
山光悦鸟性,
\n
tán yǐng kōng rén xīn
\n
潭影空人心。
\n
wàn lài cǐ dōu jì
\n
万籁此都寂,
\n
dàn yú zhōng qìng yīn
\n
但余钟磬音。"
;
return
Scaffold
(
appBar:
MyAppBar
(
isBack:
true
,
...
...
@@ -71,106 +90,349 @@ class _PoemRecordAudioPageState extends State<PoemRecordAudioPage> {
),
),
child:
SafeArea
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Container
(
margin:
EdgeInsets
.
symmetric
(
vertical:
20
.
px
,
horizontal:
20
.
px
),
height:
MediaQuery
.
of
(
context
).
size
.
height
-
125
.
px
-
widget
.
poemPanelHeight
,
width:
double
.
infinity
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade200
.
withOpacity
(
0.1
),
border:
Border
.
all
(
color:
Colors
.
grey
.
shade50
,
width:
0.5
),
// 边色与边宽度
),
child:
ClipRect
(
child:
BackdropFilter
(
filter:
ImageFilter
.
blur
(
sigmaX:
10.0
,
sigmaY:
10.0
,
),
child:
Container
(
child:
_isGetPoemInProgress
?
const
Center
(
child:
CupertinoActivityIndicator
(
radius:
16.0
,
),
)
:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Container
(
margin:
EdgeInsets
.
symmetric
(
vertical:
20
.
px
,
horizontal:
20
.
px
),
height:
MediaQuery
.
of
(
context
).
size
.
height
-
100
.
px
-
widget
.
poemPanelHeight
,
width:
double
.
infinity
,
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade200
.
withOpacity
(
0.1
),
border:
Border
.
all
(
color:
Colors
.
grey
.
shade50
,
width:
0.5
,
),
// 边色与边宽度
),
child:
Padding
(
padding:
EdgeInsets
.
all
(
10
.
px
),
child:
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
PoemContent
(
title:
"题破山寺后禅院"
,
author:
"常建"
,
poemStr:
poemStr
,
fontSize:
22
.
px
,
),
Stack
(
alignment:
Alignment
.
center
,
children:
[
Positioned
(
left:
10
.
px
,
child:
IconButton
(
icon:
Icon
(
Icons
.
camera_alt_outlined
,
size:
28
.
px
,
),
onPressed:
()
{
Toast
.
show
(
"不要着急吖,正在开发ing...."
);
},
),
),
SizedBox
(
width:
double
.
infinity
,
height:
80
.
px
,
child:
PoemVoiceWidget
(
startRecord:
startRecord
,
stopRecord:
stopRecord
,
// 加入定制化Container的相关属性
height:
40
.
px
,
),
),
],
),
Container
(
padding:
const
EdgeInsets
.
all
(
10.0
),
alignment:
Alignment
.
centerRight
,
height:
54.0
,
width:
double
.
infinity
,
child:
TextButton
(
style:
ButtonStyle
(
side:
MaterialStateProperty
.
all
(
const
BorderSide
(
color:
Colors
.
black54
,
width:
1
),
child:
ClipRect
(
child:
BackdropFilter
(
filter:
ImageFilter
.
blur
(
sigmaX:
10.0
,
sigmaY:
10.0
,
),
child:
Container
(
decoration:
BoxDecoration
(
color:
Colors
.
grey
.
shade200
.
withOpacity
(
0.1
),
),
child:
Padding
(
padding:
EdgeInsets
.
all
(
10
.
px
),
child:
SingleChildScrollView
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
children:
[
PoemContent
(
title:
"题破山寺后禅院"
,
author:
"常建"
,
poemStr:
poemStr
,
fontSize:
22
.
px
,
),
),
onPressed:
()
{
NavigatorUtils
.
push
(
context
,
'
${PoemRouter.poemPublish}
?data=100'
,
);
},
child:
const
Text
(
"下一步"
,
style:
TextStyle
(
color:
Colors
.
white
),
),
const
AudioToolBar
(),
],
),
),
]
,
)
,
),
),
),
),
)
,
]
,
),
),
],
),
),
),
);
}
}
class
AudioToolBar
extends
StatefulWidget
{
const
AudioToolBar
({
Key
?
key
,
})
:
super
(
key:
key
);
@override
_AudioToolBarState
createState
()
=>
_AudioToolBarState
();
}
class
_AudioToolBarState
extends
State
<
AudioToolBar
>
{
late
final
PausableTimer
_timer
;
int
currentTimer
=
0
;
int
duration
=
10
*
1000
;
//TODO 60 * 1000;
Codec
_codec
=
Codec
.
aacMP4
;
String
_mPath
=
'tau_file.mp4'
;
FlutterSoundPlayer
?
_mPlayer
=
FlutterSoundPlayer
();
FlutterSoundRecorder
?
_mRecorder
=
FlutterSoundRecorder
();
bool
_mPlayerIsInited
=
false
;
bool
_mRecorderIsInited
=
false
;
bool
_mPlaybackReady
=
false
;
bool
_mRecorderIsRecording
=
false
;
bool
_mRecorderIsPaused
=
false
;
@override
void
initState
()
{
super
.
initState
();
_mPlayer
!.
openAudioSession
().
then
((
value
)
{
setState
(()
{
_mPlayerIsInited
=
true
;
});
});
openTheRecorder
().
then
((
value
)
{
setState
(()
{
_mRecorderIsInited
=
true
;
});
});
_timer
=
PausableTimer
(
const
Duration
(
milliseconds:
100
),
()
{
currentTimer
+=
100
;
_timer
..
reset
()
..
start
();
if
(
currentTimer
>=
duration
)
{
_mRecorderIsRecording
=
false
;
stopRecorder
();
}
setState
(()
{});
},
);
}
@override
void
dispose
()
{
_mPlayer
!.
closeAudioSession
();
_mPlayer
=
null
;
_mRecorder
!.
closeAudioSession
();
_mRecorder
=
null
;
super
.
dispose
();
}
Future
<
void
>
openTheRecorder
()
async
{
if
(!
kIsWeb
)
{
var
status
=
await
Permission
.
microphone
.
request
();
if
(
status
!=
PermissionStatus
.
granted
)
{
//TODO 弹出授权提示框
throw
RecordingPermissionException
(
'Microphone permission not granted'
);
}
}
await
_mRecorder
!.
openAudioSession
();
if
(!
await
_mRecorder
!.
isEncoderSupported
(
_codec
)
&&
kIsWeb
)
{
final
directory
=
await
getApplicationDocumentsDirectory
();
int
currentUnix
=
DateTime
.
now
().
millisecondsSinceEpoch
;
_codec
=
Codec
.
opusWebM
;
//TODO 音频保存格式,mp3?
_mPath
=
'
${directory.path}
/
$currentUnix
.webm'
;
if
(!
await
_mRecorder
!.
isEncoderSupported
(
_codec
)
&&
kIsWeb
)
{
_mRecorderIsInited
=
true
;
return
;
}
}
_mRecorderIsInited
=
true
;
}
void
record
()
{
if
(
_mRecorderIsInited
&&
_mPlayer
!.
isStopped
)
{
currentTimer
=
0
;
_timer
..
reset
()
..
start
();
_mRecorderIsRecording
=
true
;
_mRecorder
!
.
startRecorder
(
toFile:
_mPath
,
codec:
_codec
,
audioSource:
theSource
,
)
.
then
((
value
)
{
setState
(()
{});
});
}
}
void
pauseRecorder
()
async
{
if
(
_mRecorderIsInited
&&
_mPlayer
!.
isStopped
)
{
_timer
.
pause
();
_mRecorderIsPaused
=
true
;
await
_mRecorder
!.
pauseRecorder
().
then
((
value
)
{
setState
(()
{});
});
}
}
void
resumeRecorder
()
async
{
if
(
_mRecorderIsInited
&&
_mPlayer
!.
isStopped
)
{
_timer
.
start
();
await
_mRecorder
!.
resumeRecorder
().
then
((
value
)
{
_mRecorderIsPaused
=
false
;
setState
(()
{});
});
}
}
void
stopRecorder
()
async
{
if
(
_mRecorderIsInited
&&
_mPlayer
!.
isStopped
)
{
print
(
"### stop record"
);
_timer
.
pause
();
await
_mRecorder
!.
stopRecorder
().
then
((
value
)
{
_mRecorderIsRecording
=
false
;
setState
(()
{
_mPlaybackReady
=
true
;
});
});
}
}
void
play
()
{
if
(
_mPlayerIsInited
&&
_mPlaybackReady
&&
_mRecorder
!.
isStopped
)
{
_mPlayer
!
.
startPlayer
(
fromURI:
_mPath
,
whenFinished:
()
{
setState
(()
{});
})
.
then
((
value
)
{
setState
(()
{});
});
}
}
void
stopPlayer
()
{
if
(
_mPlayerIsInited
&&
_mPlaybackReady
&&
_mRecorder
!.
isStopped
)
{
_mPlayer
!.
stopPlayer
().
then
((
value
)
{
setState
(()
{});
});
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
Padding
(
padding:
EdgeInsets
.
fromLTRB
(
16
.
px
,
8
.
px
,
16
.
px
,
8
.
px
,
),
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceBetween
,
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
InkWell
(
onTap:
()
{
if
(
_mRecorderIsRecording
)
{
_mRecorderIsPaused
?
resumeRecorder
()
:
pauseRecorder
();
}
else
{
NavigatorUtils
.
push
(
context
,
'
${PoemRouter.poemRecordVideoPage}
?id=100'
,
);
}
},
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Icon
(
Icons
.
circle
,
color:
Colors
.
black38
,
size:
60
.
px
,
),
_mRecorderIsRecording
?
_mRecorderIsPaused
?
Icon
(
Icons
.
play_arrow
,
color:
Colors
.
white
,
size:
30
.
px
,
)
:
Icon
(
Icons
.
pause
,
color:
Colors
.
white
,
size:
30
.
px
,
)
:
Icon
(
Icons
.
camera_alt_outlined
,
color:
Colors
.
white
,
size:
30
.
px
,
),
],
),
),
InkWell
(
onTap:
()
{
_mRecorderIsRecording
?
stopRecorder
()
:
record
();
},
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Icon
(
Icons
.
circle
,
color:
Colors
.
white
,
size:
80
.
px
,
),
_mRecorderIsRecording
?
SizedBox
(
width:
60
.
px
,
height:
60
.
px
,
child:
CircularProgressIndicator
(
strokeWidth:
5
.
px
,
value:
currentTimer
/
duration
,
),
)
:
Container
(),
Icon
(
Icons
.
circle
,
color:
Colors
.
red
,
size:
65
.
px
,
),
_mRecorderIsRecording
?
Container
()
:
Text
(
"60s"
,
style:
TextStyle
(
fontSize:
12
.
px
,
color:
Colors
.
white
,
),
),
_mRecorderIsRecording
?
Icon
(
Icons
.
stop_rounded
,
color:
Colors
.
white
,
size:
32
.
px
,
)
:
Container
(),
],
),
),
InkWell
(
onTap:
()
{},
child:
Stack
(
alignment:
Alignment
.
center
,
children:
[
Icon
(
Icons
.
circle
,
color:
Colors
.
black38
,
size:
60
.
px
,
),
Icon
(
Icons
.
arrow_right_alt
,
color:
Colors
.
white
,
size:
30
.
px
,
),
],
),
),
],
),
);
}
}
...
...
lib/poem/page/poem_record_video.dart
View file @
53d45ce
...
...
@@ -42,10 +42,7 @@ class _PoemRecordVideoPageState extends State<PoemRecordVideoPage>
List
<
CameraDescription
>?
cameras
=
[];
///声明变量
late
final
PausableTimer
_timer
;
///记录当前的时间
int
currentTimer
=
0
;
int
duration
=
10
*
1000
;
//TODO 60 * 1000;
...
...
lib/recorder/audio/widgets/custom_overlay.dart
deleted
100644 → 0
View file @
a0d883f
import
'package:flutter/material.dart'
;
class
CustomOverlay
extends
StatelessWidget
{
final
Widget
?
icon
;
final
BoxDecoration
decoration
;
final
double
width
;
final
double
height
;
const
CustomOverlay
({
Key
?
key
,
this
.
icon
,
this
.
decoration
=
const
BoxDecoration
(
color:
Color
(
0xff77797A
),
borderRadius:
BorderRadius
.
all
(
Radius
.
circular
(
20.0
)),
),
this
.
width
=
160
,
this
.
height
=
160
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Positioned
(
top:
MediaQuery
.
of
(
context
).
size
.
height
*
0.5
-
width
/
2
,
left:
MediaQuery
.
of
(
context
).
size
.
width
*
0.5
-
height
/
2
,
child:
Material
(
type:
MaterialType
.
transparency
,
child:
Center
(
child:
Opacity
(
opacity:
0.8
,
child:
Container
(
width:
width
,
height:
height
,
decoration:
decoration
,
child:
icon
,
),
),
),
),
);
}
}
lib/recorder/audio/widgets/poem_voice_widget.dart
deleted
100644 → 0
View file @
a0d883f
import
'dart:async'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_plugin_record/flutter_plugin_record.dart'
;
import
'package:flutter_plugin_record/utils/common_toast.dart'
;
import
'custom_overlay.dart'
;
import
'package:one_poem/extension/int_extension.dart'
;
typedef
StartRecord
=
Future
Function
();
typedef
StopRecord
=
Future
Function
();
class
PoemVoiceWidget
extends
StatefulWidget
{
final
Function
?
startRecord
;
final
Function
?
stopRecord
;
final
double
?
height
;
final
EdgeInsets
?
margin
;
final
Decoration
?
decoration
;
/// startRecord 开始录制回调 stopRecord回调
const
PoemVoiceWidget
(
{
Key
?
key
,
this
.
startRecord
,
this
.
stopRecord
,
this
.
height
,
this
.
decoration
,
this
.
margin
})
:
super
(
key:
key
);
@override
_PoemVoiceWidgetState
createState
()
=>
_PoemVoiceWidgetState
();
}
class
_PoemVoiceWidgetState
extends
State
<
PoemVoiceWidget
>
{
// 倒计时总时长
final
int
_countTotal
=
12
;
double
startY
=
0.0
;
double
offset
=
0.0
;
bool
isUp
=
false
;
String
textShow
=
"按住说话"
;
String
toastShow
=
"手指上滑,取消发送"
;
String
voiceIco
=
"images/voice_volume_1.png"
;
///默认隐藏状态
bool
voiceState
=
true
;
FlutterPluginRecord
?
recordPlugin
;
Timer
?
_timer
;
int
_count
=
0
;
OverlayEntry
?
overlayEntry
;
String
audioFilePath
=
""
;
@override
void
initState
()
{
super
.
initState
();
recordPlugin
=
FlutterPluginRecord
();
_init
();
///初始化方法的监听
recordPlugin
?.
responseFromInit
.
listen
((
data
)
{
// if (data) {
// print("初始化成功");
// } else {
// print("初始化失败");
// }
});
/// 开始录制或结束录制的监听
recordPlugin
?.
response
.
listen
((
data
)
{
if
(
data
.
msg
==
"onStop"
)
{
///结束录制时会返回录制文件的地址方便上传服务器
if
(
widget
.
stopRecord
!=
null
)
{
audioFilePath
=
data
.
path
!;
widget
.
stopRecord
!(
data
.
path
,
data
.
audioTimeLength
);
}
}
else
if
(
data
.
msg
==
"onStart"
)
{
if
(
widget
.
startRecord
!=
null
)
widget
.
startRecord
!();
}
});
///录制过程监听录制的声音的大小 方便做语音动画显示图片的样式
recordPlugin
!.
responseFromAmplitude
.
listen
((
data
)
{
var
voiceData
=
double
.
parse
(
data
.
msg
??
''
);
setState
(()
{
if
(
voiceData
>
0
&&
voiceData
<
0.1
)
{
voiceIco
=
"images/voice_volume_2.png"
;
}
else
if
(
voiceData
>
0.2
&&
voiceData
<
0.3
)
{
voiceIco
=
"images/voice_volume_3.png"
;
}
else
if
(
voiceData
>
0.3
&&
voiceData
<
0.4
)
{
voiceIco
=
"images/voice_volume_4.png"
;
}
else
if
(
voiceData
>
0.4
&&
voiceData
<
0.5
)
{
voiceIco
=
"images/voice_volume_5.png"
;
}
else
if
(
voiceData
>
0.5
&&
voiceData
<
0.6
)
{
voiceIco
=
"images/voice_volume_6.png"
;
}
else
if
(
voiceData
>
0.6
&&
voiceData
<
0.7
)
{
voiceIco
=
"images/voice_volume_7.png"
;
}
else
if
(
voiceData
>
0.7
&&
voiceData
<
1
)
{
voiceIco
=
"images/voice_volume_7.png"
;
}
else
{
voiceIco
=
"images/voice_volume_1.png"
;
}
if
(
overlayEntry
!=
null
)
{
overlayEntry
!.
markNeedsBuild
();
}
});
});
}
///显示录音悬浮布局
buildOverLayView
(
BuildContext
context
)
{
if
(
overlayEntry
==
null
)
{
overlayEntry
=
OverlayEntry
(
builder:
(
content
)
{
return
CustomOverlay
(
icon:
Column
(
children:
<
Widget
>[
Container
(
margin:
EdgeInsets
.
only
(
top:
10
.
px
),
child:
_countTotal
-
_count
<
11
?
Center
(
child:
Padding
(
padding:
EdgeInsets
.
only
(
bottom:
15
.
px
),
child:
Text
(
(
_countTotal
-
_count
).
toString
(),
style:
TextStyle
(
fontSize:
70
.
px
,
color:
Colors
.
white
,
),
),
),
)
:
Image
.
asset
(
voiceIco
,
width:
100
.
px
,
height:
100
.
px
,
package:
'flutter_plugin_record'
,
),
),
Text
(
toastShow
,
style:
TextStyle
(
fontStyle:
FontStyle
.
normal
,
color:
Colors
.
white
,
fontSize:
14
.
px
,
),
)
],
),
);
});
Overlay
.
of
(
context
)!.
insert
(
overlayEntry
!);
}
}
showVoiceView
()
{
setState
(()
{
textShow
=
"松开结束"
;
voiceState
=
false
;
});
///显示录音悬浮布局
buildOverLayView
(
context
);
start
();
}
hideVoiceView
()
{
if
(
_timer
!.
isActive
)
{
if
(
_count
<
1
)
{
CommonToast
.
showView
(
context:
context
,
msg:
'说话时间太短'
,
icon:
Text
(
'!'
,
style:
TextStyle
(
fontSize:
80
.
px
,
color:
Colors
.
white
),
));
isUp
=
true
;
}
_timer
?.
cancel
();
_count
=
0
;
}
setState
(()
{
textShow
=
"按住说话"
;
voiceState
=
true
;
});
stop
();
if
(
overlayEntry
!=
null
)
{
overlayEntry
?.
remove
();
overlayEntry
=
null
;
}
// if (isUp) {
// print("取消发送");
// } else {
// print("进行发送");
// }
}
moveVoiceView
()
{
setState
(()
{
isUp
=
startY
-
offset
>
100
?
true
:
false
;
if
(
isUp
)
{
textShow
=
"松开手指,取消发送"
;
toastShow
=
textShow
;
}
else
{
textShow
=
"松开结束"
;
toastShow
=
"手指上滑,取消发送"
;
}
});
}
///初始化语音录制的方法
void
_init
()
async
{
recordPlugin
?.
initRecordMp3
();
}
///开始语音录制的方法
void
start
()
async
{
recordPlugin
?.
start
();
}
///停止语音录制的方法
void
stop
()
{
recordPlugin
?.
stop
();
}
@override
Widget
build
(
BuildContext
context
)
{
return
Padding
(
padding:
EdgeInsets
.
only
(
right:
10
.
px
),
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisAlignment:
MainAxisAlignment
.
end
,
children:
[
GestureDetector
(
onLongPressStart:
(
details
)
{
startY
=
details
.
globalPosition
.
dy
;
_timer
=
Timer
.
periodic
(
const
Duration
(
milliseconds:
1000
),
(
t
)
{
_count
++;
if
(
_count
==
_countTotal
)
{
hideVoiceView
();
}
});
showVoiceView
();
},
onLongPressEnd:
(
details
)
{
hideVoiceView
();
},
onLongPressMoveUpdate:
(
details
)
{
offset
=
details
.
globalPosition
.
dy
;
moveVoiceView
();
},
child:
Container
(
height:
widget
.
height
??
60
.
px
,
margin:
widget
.
margin
??
EdgeInsets
.
fromLTRB
(
50
.
px
,
0
,
50
.
px
,
20
.
px
),
child:
Icon
(
Icons
.
mic_none
,
size:
70
.
px
,
color:
Colors
.
black45
.
withOpacity
(
0.6
),
),
),
),
IconButton
(
icon:
Icon
(
Icons
.
play_circle_outline
,
size:
28
.
px
,
),
onPressed:
()
{
print
(
"######:"
+
audioFilePath
);
recordPlugin
!.
playByPath
(
audioFilePath
,
"file"
);
},
),
],
),
);
}
@override
void
dispose
()
{
recordPlugin
?.
dispose
();
_timer
?.
cancel
();
super
.
dispose
();
}
}
lib/recorder/video/captures_screen.dart
deleted
100644 → 0
View file @
a0d883f
import
'dart:io'
;
import
'package:flutter/material.dart'
;
import
'preview_screen.dart'
;
class
CapturesScreen
extends
StatelessWidget
{
final
List
<
File
>
imageFileList
;
const
CapturesScreen
({
Key
?
key
,
required
this
.
imageFileList
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
backgroundColor:
Colors
.
black
,
body:
SingleChildScrollView
(
physics:
const
BouncingScrollPhysics
(),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
const
Padding
(
padding:
EdgeInsets
.
all
(
16.0
),
child:
Text
(
'Captures'
,
style:
TextStyle
(
fontSize:
32.0
,
color:
Colors
.
white
,
),
),
),
GridView
.
count
(
shrinkWrap:
true
,
physics:
const
NeverScrollableScrollPhysics
(),
crossAxisCount:
2
,
children:
[
for
(
File
imageFile
in
imageFileList
)
Container
(
decoration:
BoxDecoration
(
border:
Border
.
all
(
color:
Colors
.
black
,
width:
2
,
),
),
child:
InkWell
(
onTap:
()
{
Navigator
.
of
(
context
).
pushReplacement
(
MaterialPageRoute
(
builder:
(
context
)
=>
PreviewScreen
(
fileList:
imageFileList
,
imageFile:
imageFile
,
),
),
);
},
child:
Image
.
file
(
imageFile
,
fit:
BoxFit
.
cover
,
),
),
),
],
),
],
),
),
);
}
}
lib/recorder/video/preview_screen.dart
deleted
100644 → 0
View file @
a0d883f
import
'dart:io'
;
import
'package:flutter/material.dart'
;
import
'captures_screen.dart'
;
class
PreviewScreen
extends
StatelessWidget
{
final
File
imageFile
;
final
List
<
File
>
fileList
;
const
PreviewScreen
({
Key
?
key
,
required
this
.
imageFile
,
required
this
.
fileList
,
})
:
super
(
key:
key
);
@override
Widget
build
(
BuildContext
context
)
{
return
Scaffold
(
backgroundColor:
Colors
.
black
,
body:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
all
(
8.0
),
child:
TextButton
(
onPressed:
()
{
Navigator
.
of
(
context
).
pushReplacement
(
MaterialPageRoute
(
builder:
(
context
)
=>
CapturesScreen
(
imageFileList:
fileList
,
),
),
);
},
child:
const
Text
(
'打开全部视频'
),
style:
TextButton
.
styleFrom
(
primary:
Colors
.
black
,
backgroundColor:
Colors
.
white
,
),
),
),
Expanded
(
child:
Image
.
file
(
imageFile
),
),
],
),
);
}
}
pubspec.lock
View file @
53d45ce
...
...
@@ -21,7 +21,7 @@ packages:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.
2
"
version: "3.1.
6
"
args:
dependency: transitive
description:
...
...
@@ -35,7 +35,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.
1
"
version: "2.8.
2
"
boolean_selector:
dependency: transitive
description:
...
...
@@ -126,14 +126,14 @@ packages:
name: camera
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.4+
6
"
version: "0.9.4+
7
"
camera_platform_interface:
dependency: transitive
description:
name: camera_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.
4
"
version: "2.1.
5
"
camera_web:
dependency: transitive
description:
...
...
@@ -147,7 +147,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.
1
.0"
version: "1.
2
.0"
charcode:
dependency: transitive
description:
...
...
@@ -400,7 +400,7 @@ packages:
name: flutter_native_splash
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.
2
"
version: "1.3.
3
"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
...
...
@@ -408,20 +408,34 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
flutter_
plugin_record
:
flutter_
slidable
:
dependency: "direct main"
description:
name: flutter_
plugin_record
name: flutter_
slidable
url: "https://pub.dartlang.org"
source: hosted
version: "1.
0.1
"
flutter_s
lidable
:
version: "1.
2.0
"
flutter_s
ound
:
dependency: "direct main"
description:
name: flutter_s
lidable
name: flutter_s
ound
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "8.5.0"
flutter_sound_platform_interface:
dependency: transitive
description:
name: flutter_sound_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "8.5.0"
flutter_sound_web:
dependency: transitive
description:
name: flutter_sound_web
url: "https://pub.dartlang.org"
source: hosted
version: "8.5.0"
flutter_spinkit:
dependency: "direct main"
description:
...
...
@@ -513,7 +527,7 @@ packages:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.4+
4
"
version: "0.8.4+
5
"
image_picker_for_web:
dependency: transitive
description:
...
...
@@ -582,6 +596,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
logger:
dependency: transitive
description:
name: logger
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
logging:
dependency: transitive
description:
...
...
@@ -595,7 +616,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.1
0
"
version: "0.12.1
1
"
meta:
dependency: transitive
description:
...
...
@@ -742,7 +763,7 @@ packages:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.
0
"
version: "3.0.
2
"
plugin_platform_interface:
dependency: transitive
description:
...
...
@@ -763,7 +784,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.
3
"
version: "4.2.
4
"
provider:
dependency: "direct main"
description:
...
...
@@ -820,6 +841,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
recase:
dependency: transitive
description:
name: recase
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.0"
rxdart:
dependency: "direct main"
description:
...
...
@@ -985,7 +1013,7 @@ packages:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "2.
0.1+1
"
version: "2.
2.0
"
stack_trace:
dependency: transitive
description:
...
...
@@ -1055,21 +1083,21 @@ packages:
name: test
url: "https://pub.dartlang.org"
source: hosted
version: "1.17.1
0
"
version: "1.17.1
2
"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.
2
"
version: "0.4.
3
"
test_core:
dependency: transitive
description:
name: test_core
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.
0
"
version: "0.4.
2
"
timing:
dependency: transitive
description:
...
...
@@ -1097,7 +1125,7 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.1
7
"
version: "6.0.1
8
"
url_launcher_android:
dependency: transitive
description:
...
...
@@ -1167,7 +1195,7 @@ packages:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.
0
"
version: "2.1.
1
"
vibration:
dependency: "direct main"
description:
...
...
@@ -1209,7 +1237,7 @@ packages:
name: vm_service
url: "https://pub.dartlang.org"
source: hosted
version: "7.
1.1
"
version: "7.
3.0
"
watcher:
dependency: transitive
description:
...
...
@@ -1272,7 +1300,7 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.
6
"
version: "2.3.
8
"
xdg_directories:
dependency: transitive
description:
...
...
@@ -1295,5 +1323,5 @@ packages:
source: hosted
version: "3.1.0"
sdks:
dart: ">=2.1
4.0
<3.0.0"
dart: ">=2.1
5.1
<3.0.0"
flutter: ">=2.5.0"
...
...
pubspec.yaml
View file @
53d45ce
...
...
@@ -50,9 +50,9 @@ dependencies:
# Flutter 轮播图 https://github.com/lianyagang/flutter_swiper_null_safety
flutter_swiper_null_safety
:
^1.0.2
# flutter_swiper很久不维护,可以使用空安全版本:flutter_swiper_null_safety
# 启动URL的插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/url_launcher
url_launcher
:
6.0.17
url_launcher
:
^6.0.18
# 图片选择插件(支持Web) https://github.com/flutter/plugins/tree/master/packages/image_picker
image_picker
:
0.8.4+4
image_picker
:
^0.8.4+5
# 侧滑删除 https://github.com/letsar/flutter_slidable
flutter_slidable
:
^1.1.0
# WebView插件 https://github.com/flutter/plugins/tree/master/packages/webview_flutter
...
...
@@ -91,12 +91,12 @@ dependencies:
flutter_spinkit
:
^5.0.0
json_annotation
:
^4.4.0
flutter_
plugin_record
:
^1.0.1
flutter_
sound
:
^8.5.0
# fijkplayer (Video player plugin for Flutter) Flutter 媒体播放器
fijkplayer
:
^0.10.1
camera
:
^0.9.4+
5
camera
:
^0.9.4+
7
path_provider
:
^2.0.8
# A Dart timer that can be paused, resumed and reset.
...
...
Please
register
or
login
to post a comment