mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-01-14 22:29:32 +00:00
chore: run dart format
Some checks are pending
Flutter CI & Release / Test (push) Waiting to run
Flutter CI & Release / Build Android APKs (push) Blocked by required conditions
Flutter CI & Release / build_linux (push) Blocked by required conditions
Flutter CI & Release / Create GitHub Release (push) Blocked by required conditions
Some checks are pending
Flutter CI & Release / Test (push) Waiting to run
Flutter CI & Release / Build Android APKs (push) Blocked by required conditions
Flutter CI & Release / build_linux (push) Blocked by required conditions
Flutter CI & Release / Create GitHub Release (push) Blocked by required conditions
This commit is contained in:
parent
a520136e01
commit
e23c0b6c5f
84 changed files with 1565 additions and 1945 deletions
|
|
@ -4,10 +4,7 @@ import 'package:vaani/constants/sizes.dart';
|
|||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||
|
||||
class AudiobookPlayerSeekButton extends HookConsumerWidget {
|
||||
const AudiobookPlayerSeekButton({
|
||||
super.key,
|
||||
required this.isForward,
|
||||
});
|
||||
const AudiobookPlayerSeekButton({super.key, required this.isForward});
|
||||
|
||||
/// if true, the button seeks forward, else it seeks backwards
|
||||
final bool isForward;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@ import 'package:vaani/constants/sizes.dart';
|
|||
import 'package:vaani/features/player/providers/audiobook_player.dart';
|
||||
|
||||
class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
||||
const AudiobookPlayerSeekChapterButton({
|
||||
super.key,
|
||||
required this.isForward,
|
||||
});
|
||||
const AudiobookPlayerSeekChapterButton({super.key, required this.isForward});
|
||||
|
||||
/// if true, the button seeks forward, else it seeks backwards
|
||||
final bool isForward;
|
||||
|
|
@ -27,9 +24,7 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
void seekForward() {
|
||||
final index = player.book!.chapters.indexOf(player.currentChapter!);
|
||||
if (index < player.book!.chapters.length - 1) {
|
||||
player.seek(
|
||||
player.book!.chapters[index + 1].start + offset,
|
||||
);
|
||||
player.seek(player.book!.chapters[index + 1].start + offset);
|
||||
} else {
|
||||
player.seek(player.currentChapter!.end);
|
||||
}
|
||||
|
|
@ -37,8 +32,9 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
|
||||
/// seek backward to the previous chapter or the start of the current chapter
|
||||
void seekBackward() {
|
||||
final currentPlayingChapterIndex =
|
||||
player.book!.chapters.indexOf(player.currentChapter!);
|
||||
final currentPlayingChapterIndex = player.book!.chapters.indexOf(
|
||||
player.currentChapter!,
|
||||
);
|
||||
final chapterPosition =
|
||||
player.positionInBook - player.currentChapter!.start;
|
||||
BookChapter chapterToSeekTo;
|
||||
|
|
@ -49,9 +45,7 @@ class AudiobookPlayerSeekChapterButton extends HookConsumerWidget {
|
|||
} else {
|
||||
chapterToSeekTo = player.currentChapter!;
|
||||
}
|
||||
player.seek(
|
||||
chapterToSeekTo.start + offset,
|
||||
);
|
||||
player.seek(chapterToSeekTo.start + offset);
|
||||
}
|
||||
|
||||
return IconButton(
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ import 'package:vaani/shared/extensions/duration_format.dart'
|
|||
import 'package:vaani/shared/hooks.dart' show useTimer;
|
||||
|
||||
class ChapterSelectionButton extends HookConsumerWidget {
|
||||
const ChapterSelectionButton({
|
||||
super.key,
|
||||
});
|
||||
const ChapterSelectionButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -49,9 +47,7 @@ class ChapterSelectionButton extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
class ChapterSelectionModal extends HookConsumerWidget {
|
||||
const ChapterSelectionModal({
|
||||
super.key,
|
||||
});
|
||||
const ChapterSelectionModal({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -87,41 +83,40 @@ class ChapterSelectionModal extends HookConsumerWidget {
|
|||
child: currentBook?.chapters == null
|
||||
? const Text('No chapters found')
|
||||
: Column(
|
||||
children: currentBook!.chapters.map(
|
||||
(chapter) {
|
||||
final isCurrent = currentChapterIndex == chapter.id;
|
||||
final isPlayed = currentChapterIndex != null &&
|
||||
chapter.id < currentChapterIndex;
|
||||
return ListTile(
|
||||
autofocus: isCurrent,
|
||||
iconColor: isPlayed && !isCurrent
|
||||
? theme.disabledColor
|
||||
children: currentBook!.chapters.map((chapter) {
|
||||
final isCurrent = currentChapterIndex == chapter.id;
|
||||
final isPlayed =
|
||||
currentChapterIndex != null &&
|
||||
chapter.id < currentChapterIndex;
|
||||
return ListTile(
|
||||
autofocus: isCurrent,
|
||||
iconColor: isPlayed && !isCurrent
|
||||
? theme.disabledColor
|
||||
: null,
|
||||
title: Text(
|
||||
chapter.title,
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
title: Text(
|
||||
chapter.title,
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
subtitle: Text(
|
||||
'(${chapter.duration.smartBinaryFormat})',
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
trailing: isCurrent
|
||||
? const PlayingIndicatorIcon()
|
||||
: const Icon(Icons.play_arrow),
|
||||
selected: isCurrent,
|
||||
key: isCurrent ? chapterKey : null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
notifier.seek(chapter.start + 90.ms);
|
||||
notifier.play();
|
||||
},
|
||||
);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
subtitle: Text(
|
||||
'(${chapter.duration.smartBinaryFormat})',
|
||||
style: isPlayed && !isCurrent
|
||||
? TextStyle(color: theme.disabledColor)
|
||||
: null,
|
||||
),
|
||||
trailing: isCurrent
|
||||
? const PlayingIndicatorIcon()
|
||||
: const Icon(Icons.play_arrow),
|
||||
selected: isCurrent,
|
||||
key: isCurrent ? chapterKey : null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
notifier.seek(chapter.start + 90.ms);
|
||||
notifier.play();
|
||||
},
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
|||
final _logger = Logger('PlayerSpeedAdjustButton');
|
||||
|
||||
class PlayerSpeedAdjustButton extends HookConsumerWidget {
|
||||
const PlayerSpeedAdjustButton({
|
||||
super.key,
|
||||
});
|
||||
const PlayerSpeedAdjustButton({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -35,21 +33,19 @@ class PlayerSpeedAdjustButton extends HookConsumerWidget {
|
|||
notifier.setSpeed(speed);
|
||||
if (appSettings.playerSettings.configurePlayerForEveryBook) {
|
||||
ref
|
||||
.read(
|
||||
bookSettingsProvider(bookId).notifier,
|
||||
)
|
||||
.read(bookSettingsProvider(bookId).notifier)
|
||||
.update(
|
||||
bookSettings.copyWith
|
||||
.playerSettings(preferredDefaultSpeed: speed),
|
||||
bookSettings.copyWith.playerSettings(
|
||||
preferredDefaultSpeed: speed,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ref
|
||||
.read(
|
||||
appSettingsProvider.notifier,
|
||||
)
|
||||
.read(appSettingsProvider.notifier)
|
||||
.update(
|
||||
appSettings.copyWith
|
||||
.playerSettings(preferredDefaultSpeed: speed),
|
||||
appSettings.copyWith.playerSettings(
|
||||
preferredDefaultSpeed: speed,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,8 +59,11 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationParams =
|
||||
List.generate(widget.barCount, _createRandomParams, growable: false);
|
||||
_animationParams = List.generate(
|
||||
widget.barCount,
|
||||
_createRandomParams,
|
||||
growable: false,
|
||||
);
|
||||
}
|
||||
|
||||
// Helper to generate random parameters for one bar's animation cycle
|
||||
|
|
@ -72,10 +75,12 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
|
||||
// Note: These factors represent the scale relative to the *half-height*
|
||||
// if centerSymmetric is true, controlled by the alignment in scaleY.
|
||||
final targetHeightFactor1 = widget.minHeightFactor +
|
||||
final targetHeightFactor1 =
|
||||
widget.minHeightFactor +
|
||||
_random.nextDouble() *
|
||||
(widget.maxHeightFactor - widget.minHeightFactor);
|
||||
final targetHeightFactor2 = widget.minHeightFactor +
|
||||
final targetHeightFactor2 =
|
||||
widget.minHeightFactor +
|
||||
_random.nextDouble() *
|
||||
(widget.maxHeightFactor - widget.minHeightFactor);
|
||||
|
||||
|
|
@ -95,7 +100,8 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = widget.color ??
|
||||
final color =
|
||||
widget.color ??
|
||||
IconTheme.of(context).color ??
|
||||
Theme.of(context).colorScheme.primary;
|
||||
|
||||
|
|
@ -110,8 +116,9 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
final double maxHeight = widget.size;
|
||||
|
||||
// Determine the alignment for scaling based on the symmetric flag
|
||||
final Alignment scaleAlignment =
|
||||
widget.centerSymmetric ? Alignment.center : Alignment.bottomCenter;
|
||||
final Alignment scaleAlignment = widget.centerSymmetric
|
||||
? Alignment.center
|
||||
: Alignment.bottomCenter;
|
||||
|
||||
// Determine the cross axis alignment for the Row
|
||||
final CrossAxisAlignment rowAlignment = widget.centerSymmetric
|
||||
|
|
@ -129,47 +136,40 @@ class _PlayingIndicatorIconState extends State<PlayingIndicatorIcon> {
|
|||
crossAxisAlignment: rowAlignment,
|
||||
// Use spaceEvenly for better distribution, especially with center alignment
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: List.generate(
|
||||
widget.barCount,
|
||||
(index) {
|
||||
final params = _animationParams[index];
|
||||
// The actual bar widget that will be animated
|
||||
return Container(
|
||||
width: barWidth,
|
||||
// Set initial height to the max potential height
|
||||
// The scaleY animation will control the visible height
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(barWidth / 2),
|
||||
),
|
||||
)
|
||||
.animate(
|
||||
delay: params.initialDelay,
|
||||
onPlay: (controller) => controller.repeat(
|
||||
reverse: true,
|
||||
),
|
||||
)
|
||||
// 1. Scale to targetHeightFactor1
|
||||
.scaleY(
|
||||
begin:
|
||||
widget.minHeightFactor, // Scale factor starts near min
|
||||
end: params.targetHeightFactor1,
|
||||
duration: params.duration1,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
)
|
||||
// 2. Then scale to targetHeightFactor2
|
||||
.then()
|
||||
.scaleY(
|
||||
end: params.targetHeightFactor2,
|
||||
duration: params.duration2,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
);
|
||||
},
|
||||
growable: false,
|
||||
),
|
||||
children: List.generate(widget.barCount, (index) {
|
||||
final params = _animationParams[index];
|
||||
// The actual bar widget that will be animated
|
||||
return Container(
|
||||
width: barWidth,
|
||||
// Set initial height to the max potential height
|
||||
// The scaleY animation will control the visible height
|
||||
height: maxHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(barWidth / 2),
|
||||
),
|
||||
)
|
||||
.animate(
|
||||
delay: params.initialDelay,
|
||||
onPlay: (controller) => controller.repeat(reverse: true),
|
||||
)
|
||||
// 1. Scale to targetHeightFactor1
|
||||
.scaleY(
|
||||
begin: widget.minHeightFactor, // Scale factor starts near min
|
||||
end: params.targetHeightFactor1,
|
||||
duration: params.duration1,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
)
|
||||
// 2. Then scale to targetHeightFactor2
|
||||
.then()
|
||||
.scaleY(
|
||||
end: params.targetHeightFactor2,
|
||||
duration: params.duration2,
|
||||
curve: Curves.easeInOutCirc,
|
||||
alignment: scaleAlignment, // Apply chosen alignment
|
||||
);
|
||||
}, growable: false),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ import 'package:vaani/settings/app_settings_provider.dart';
|
|||
const double itemExtent = 25;
|
||||
|
||||
class SpeedSelector extends HookConsumerWidget {
|
||||
const SpeedSelector({
|
||||
super.key,
|
||||
required this.onSpeedSelected,
|
||||
});
|
||||
const SpeedSelector({super.key, required this.onSpeedSelected});
|
||||
|
||||
final void Function(double speed) onSpeedSelected;
|
||||
|
||||
|
|
@ -26,34 +23,22 @@ class SpeedSelector extends HookConsumerWidget {
|
|||
final speedState = useState(currentSpeed);
|
||||
|
||||
// hook the onSpeedSelected function to the state
|
||||
useEffect(
|
||||
() {
|
||||
onSpeedSelected(speedState.value);
|
||||
return null;
|
||||
},
|
||||
[speedState.value],
|
||||
);
|
||||
useEffect(() {
|
||||
onSpeedSelected(speedState.value);
|
||||
return null;
|
||||
}, [speedState.value]);
|
||||
|
||||
// the speed options
|
||||
final minSpeed = min(
|
||||
speeds.reduce(min),
|
||||
playerSettings.minSpeed,
|
||||
);
|
||||
final maxSpeed = max(
|
||||
speeds.reduce(max),
|
||||
playerSettings.maxSpeed,
|
||||
);
|
||||
final minSpeed = min(speeds.reduce(min), playerSettings.minSpeed);
|
||||
final maxSpeed = max(speeds.reduce(max), playerSettings.maxSpeed);
|
||||
final speedIncrement = playerSettings.speedIncrement;
|
||||
final availableSpeeds = ((maxSpeed - minSpeed) / speedIncrement).ceil() + 1;
|
||||
final availableSpeedsList = List.generate(
|
||||
availableSpeeds,
|
||||
(index) {
|
||||
// need to round to 2 decimal place to avoid floating point errors
|
||||
return double.parse(
|
||||
(minSpeed + index * speedIncrement).toStringAsFixed(2),
|
||||
);
|
||||
},
|
||||
);
|
||||
final availableSpeedsList = List.generate(availableSpeeds, (index) {
|
||||
// need to round to 2 decimal place to avoid floating point errors
|
||||
return double.parse(
|
||||
(minSpeed + index * speedIncrement).toStringAsFixed(2),
|
||||
);
|
||||
});
|
||||
|
||||
final scrollController = useFixedExtentScrollController(
|
||||
initialItem: availableSpeedsList.indexOf(currentSpeed),
|
||||
|
|
@ -107,18 +92,19 @@ class SpeedSelector extends HookConsumerWidget {
|
|||
(speed) => TextButton(
|
||||
style: speed == speedState.value
|
||||
? TextButton.styleFrom(
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(context)
|
||||
.colorScheme
|
||||
.onPrimaryContainer,
|
||||
backgroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
foregroundColor: Theme.of(
|
||||
context,
|
||||
).colorScheme.onPrimaryContainer,
|
||||
)
|
||||
// border if not selected
|
||||
: TextButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.primaryContainer,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.primaryContainer,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
|
|
@ -195,14 +181,13 @@ class SpeedWheel extends StatelessWidget {
|
|||
controller: scrollController,
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemExtent: itemExtent,
|
||||
diameterRatio: 1.5, squeeze: 1.2,
|
||||
diameterRatio: 1.5,
|
||||
squeeze: 1.2,
|
||||
// useMagnifier: true,
|
||||
// magnification: 1.5,
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
children: availableSpeedsList
|
||||
.map(
|
||||
(speed) => SpeedLine(speed: speed),
|
||||
)
|
||||
.map((speed) => SpeedLine(speed: speed))
|
||||
.toList(),
|
||||
onSelectedItemChanged: (index) {
|
||||
speedState.value = availableSpeedsList[index];
|
||||
|
|
@ -232,10 +217,7 @@ class SpeedWheel extends StatelessWidget {
|
|||
}
|
||||
|
||||
class SpeedLine extends StatelessWidget {
|
||||
const SpeedLine({
|
||||
super.key,
|
||||
required this.speed,
|
||||
});
|
||||
const SpeedLine({super.key, required this.speed});
|
||||
|
||||
final double speed;
|
||||
|
||||
|
|
@ -250,8 +232,8 @@ class SpeedLine extends StatelessWidget {
|
|||
width: speed % 0.5 == 0
|
||||
? 3
|
||||
: speed % 0.25 == 0
|
||||
? 2
|
||||
: 0.5,
|
||||
? 2
|
||||
: 0.5,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue