295 lines
9.2 KiB
Dart
295 lines
9.2 KiB
Dart
// ignore_for_file: implementation_imports, unused_element, empty_catches
|
|
|
|
import 'package:didvan/constants/app_icons.dart';
|
|
import 'package:didvan/views/ai/widgets/message_bar_btn.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:voice_message_package/src/helpers/play_status.dart';
|
|
import 'package:voice_message_package/src/helpers/utils.dart';
|
|
import 'package:voice_message_package/src/voice_controller.dart';
|
|
import 'package:voice_message_package/src/widgets/noises.dart';
|
|
import 'package:voice_message_package/src/widgets/play_pause_button.dart';
|
|
|
|
/// A widget that displays a voice message view with play/pause functionality.
|
|
///
|
|
/// The [VoiceMessageView] widget is used to display a voice message with customizable appearance and behavior.
|
|
/// It provides a play/pause button, a progress slider, and a counter for the remaining time.
|
|
/// The appearance of the widget can be customized using various properties such as background color, slider color, and text styles.
|
|
///
|
|
class MyVoiceMessageView extends StatelessWidget {
|
|
const MyVoiceMessageView(
|
|
{Key? key,
|
|
required this.controller,
|
|
this.backgroundColor = Colors.transparent,
|
|
this.activeSliderColor = Colors.red,
|
|
this.notActiveSliderColor,
|
|
this.circlesColor = Colors.red,
|
|
this.innerPadding = 12,
|
|
this.cornerRadius = 20,
|
|
// this.playerWidth = 170,
|
|
this.size = 38,
|
|
this.refreshIcon = const Icon(
|
|
Icons.refresh,
|
|
color: Colors.white,
|
|
),
|
|
this.pauseIcon = const Icon(
|
|
Icons.pause_rounded,
|
|
color: Colors.white,
|
|
),
|
|
this.playIcon = const Icon(
|
|
Icons.play_arrow_rounded,
|
|
color: Colors.white,
|
|
),
|
|
this.stopDownloadingIcon = const Icon(
|
|
Icons.close,
|
|
color: Colors.white,
|
|
),
|
|
this.playPauseButtonDecoration,
|
|
this.circlesTextStyle = const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 10,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
this.counterTextStyle = const TextStyle(
|
|
fontSize: 11,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
this.playPauseButtonLoadingColor = Colors.white,
|
|
this.trashClick,
|
|
this.showSpeed = false})
|
|
: super(key: key);
|
|
|
|
/// The controller for the voice message view.
|
|
final VoiceController controller;
|
|
|
|
/// The background color of the voice message view.
|
|
final Color backgroundColor;
|
|
|
|
///
|
|
final Color circlesColor;
|
|
|
|
/// The color of the active slider.
|
|
final Color activeSliderColor;
|
|
|
|
/// The color of the not active slider.
|
|
final Color? notActiveSliderColor;
|
|
|
|
/// The text style of the circles.
|
|
final TextStyle circlesTextStyle;
|
|
|
|
/// The text style of the counter.
|
|
final TextStyle counterTextStyle;
|
|
|
|
/// The padding between the inner content and the outer container.
|
|
final double innerPadding;
|
|
|
|
/// The corner radius of the outer container.
|
|
final double cornerRadius;
|
|
|
|
/// The size of the play/pause button.
|
|
final double size;
|
|
|
|
/// The refresh icon of the play/pause button.
|
|
final Widget refreshIcon;
|
|
|
|
/// The pause icon of the play/pause button.
|
|
final Widget pauseIcon;
|
|
|
|
/// The play icon of the play/pause button.
|
|
final Widget playIcon;
|
|
|
|
/// The stop downloading icon of the play/pause button.
|
|
final Widget stopDownloadingIcon;
|
|
|
|
/// The play Decoration of the play/pause button.
|
|
final Decoration? playPauseButtonDecoration;
|
|
|
|
/// The loading Color of the play/pause button.
|
|
final Color playPauseButtonLoadingColor;
|
|
|
|
final Function()? trashClick;
|
|
|
|
final bool showSpeed;
|
|
|
|
@override
|
|
|
|
/// Build voice message view.
|
|
Widget build(BuildContext context) {
|
|
final ThemeData theme = Theme.of(context);
|
|
final color = circlesColor;
|
|
final newTHeme = theme.copyWith(
|
|
sliderTheme: SliderThemeData(
|
|
trackShape: CustomTrackShape(),
|
|
thumbShape: SliderComponentShape.noThumb,
|
|
minThumbSeparation: 0,
|
|
),
|
|
splashColor: Colors.transparent,
|
|
);
|
|
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Container(
|
|
width: 160 + (controller.noiseCount * .72.w()),
|
|
padding: EdgeInsets.all(innerPadding),
|
|
decoration: BoxDecoration(
|
|
color: backgroundColor,
|
|
borderRadius: BorderRadius.circular(cornerRadius),
|
|
),
|
|
child: ValueListenableBuilder(
|
|
/// update ui when change play status
|
|
valueListenable: controller.updater,
|
|
builder: (context, value, child) {
|
|
return Row(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
const SizedBox(width: 12),
|
|
|
|
/// play pause button
|
|
PlayPauseButton(
|
|
controller: controller,
|
|
color: color,
|
|
loadingColor: playPauseButtonLoadingColor,
|
|
size: size,
|
|
refreshIcon: refreshIcon,
|
|
pauseIcon: pauseIcon,
|
|
playIcon: playIcon,
|
|
stopDownloadingIcon: stopDownloadingIcon,
|
|
buttonDecoration: playPauseButtonDecoration,
|
|
),
|
|
const SizedBox(width: 12),
|
|
|
|
///
|
|
|
|
/// slider & noises
|
|
Expanded(
|
|
child: _noises(newTHeme),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Text(controller.remindingTime, style: counterTextStyle),
|
|
|
|
const SizedBox(width: 12),
|
|
|
|
///
|
|
|
|
/// speed button
|
|
if (showSpeed) _changeSpeedButton(color),
|
|
|
|
///
|
|
if (trashClick != null)
|
|
MessageBarBtn(
|
|
enable: true,
|
|
icon: DidvanIcons.trash_solid,
|
|
color: Theme.of(context).colorScheme.error,
|
|
click: () async {
|
|
trashClick?.call();
|
|
}),
|
|
const SizedBox(width: 12),
|
|
],
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
SizedBox _noises(ThemeData newTHeme) => SizedBox(
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
/// noises
|
|
Noises(
|
|
rList: controller.randoms!,
|
|
activeSliderColor: activeSliderColor,
|
|
),
|
|
|
|
/// slider
|
|
AnimatedBuilder(
|
|
animation: CurvedAnimation(
|
|
parent: controller.animController,
|
|
curve: Curves.ease,
|
|
),
|
|
builder: (BuildContext context, Widget? child) {
|
|
return Positioned(
|
|
left: controller.animController.value,
|
|
child: Container(
|
|
width: controller.noiseWidth,
|
|
height: 6.w(),
|
|
color: notActiveSliderColor ?? backgroundColor,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
Opacity(
|
|
opacity: 0,
|
|
child: Container(
|
|
width: controller.noiseWidth,
|
|
color: Colors.transparent.withOpacity(1),
|
|
child: Theme(
|
|
data: newTHeme,
|
|
child: Slider(
|
|
value: controller.currentMillSeconds,
|
|
max: controller.maxMillSeconds,
|
|
onChangeStart: controller.onChangeSliderStart,
|
|
onChanged: controller.onChanging,
|
|
onChangeEnd: (value) {
|
|
controller.onSeek(
|
|
Duration(milliseconds: value.toInt()),
|
|
);
|
|
controller.play();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
|
|
Transform _changeSpeedButton(Color color) => Transform.translate(
|
|
offset: const Offset(0, -7),
|
|
child: GestureDetector(
|
|
onTap: () {
|
|
controller.changeSpeed();
|
|
},
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 3, vertical: 2),
|
|
decoration: BoxDecoration(
|
|
color: color,
|
|
borderRadius: BorderRadius.circular(4),
|
|
),
|
|
child: Text(
|
|
controller.speed.playSpeedStr,
|
|
style: circlesTextStyle,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
///
|
|
/// A custom track shape for a slider that is rounded rectangular in shape.
|
|
/// Extends the [RoundedRectSliderTrackShape] class.
|
|
class CustomTrackShape extends RoundedRectSliderTrackShape {
|
|
@override
|
|
|
|
/// Returns the preferred rectangle for the voice message view.
|
|
///
|
|
/// The preferred rectangle is calculated based on the current state and layout
|
|
/// of the voice message view. It represents the area where the view should be
|
|
/// displayed on the screen.
|
|
///
|
|
/// Returns a [Rect] object representing the preferred rectangle.
|
|
Rect getPreferredRect({
|
|
required RenderBox parentBox,
|
|
Offset offset = Offset.zero,
|
|
required SliderThemeData sliderTheme,
|
|
bool isEnabled = false,
|
|
bool isDiscrete = false,
|
|
}) {
|
|
const double trackHeight = 10;
|
|
final double trackLeft = offset.dx,
|
|
trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
|
|
final double trackWidth = parentBox.size.width;
|
|
return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
|
|
}
|
|
}
|