测试安卓修改app名称

This commit is contained in:
rang 2025-12-05 17:59:13 +08:00
parent 6b1edcb475
commit 6ceeb99d20
19 changed files with 1218 additions and 822 deletions

View file

@ -0,0 +1,39 @@
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
final AudioPlayer player;
AbsAudioHandler(this.player);
//
@override
Future<void> play() async {
await player.play();
}
@override
Future<void> pause() async {
await player.pause();
}
@override
Future<void> skipToNext() async {
await player.seekToNext();
}
@override
Future<void> skipToPrevious() async {
await player.seekToPrevious();
}
@override
Future<void> seek(Duration position) async {
await player.seek(position);
}
@override
Future<void> setSpeed(double speed) async {
await player.setSpeed(speed);
}
}

View file

@ -0,0 +1,5 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:just_audio/just_audio.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
class AbsAudioPlayer extends AudioPlayer {}

View file

@ -32,6 +32,7 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
final _currentChapterObject = BehaviorSubject<BookChapter?>.seeded(null);
AbsAudioHandler(this.ref) {
notificationSettings = ref.read(appSettingsProvider).notificationSettings;
ref.listen(appSettingsProvider, (a, b) {
if (a?.notificationSettings != b.notificationSettings) {
notificationSettings = b.notificationSettings;
@ -52,12 +53,12 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
final chapter = _book?.findChapterAtTime(positionInBook);
if (chapter != currentChapter) {
if (mediaItem.hasValue && chapter != null) {
updateMediaItem(
mediaItem.value!.copyWith(
duration: chapter.duration,
displayTitle: chapter.title,
),
);
// updateMediaItem(
// mediaItem.value!.copyWith(
// duration: chapter.duration,
// displayTitle: chapter.title,
// ),
// );
}
_currentChapterObject.sink.add(chapter);
}

View file

@ -0,0 +1,56 @@
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:just_audio_media_kit/just_audio_media_kit.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:vaani/features/player/core/abs_audio_handler.dart' as core;
import 'package:vaani/features/player/core/abs_audio_player.dart' as core;
part 'abs_provider.g.dart';
final _logger = Logger('AbsPlayerProvider');
@Riverpod(keepAlive: true)
Future<core.AbsAudioHandler> absAudioHandler(Ref ref) async {
// for playing audio on windows, linux
JustAudioMediaKit.ensureInitialized();
// for configuring how this app will interact with other audio apps
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
final player = ref.read(absAudioPlayerProvider);
final audioService = await AudioService.init(
builder: () => core.AbsAudioHandler(player),
config: const AudioServiceConfig(
androidNotificationChannelId: 'dr.blank.vaani.channel.audio',
androidNotificationChannelName: 'ABSPlayback',
androidNotificationChannelDescription:
'Needed to control audio from lock screen',
androidNotificationOngoing: false,
androidStopForegroundOnPause: false,
androidNotificationIcon: 'drawable/ic_stat_logo',
preloadArtwork: true,
// fastForwardInterval: Duration(seconds: 20),
// rewindInterval: Duration(seconds: 20),
),
);
return audioService;
}
@Riverpod(keepAlive: true)
class AbsAudioPlayer extends _$AbsAudioPlayer {
@override
core.AbsAudioPlayer build() {
final player = core.AbsAudioPlayer();
ref.onDispose(player.dispose);
_logger.finer('created simple player');
return player;
}
}

View file

@ -0,0 +1,43 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'abs_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$absAudioHandlerHash() => r'f4ef20cc3e244d5d37354ef38a1e0fdbd89412f4';
/// See also [absAudioHandler].
@ProviderFor(absAudioHandler)
final absAudioHandlerProvider = FutureProvider<core.AbsAudioHandler>.internal(
absAudioHandler,
name: r'absAudioHandlerProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$absAudioHandlerHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef AbsAudioHandlerRef = FutureProviderRef<core.AbsAudioHandler>;
String _$absAudioPlayerHash() => r'68a56d45a9f165d257c23f81d9bf7d0930425464';
/// See also [AbsAudioPlayer].
@ProviderFor(AbsAudioPlayer)
final absAudioPlayerProvider =
NotifierProvider<AbsAudioPlayer, core.AbsAudioPlayer>.internal(
AbsAudioPlayer.new,
name: r'absAudioPlayerProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$absAudioPlayerHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$AbsAudioPlayer = Notifier<core.AbsAudioPlayer>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -99,6 +99,7 @@ List<core.BookChapter> currentChapters(Ref ref) {
}
final index = book.chapters.indexOf(currentChapter);
final total = book.chapters.length;
return book.chapters
.sublist(index - 3, (total - 3) <= (index + 17) ? total : index + 17);
final start = index - 3 >= 0 ? index - 3 : 0;
final end = start + 20 <= total ? start + 20 : total;
return book.chapters.sublist(start, end);
}

View file

@ -6,7 +6,7 @@ part of 'currently_playing_provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$currentChaptersHash() => r'a25733d8085a2ce7dbc16fa2bf14f00ab8e2a623';
String _$currentChaptersHash() => r'6574b3f4ee0af8006f233aaf76cc507d188c6305';
/// See also [currentChapters].
@ProviderFor(currentChapters)

View file

@ -1,7 +1,9 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:vaani/constants/sizes.dart';
import 'package:vaani/features/player/providers/audiobook_player.dart';
import 'package:vaani/features/player/providers/currently_playing_provider.dart';
@ -137,22 +139,45 @@ class PlayerExpandedDesktop extends HookConsumerWidget {
class ChapterSelection extends HookConsumerWidget {
const ChapterSelection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final currentChapter = ref.watch(currentChapterProvider);
if (currentChapter == null) {
return SizedBox.shrink();
}
final chapters = useState(<BookChapter>[]);
final scrollController = useScrollController();
useEffect(
() {
int page = 0;
void load(page) {
chapters.value.addAll(ref.watch(currentChaptersProvider));
}
final currentChapters = ref.watch(currentChaptersProvider);
final currentChapterIndex = currentChapters.indexOf(currentChapter);
load(page);
void listener() {
if (scrollController.position.pixels /
scrollController.position.maxScrollExtent >
0.8) {
print('滚动到底部');
}
}
scrollController.addListener(listener);
return () => scrollController.removeListener(listener);
},
[scrollController],
);
final currentChapterIndex = chapters.value.indexOf(currentChapter);
final theme = Theme.of(context);
return Scrollbar(
controller: scrollController,
child: ListView.builder(
itemCount: currentChapters.length,
controller: scrollController,
itemCount: chapters.value.length,
itemBuilder: (context, index) {
final chapter = currentChapters[index];
final chapter = chapters.value[index];
final isCurrent = currentChapterIndex == index;
final isPlayed = index < currentChapterIndex;
return ListTile(