|
|
|
@ -67,98 +67,102 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> { |
|
|
|
), |
|
|
|
onPressed: () => Get.back(), |
|
|
|
), |
|
|
|
title: Opacity( |
|
|
|
opacity: controller.isTop.value ? 1.0 : 0.0, |
|
|
|
child: Container( |
|
|
|
width: 170.w, |
|
|
|
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w), |
|
|
|
clipBehavior: Clip.hardEdge, |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey[200], |
|
|
|
borderRadius: BorderRadius.circular(30.r), |
|
|
|
), |
|
|
|
child: Row( |
|
|
|
children: [ |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.meetingData.value.filepath.isEmpty) { |
|
|
|
controller.downloadAudio(); |
|
|
|
} else { |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
title: Obx( |
|
|
|
() => Opacity( |
|
|
|
opacity: (1 - (controller.dragOffset.value / 100.w)).clamp(0.0, 1.0), |
|
|
|
child: Container( |
|
|
|
width: 170.w, |
|
|
|
padding: EdgeInsets.symmetric(horizontal: 2.w, vertical: 3.w), |
|
|
|
clipBehavior: Clip.hardEdge, |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey[200], |
|
|
|
borderRadius: BorderRadius.circular(30.r), |
|
|
|
), |
|
|
|
child: Row( |
|
|
|
children: [ |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.meetingData.value.filepath.isEmpty) { |
|
|
|
controller.downloadAudio(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
child: Obx( |
|
|
|
() => !controller.isLoading.value && |
|
|
|
controller.meetingData.value.filepath.isEmpty |
|
|
|
? Obx( |
|
|
|
() => Stack( |
|
|
|
alignment: Alignment.center, |
|
|
|
children: [ |
|
|
|
if (controller.isDownload.value) |
|
|
|
SizedBox( |
|
|
|
width: 26.w, |
|
|
|
height: 26.w, |
|
|
|
child: CircularProgressIndicator( |
|
|
|
value: controller.downloadProgress.value, |
|
|
|
valueColor: |
|
|
|
const AlwaysStoppedAnimation<Color>( |
|
|
|
Colors.red), |
|
|
|
strokeWidth: 2.w, |
|
|
|
}, |
|
|
|
child: Obx( |
|
|
|
() => !controller.isLoading.value && |
|
|
|
controller.meetingData.value.filepath.isEmpty |
|
|
|
? Obx( |
|
|
|
() => Stack( |
|
|
|
alignment: Alignment.center, |
|
|
|
children: [ |
|
|
|
if (controller.isDownload.value) |
|
|
|
SizedBox( |
|
|
|
width: 26.w, |
|
|
|
height: 26.w, |
|
|
|
child: CircularProgressIndicator( |
|
|
|
value: controller.downloadProgress.value, |
|
|
|
valueColor: |
|
|
|
const AlwaysStoppedAnimation<Color>( |
|
|
|
Colors.red), |
|
|
|
strokeWidth: 2.w, |
|
|
|
), |
|
|
|
), |
|
|
|
Icon( |
|
|
|
Icons.download_for_offline, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
Icon( |
|
|
|
Icons.download_for_offline, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
) |
|
|
|
: Icon( |
|
|
|
controller.isPlay.value |
|
|
|
? Icons.pause_circle |
|
|
|
: Icons.play_circle, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
) |
|
|
|
: Icon( |
|
|
|
controller.isPlay.value |
|
|
|
? Icons.pause_circle |
|
|
|
: Icons.play_circle, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
4.horizontalSpace, |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.isSpeakerText.value) return; |
|
|
|
controller.dragOffset.value = 210.w; |
|
|
|
controller.isTop.value = false; |
|
|
|
}, |
|
|
|
child: SizedBox( |
|
|
|
width: 130.w, |
|
|
|
child: FittedBox( |
|
|
|
fit: BoxFit.scaleDown, |
|
|
|
child: AudioFileWaveforms( |
|
|
|
size: Size(350.w, 30.w), |
|
|
|
playerController: controller.playerController, |
|
|
|
waveformData: List.generate(88, (int index) { |
|
|
|
return 0.01 + Random().nextDouble() * 0.09; |
|
|
|
}), |
|
|
|
waveformType: WaveformType.fitWidth, |
|
|
|
enableSeekGesture: false, |
|
|
|
playerWaveStyle: PlayerWaveStyle( |
|
|
|
spacing: 4.w, |
|
|
|
waveThickness: 2.w, |
|
|
|
fixedWaveColor: Colors.grey[400]!, |
|
|
|
liveWaveColor: Colors.red, |
|
|
|
seekLineColor: Colors.red, |
|
|
|
scaleFactor: 200, |
|
|
|
4.horizontalSpace, |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.isSpeakerText.value) return; |
|
|
|
controller.dragOffset.value = 210.w; |
|
|
|
controller.isTop.value = false; |
|
|
|
}, |
|
|
|
behavior: HitTestBehavior.translucent, |
|
|
|
child: SizedBox( |
|
|
|
width: 130.w, |
|
|
|
height: 30.w, |
|
|
|
child: FittedBox( |
|
|
|
fit: BoxFit.scaleDown, |
|
|
|
child: AudioFileWaveforms( |
|
|
|
size: Size(350.w, 30.w), |
|
|
|
playerController: controller.playerController, |
|
|
|
waveformData: List.generate(88, (int index) { |
|
|
|
return 0.01 + Random().nextDouble() * 0.09; |
|
|
|
}), |
|
|
|
waveformType: WaveformType.fitWidth, |
|
|
|
enableSeekGesture: false, |
|
|
|
playerWaveStyle: PlayerWaveStyle( |
|
|
|
spacing: 4.w, |
|
|
|
waveThickness: 2.w, |
|
|
|
fixedWaveColor: Colors.grey[400]!, |
|
|
|
liveWaveColor: Colors.red, |
|
|
|
seekLineColor: Colors.red, |
|
|
|
scaleFactor: 200, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
@ -373,176 +377,180 @@ class MeetingDetailsView extends GetView<MeetingDetailsController> { |
|
|
|
|
|
|
|
Widget _soundWave(bool isDarkMode) { |
|
|
|
return Obx( |
|
|
|
() => SizedBox( |
|
|
|
height: controller.dragOffset.value < 0 |
|
|
|
? 0 |
|
|
|
: controller.dragOffset.value > 210.w |
|
|
|
? 210.w |
|
|
|
: controller.dragOffset.value, |
|
|
|
child: Stack( |
|
|
|
children: [ |
|
|
|
Positioned( |
|
|
|
bottom: 0, |
|
|
|
child: Container( |
|
|
|
width: 1.sw, |
|
|
|
height: 200.w, |
|
|
|
margin: EdgeInsets.only(bottom: 10.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey[200]!, |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
bottom: Radius.circular(20.r), |
|
|
|
() => Opacity( |
|
|
|
opacity: (controller.dragOffset.value / 210.w).clamp(0.0, 1.0), |
|
|
|
child: SizedBox( |
|
|
|
height: controller.dragOffset.value < 0 |
|
|
|
? 0 |
|
|
|
: controller.dragOffset.value > 210.w |
|
|
|
? 210.w |
|
|
|
: controller.dragOffset.value, |
|
|
|
child: Stack( |
|
|
|
children: [ |
|
|
|
Positioned( |
|
|
|
bottom: 0, |
|
|
|
child: Container( |
|
|
|
width: 1.sw, |
|
|
|
height: 200.w, |
|
|
|
margin: EdgeInsets.only(bottom: 10.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.grey[200]!, |
|
|
|
borderRadius: BorderRadius.vertical( |
|
|
|
bottom: Radius.circular(20.r), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
child: Column( |
|
|
|
children: [ |
|
|
|
Container( |
|
|
|
margin: EdgeInsets.only(bottom: 5.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.white, |
|
|
|
borderRadius: BorderRadius.circular(8.r), |
|
|
|
), |
|
|
|
child: AudioFileWaveforms( |
|
|
|
size: Size(350.w, 120.w), |
|
|
|
playerController: controller.playerController, |
|
|
|
waveformData: List.generate(88, (int index) { |
|
|
|
return 0.01 + Random().nextDouble() * 0.09; |
|
|
|
}), |
|
|
|
waveformType: WaveformType.fitWidth, |
|
|
|
playerWaveStyle: PlayerWaveStyle( |
|
|
|
spacing: 4.w, |
|
|
|
waveThickness: 2.w, |
|
|
|
fixedWaveColor: Colors.grey[300]!, |
|
|
|
liveWaveColor: Colors.red, |
|
|
|
seekLineColor: Colors.red, |
|
|
|
scaleFactor: 600, |
|
|
|
child: Column( |
|
|
|
children: [ |
|
|
|
Container( |
|
|
|
margin: EdgeInsets.only(bottom: 5.w), |
|
|
|
decoration: BoxDecoration( |
|
|
|
color: Colors.white, |
|
|
|
borderRadius: BorderRadius.circular(8.r), |
|
|
|
), |
|
|
|
child: AudioFileWaveforms( |
|
|
|
size: Size(350.w, 120.w), |
|
|
|
playerController: controller.playerController, |
|
|
|
waveformData: List.generate(88, (int index) { |
|
|
|
return 0.01 + Random().nextDouble() * 0.09; |
|
|
|
}), |
|
|
|
waveformType: WaveformType.fitWidth, |
|
|
|
playerWaveStyle: PlayerWaveStyle( |
|
|
|
spacing: 4.w, |
|
|
|
waveThickness: 2.w, |
|
|
|
fixedWaveColor: Colors.grey[300]!, |
|
|
|
liveWaveColor: Colors.red, |
|
|
|
seekLineColor: Colors.red, |
|
|
|
scaleFactor: 600, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
SizedBox( |
|
|
|
width: 350.w, |
|
|
|
child: Row( |
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
|
children: [ |
|
|
|
Obx( |
|
|
|
() => Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
controller.currentDuration.value, |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: isDarkMode |
|
|
|
? Colors.grey[400] |
|
|
|
: Colors.grey[500], |
|
|
|
fontSize: 12.sp, |
|
|
|
SizedBox( |
|
|
|
width: 350.w, |
|
|
|
child: Row( |
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
|
|
children: [ |
|
|
|
Obx( |
|
|
|
() => Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
controller.currentDuration.value, |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: isDarkMode |
|
|
|
? Colors.grey[400] |
|
|
|
: Colors.grey[500], |
|
|
|
fontSize: 12.sp, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
Obx( |
|
|
|
() => Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
controller.durationMax.value, |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: isDarkMode |
|
|
|
? Colors.grey[400] |
|
|
|
: Colors.grey[500], |
|
|
|
fontSize: 12.sp, |
|
|
|
Obx( |
|
|
|
() => Text( |
|
|
|
DateUtil.formatDateMs( |
|
|
|
controller.durationMax.value, |
|
|
|
format: 'HH:mm:ss', |
|
|
|
isUtc: true, |
|
|
|
), |
|
|
|
style: TextStyle( |
|
|
|
color: isDarkMode |
|
|
|
? Colors.grey[400] |
|
|
|
: Colors.grey[500], |
|
|
|
fontSize: 12.sp, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
Row( |
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
|
|
|
children: [ |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
int progress = |
|
|
|
controller.currentDuration.value - 10000; |
|
|
|
if (progress < 0) { |
|
|
|
progress = 0; |
|
|
|
} |
|
|
|
controller.playerController.seekTo(progress); |
|
|
|
}, |
|
|
|
child: Icon( |
|
|
|
Icons.replay_10, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
Row( |
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly, |
|
|
|
children: [ |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
int progress = |
|
|
|
controller.currentDuration.value - 10000; |
|
|
|
if (progress < 0) { |
|
|
|
progress = 0; |
|
|
|
} |
|
|
|
controller.playerController.seekTo(progress); |
|
|
|
}, |
|
|
|
child: Icon( |
|
|
|
Icons.replay_10, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller.meetingData.value.filepath.isEmpty) { |
|
|
|
controller.downloadAudio(); |
|
|
|
} else { |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
if (controller |
|
|
|
.meetingData.value.filepath.isEmpty) { |
|
|
|
controller.downloadAudio(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
if (controller.isPlay.value) { |
|
|
|
controller.playerController.pausePlayer(); |
|
|
|
} else { |
|
|
|
controller.playerController.startPlayer(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
child: Obx( |
|
|
|
() => !controller.isLoading.value && |
|
|
|
controller |
|
|
|
.meetingData.value.filepath.isEmpty |
|
|
|
? Obx( |
|
|
|
() => Stack( |
|
|
|
alignment: Alignment.center, |
|
|
|
children: [ |
|
|
|
if (controller.isDownload.value) |
|
|
|
SizedBox( |
|
|
|
width: 42.w, |
|
|
|
height: 42.w, |
|
|
|
child: CircularProgressIndicator( |
|
|
|
value: controller |
|
|
|
.downloadProgress.value, |
|
|
|
valueColor: |
|
|
|
const AlwaysStoppedAnimation< |
|
|
|
Color>(Colors.red), |
|
|
|
strokeWidth: 3.w, |
|
|
|
}, |
|
|
|
child: Obx( |
|
|
|
() => !controller.isLoading.value && |
|
|
|
controller |
|
|
|
.meetingData.value.filepath.isEmpty |
|
|
|
? Obx( |
|
|
|
() => Stack( |
|
|
|
alignment: Alignment.center, |
|
|
|
children: [ |
|
|
|
if (controller.isDownload.value) |
|
|
|
SizedBox( |
|
|
|
width: 42.w, |
|
|
|
height: 42.w, |
|
|
|
child: CircularProgressIndicator( |
|
|
|
value: controller |
|
|
|
.downloadProgress.value, |
|
|
|
valueColor: |
|
|
|
const AlwaysStoppedAnimation< |
|
|
|
Color>(Colors.red), |
|
|
|
strokeWidth: 3.w, |
|
|
|
), |
|
|
|
), |
|
|
|
Icon( |
|
|
|
Icons.download_for_offline, |
|
|
|
color: Colors.black, |
|
|
|
size: 48.w, |
|
|
|
), |
|
|
|
Icon( |
|
|
|
Icons.download_for_offline, |
|
|
|
color: Colors.black, |
|
|
|
size: 48.w, |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
) |
|
|
|
: Icon( |
|
|
|
controller.isPlay.value |
|
|
|
? Icons.pause_circle |
|
|
|
: Icons.play_circle, |
|
|
|
color: Colors.black, |
|
|
|
size: 48.w, |
|
|
|
), |
|
|
|
) |
|
|
|
: Icon( |
|
|
|
controller.isPlay.value |
|
|
|
? Icons.pause_circle |
|
|
|
: Icons.play_circle, |
|
|
|
color: Colors.black, |
|
|
|
size: 48.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
int progress = |
|
|
|
controller.currentDuration.value + 10000; |
|
|
|
controller.playerController.seekTo(progress); |
|
|
|
}, |
|
|
|
child: Icon( |
|
|
|
Icons.forward_10, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
GestureDetector( |
|
|
|
onTap: () { |
|
|
|
int progress = |
|
|
|
controller.currentDuration.value + 10000; |
|
|
|
controller.playerController.seekTo(progress); |
|
|
|
}, |
|
|
|
child: Icon( |
|
|
|
Icons.forward_10, |
|
|
|
color: Colors.black, |
|
|
|
size: 30.w, |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
], |
|
|
|
], |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
); |
|
|
|
|